diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/prometheus_collector.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/prometheus_collector.h new file mode 100644 index 0000000000..71aad4d59b --- /dev/null +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/prometheus_collector.h @@ -0,0 +1,100 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "opentelemetry/sdk/metrics/record.h" +#include "prometheus/collectable.h" +#include "prometheus/metric_family.h" +#include "prometheus_exporter_utils.h" + +namespace prometheus_client = ::prometheus; +namespace metric_sdk = opentelemetry::sdk::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace prometheus +{ +/** + * The Prometheus Collector maintains the intermediate collection in Prometheus Exporter + */ +class PrometheusCollector : public prometheus_client::Collectable +{ +public: + /** + * Default Constructor. + * + * This constructor initializes the collection for metrics to export + * in this class with default capacity + */ + explicit PrometheusCollector(int max_collection_size = 2048); + + /** + * Collects all metrics data from metricsToCollect collection. + * + * @return all metrics in the metricsToCollect snapshot + */ + std::vector Collect() const override; + + /** + * This function is called by export() function and add the collection of + * records to the metricsToCollect collection + * + * @param records a collection of records to add to the metricsToCollect collection + */ + void AddMetricData(const std::vector &records); + + /** + * Get the current collection in the collector. + * + * @return the current metricsToCollect collection + */ + std::vector GetCollection(); + + /** + * Gets the maximum size of the collection. + * + * @return max collection size + */ + int GetMaxCollectionSize() const; + +private: + /** + * Collection of metrics data from the export() function, and to be export + * to user when they send a pull request. This collection is a pointer + * to a collection so Collect() is able to clear the collection, even + * though it is a const function. + */ + std::unique_ptr> metrics_to_collect_; + + /** + * Maximum size of the metricsToCollect collection. + */ + int max_collection_size_; + + /* + * Lock when operating the metricsToCollect collection + */ + mutable std::mutex collection_lock_; +}; +} // namespace prometheus +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/prometheus/src/prometheus_collector.cc b/exporters/prometheus/src/prometheus_collector.cc new file mode 100644 index 0000000000..3851296209 --- /dev/null +++ b/exporters/prometheus/src/prometheus_collector.cc @@ -0,0 +1,169 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "opentelemetry/exporters/prometheus/prometheus_collector.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace prometheus +{ +/** + * Default Constructor. + * + * This constructor initializes the collection for metrics to export + * in this class with default capacity + */ +PrometheusCollector::PrometheusCollector(int max_collection_size) + : max_collection_size_(max_collection_size) +{ + metrics_to_collect_ = + std::unique_ptr>(new std::vector); +} + +/** + * Collects all metrics data from metricsToCollect collection. + * + * @return all metrics in the metricsToCollect snapshot + */ +std::vector PrometheusCollector::Collect() const +{ + if (metrics_to_collect_->empty()) + { + return {}; + } + + std::vector result; + + // copy the intermediate collection, and then clear it + std::vector copied_data; + + collection_lock_.lock(); + copied_data = std::vector(*metrics_to_collect_); + metrics_to_collect_->clear(); + collection_lock_.unlock(); + + result = PrometheusExporterUtils::TranslateToPrometheus(copied_data); + return result; +} + +/** + * This function is called by export() function and add the collection of + * records to the metricsToCollect collection + * + * @param records a collection of records to add to the metricsToCollect collection + */ +void PrometheusCollector::AddMetricData(const std::vector &records) +{ + if (metrics_to_collect_->size() + records.size() <= max_collection_size_ && !records.empty()) + { + /** + * ValidAggregator is a lambda that checks a Record to see if its + * Aggregator is a valid std::shared_ptr and not a nullptr. + */ + auto ValidAggregator = [](sdk::metrics::Record record) { + auto aggregator_variant = record.GetAggregator(); + if (nostd::holds_alternative>>( + aggregator_variant)) + { + auto aggregator = + nostd::get>>(aggregator_variant); + if (!aggregator) + { + return false; + } + } + else if (nostd::holds_alternative>>( + aggregator_variant)) + { + auto aggregator = + nostd::get>>(aggregator_variant); + if (!aggregator) + { + return false; + } + } + else if (nostd::holds_alternative>>( + aggregator_variant)) + { + auto aggregator = + nostd::get>>(aggregator_variant); + if (!aggregator) + { + return false; + } + } + else if (nostd::holds_alternative>>( + aggregator_variant)) + { + auto aggregator = + nostd::get>>(aggregator_variant); + if (!aggregator) + { + return false; + } + } + + return true; + }; + + collection_lock_.lock(); + + for (auto &r : records) + { + if (ValidAggregator(r)) + { + metrics_to_collect_->push_back(r); + } + // Drop the record and write to std::cout + else + { + // Cannot call non const functions on const Record r + sdk::metrics::Record c = r; + std::cout << "Dropped Record containing invalid aggregator with name: " + c.GetName() + << std::endl; + } + } + + collection_lock_.unlock(); + } +} + +/** + * Get the current collection in the collector. + * + * @return the current metrics_to_collect collection + */ +std::vector PrometheusCollector::GetCollection() +{ + return *metrics_to_collect_; +} + +/** + * Gets the maximum size of the collection. + * + * @return max collection size + */ +int PrometheusCollector::GetMaxCollectionSize() const +{ + return max_collection_size_; +} + +} // namespace prometheus +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE