From 7fde3bc7928a4ae55e5502ff6934454a23c3a384 Mon Sep 17 00:00:00 2001 From: WenTao Ou Date: Fri, 22 Apr 2022 00:46:29 +0800 Subject: [PATCH 01/17] Link `opentelemetry_ext` with `opentelemetry_api` (#1336) --- ext/CMakeLists.txt | 1 + ext/src/http/client/nosend/CMakeLists.txt | 2 +- ext/src/zpages/CMakeLists.txt | 5 ++--- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index a2baa47a32..034328eaa5 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -5,6 +5,7 @@ target_include_directories( "$") set_target_properties(opentelemetry_ext PROPERTIES EXPORT_NAME "ext") +target_link_libraries(opentelemetry_ext INTERFACE opentelemetry_api) install( TARGETS opentelemetry_ext diff --git a/ext/src/http/client/nosend/CMakeLists.txt b/ext/src/http/client/nosend/CMakeLists.txt index 9118abbfb5..497daeb342 100644 --- a/ext/src/http/client/nosend/CMakeLists.txt +++ b/ext/src/http/client/nosend/CMakeLists.txt @@ -25,7 +25,7 @@ if(${BUILD_TESTING}) endif() target_link_libraries(http_client_nosend ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIB} - opentelemetry_api opentelemetry_ext) + opentelemetry_ext) install( TARGETS http_client_nosend diff --git a/ext/src/zpages/CMakeLists.txt b/ext/src/zpages/CMakeLists.txt index 64d9c73728..e3fd480df6 100644 --- a/ext/src/zpages/CMakeLists.txt +++ b/ext/src/zpages/CMakeLists.txt @@ -10,9 +10,8 @@ add_library( set_target_properties(opentelemetry_zpages PROPERTIES EXPORT_NAME zpages) -target_link_libraries( - opentelemetry_zpages PUBLIC opentelemetry_ext opentelemetry_api - opentelemetry_trace) +target_link_libraries(opentelemetry_zpages PUBLIC opentelemetry_ext + opentelemetry_trace) install( TARGETS opentelemetry_zpages From bf8f433cae41ad682cf9e390650158a2751373c1 Mon Sep 17 00:00:00 2001 From: Ehsan Saei <71217171+esigo@users.noreply.github.com> Date: Thu, 21 Apr 2022 23:27:19 +0200 Subject: [PATCH 02/17] ostream metrics cmake (#1344) --- examples/CMakeLists.txt | 4 +-- examples/common/CMakeLists.txt | 1 + .../common/metrics_foo_library/CMakeLists.txt | 2 ++ examples/metrics_simple/CMakeLists.txt | 17 +++++++---- exporters/ostream/CMakeLists.txt | 29 +++++++++++++++++++ 5 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 examples/common/metrics_foo_library/CMakeLists.txt diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 70bca10221..db0fe159be 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -18,9 +18,7 @@ endif() add_subdirectory(plugin) add_subdirectory(simple) add_subdirectory(batch) -if(WITH_METRICS_PREVIEW) - add_subdirectory(metrics_simple) -endif() +add_subdirectory(metrics_simple) add_subdirectory(multithreaded) add_subdirectory(multi_processor) add_subdirectory(http) diff --git a/examples/common/CMakeLists.txt b/examples/common/CMakeLists.txt index f89faf4a2f..c2fdca2594 100644 --- a/examples/common/CMakeLists.txt +++ b/examples/common/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(foo_library) if(WITH_LOGS_PREVIEW) add_subdirectory(logs_foo_library) endif() +add_subdirectory(metrics_foo_library) diff --git a/examples/common/metrics_foo_library/CMakeLists.txt b/examples/common/metrics_foo_library/CMakeLists.txt new file mode 100644 index 0000000000..4f2bca2a0b --- /dev/null +++ b/examples/common/metrics_foo_library/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(common_metrics_foo_library foo_library.h foo_library.cc) +target_link_libraries(common_metrics_foo_library PUBLIC opentelemetry_api) diff --git a/examples/metrics_simple/CMakeLists.txt b/examples/metrics_simple/CMakeLists.txt index 94b441061b..a2088fd510 100644 --- a/examples/metrics_simple/CMakeLists.txt +++ b/examples/metrics_simple/CMakeLists.txt @@ -1,6 +1,13 @@ include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) - -add_executable(simple_metrics main.cc) -target_link_libraries( - simple_metrics ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics_deprecated - opentelemetry_exporter_ostream_metrics_deprecated) +if(WITH_METRICS_PREVIEW) + add_executable(simple_metrics main.cc) + target_link_libraries( + simple_metrics ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics_deprecated + opentelemetry_exporter_ostream_metrics_deprecated) +else() + add_executable(metrics_ostream_example metrics_ostream.cc) + target_link_libraries( + metrics_ostream_example ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics + opentelemetry_exporter_ostream_metrics opentelemetry_resources + common_metrics_foo_library) +endif() diff --git a/exporters/ostream/CMakeLists.txt b/exporters/ostream/CMakeLists.txt index 31f1e9b0d0..db2562ddde 100644 --- a/exporters/ostream/CMakeLists.txt +++ b/exporters/ostream/CMakeLists.txt @@ -63,6 +63,35 @@ if(WITH_METRICS_PREVIEW) TEST_PREFIX exporter. TEST_LIST ostream_metrics_test) endif() +else() + add_library(opentelemetry_exporter_ostream_metrics src/metric_exporter.cc) + set_target_properties(opentelemetry_exporter_ostream_metrics + PROPERTIES EXPORT_NAME ostream_metrics_exporter) + target_include_directories( + opentelemetry_exporter_ostream_metrics + PUBLIC "$") + target_link_libraries(opentelemetry_exporter_ostream_metrics + PUBLIC opentelemetry_metrics) + install( + TARGETS opentelemetry_exporter_ostream_metrics + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "metric_exporter.h") + if(BUILD_TESTING) + add_executable(ostream_metric_test test/ostream_metric_test.cc) + target_link_libraries( + ostream_metric_test ${GTEST_BOTH_LIBRARIES} + opentelemetry_exporter_ostream_metrics opentelemetry_resources) + gtest_add_tests( + TARGET ostream_metric_test + TEST_PREFIX exporter. + TEST_LIST ostream_metric_test) + endif() endif() if(WITH_LOGS_PREVIEW) From e6fb935f75c9c5a34ca3422ebdb47bb7e620f405 Mon Sep 17 00:00:00 2001 From: Ehsan Saei <71217171+esigo@users.noreply.github.com> Date: Mon, 25 Apr 2022 18:48:11 +0200 Subject: [PATCH 03/17] prometheus exporter (#1331) --- exporters/CMakeLists.txt | 2 +- exporters/prometheus/BUILD | 73 +++- exporters/prometheus/CMakeLists.txt | 99 ++++-- .../exporters/prometheus/collector.h | 87 +++++ .../exporters/prometheus/exporter.h | 126 +++++++ .../exporters/prometheus/exporter_utils.h | 129 +++++++ exporters/prometheus/src/collector.cc | 89 +++++ exporters/prometheus/src/exporter.cc | 100 ++++++ exporters/prometheus/src/exporter_utils.cc | 327 ++++++++++++++++++ 9 files changed, 991 insertions(+), 41 deletions(-) create mode 100644 exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h create mode 100644 exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h create mode 100644 exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h create mode 100644 exporters/prometheus/src/collector.cc create mode 100644 exporters/prometheus/src/exporter.cc create mode 100644 exporters/prometheus/src/exporter_utils.cc diff --git a/exporters/CMakeLists.txt b/exporters/CMakeLists.txt index 2ae8fd92bb..862d2c779e 100644 --- a/exporters/CMakeLists.txt +++ b/exporters/CMakeLists.txt @@ -19,7 +19,7 @@ endif() add_subdirectory(ostream) add_subdirectory(memory) -if(WITH_PROMETHEUS AND WITH_METRICS_PREVIEW) +if(WITH_PROMETHEUS) add_subdirectory(prometheus) endif() diff --git a/exporters/prometheus/BUILD b/exporters/prometheus/BUILD index e92f9412eb..47c9bbab16 100644 --- a/exporters/prometheus/BUILD +++ b/exporters/prometheus/BUILD @@ -15,7 +15,7 @@ package(default_visibility = ["//visibility:public"]) cc_library( - name = "prometheus_exporter", + name = "prometheus_exporter_deprecated", srcs = [ "src/prometheus_exporter.cc", ], @@ -25,8 +25,8 @@ cc_library( strip_include_prefix = "include", tags = ["prometheus"], deps = [ - ":prometheus_collector", - ":prometheus_exporter_utils", + ":prometheus_collector_deprecated", + ":prometheus_exporter_utils_deprecated", "//api", "//sdk:headers", "@com_github_jupp0r_prometheus_cpp//core", @@ -35,7 +35,7 @@ cc_library( ) cc_library( - name = "prometheus_exporter_utils", + name = "prometheus_exporter_utils_deprecated", srcs = [ "src/prometheus_exporter_utils.cc", ], @@ -53,7 +53,7 @@ cc_library( ) cc_library( - name = "prometheus_collector", + name = "prometheus_collector_deprecated", srcs = [ "src/prometheus_collector.cc", ], @@ -63,7 +63,7 @@ cc_library( strip_include_prefix = "include", tags = ["prometheus"], deps = [ - ":prometheus_exporter_utils", + ":prometheus_exporter_utils_deprecated", "//api", "//sdk:headers", "@com_github_jupp0r_prometheus_cpp//core", @@ -72,7 +72,7 @@ cc_library( ) cc_test( - name = "prometheus_exporter_test", + name = "prometheus_exporter_test_deprecated", srcs = [ "test/prometheus_exporter_test.cc", ], @@ -81,7 +81,64 @@ cc_test( "test", ], deps = [ - ":prometheus_exporter", + ":prometheus_exporter_deprecated", "@com_google_googletest//:gtest_main", ], ) + +cc_library( + name = "prometheus_exporter", + srcs = [ + "src/exporter.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/prometheus/exporter.h", + ], + strip_include_prefix = "include", + tags = ["prometheus"], + deps = [ + ":prometheus_collector", + ":prometheus_exporter_utils", + "//api", + "//sdk:headers", + "@com_github_jupp0r_prometheus_cpp//core", + "@com_github_jupp0r_prometheus_cpp//pull", + ], +) + +cc_library( + name = "prometheus_exporter_utils", + srcs = [ + "src/exporter_utils.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/prometheus/exporter_utils.h", + ], + strip_include_prefix = "include", + tags = ["prometheus"], + deps = [ + "//api", + "//sdk:headers", + "@com_github_jupp0r_prometheus_cpp//core", + "@com_github_jupp0r_prometheus_cpp//pull", + ], +) + +cc_library( + name = "prometheus_collector", + srcs = [ + "src/collector.cc", + ], + hdrs = [ + "include/opentelemetry/exporters/prometheus/collector.h", + ], + strip_include_prefix = "include", + tags = ["prometheus"], + deps = [ + ":prometheus_exporter_utils", + "//api", + "//sdk:headers", + "@com_github_jupp0r_prometheus_cpp//core", + "@com_github_jupp0r_prometheus_cpp//pull", + ], +) diff --git a/exporters/prometheus/CMakeLists.txt b/exporters/prometheus/CMakeLists.txt index 753fa18cac..56523ec848 100755 --- a/exporters/prometheus/CMakeLists.txt +++ b/exporters/prometheus/CMakeLists.txt @@ -16,40 +16,75 @@ include_directories(include) if(NOT TARGET prometheus-cpp::core) find_package(prometheus-cpp CONFIG REQUIRED) endif() +if(WITH_METRICS_PREVIEW) + add_library( + prometheus_exporter_deprecated + src/prometheus_exporter.cc src/prometheus_collector.cc + src/prometheus_exporter_utils.cc) + target_include_directories( + prometheus_exporter_deprecated + PUBLIC "$" + "$") -add_library( - prometheus_exporter_deprecated - src/prometheus_exporter.cc src/prometheus_collector.cc - src/prometheus_exporter_utils.cc) -target_include_directories( - prometheus_exporter_deprecated - PUBLIC "$" - "$") + set(PROMETHEUS_EXPORTER_TARGETS_DEPRECATED prometheus_exporter_deprecated) + if(TARGET pull) + list(APPEND PROMETHEUS_EXPORTER_TARGETS_DEPRECATED pull) + endif() + if(TARGET core) + list(APPEND PROMETHEUS_EXPORTER_TARGETS_DEPRECATED core) + endif() + target_link_libraries( + prometheus_exporter_deprecated + PUBLIC opentelemetry_metrics_deprecated prometheus-cpp::pull + prometheus-cpp::core) + install( + TARGETS ${PROMETHEUS_EXPORTER_TARGETS_DEPRECATED} + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -set(PROMETHEUS_EXPORTER_TARGETS prometheus_exporter_deprecated) -if(TARGET pull) - list(APPEND PROMETHEUS_EXPORTER_TARGETS pull) -endif() -if(TARGET core) - list(APPEND PROMETHEUS_EXPORTER_TARGETS core) -endif() -target_link_libraries( - prometheus_exporter_deprecated - PUBLIC opentelemetry_metrics_deprecated prometheus-cpp::pull - prometheus-cpp::core) -install( - TARGETS ${PROMETHEUS_EXPORTER_TARGETS} - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install( + DIRECTORY include/opentelemetry/exporters/prometheus + DESTINATION include/opentelemetry/exporters/ + FILES_MATCHING + PATTERN "*.h") + if(BUILD_TESTING) + add_subdirectory(test) + endif() +else() + + add_library(prometheus_exporter src/exporter.cc src/collector.cc + src/exporter_utils.cc) + target_include_directories( + prometheus_exporter + PUBLIC "$" + "$") + + set(PROMETHEUS_EXPORTER_TARGETS prometheus_exporter) + if(TARGET pull) + list(APPEND PROMETHEUS_EXPORTER_TARGETS pull) + endif() + if(TARGET core) + list(APPEND PROMETHEUS_EXPORTER_TARGETS core) + endif() + target_link_libraries( + prometheus_exporter PUBLIC opentelemetry_metrics prometheus-cpp::pull + prometheus-cpp::core) + install( + TARGETS ${PROMETHEUS_EXPORTER_TARGETS} + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY include/opentelemetry/exporters/prometheus - DESTINATION include/opentelemetry/exporters - FILES_MATCHING - PATTERN "*.h") + install( + DIRECTORY include/opentelemetry/exporters/prometheus + DESTINATION include/opentelemetry/exporters/ + FILES_MATCHING + PATTERN "*.h") -if(BUILD_TESTING) - add_subdirectory(test) + if(BUILD_TESTING) + add_subdirectory(test) + endif() endif() diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h new file mode 100644 index 0000000000..68f50d29fa --- /dev/null +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h @@ -0,0 +1,87 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW + +# include +# include +# include + +# include +# include +# include "opentelemetry/exporters/prometheus/exporter_utils.h" + +namespace prometheus_client = ::prometheus; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace metrics +{ +/** + * 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(size_t 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 sdk::metrics::ResourceMetrics &data); + + /** + * 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. + */ + mutable std::vector> metrics_to_collect_; + + /** + * Maximum size of the metricsToCollect collection. + */ + size_t max_collection_size_; + + /* + * Lock when operating the metricsToCollect collection + */ + mutable std::mutex collection_lock_; +}; +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h new file mode 100644 index 0000000000..6945f09bb9 --- /dev/null +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h @@ -0,0 +1,126 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include +# include +# include + +# include +# include "opentelemetry/common/spin_lock_mutex.h" +# include "opentelemetry/exporters/prometheus/collector.h" +# include "opentelemetry/nostd/span.h" +# include "opentelemetry/sdk/common/env_variables.h" +# include "opentelemetry/sdk/metrics/metric_exporter.h" +# include "opentelemetry/version.h" + +/** + * This class is an implementation of the MetricsExporter interface and + * exports Prometheus metrics data. Functions in this class should be + * called by the Controller in our data pipeline. + */ + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace exporter +{ +namespace metrics +{ + +inline const std::string GetOtlpDefaultHttpEndpoint() +{ + constexpr char kPrometheusEndpointEnv[] = "PROMETHEUS_EXPORTER_ENDPOINT"; + constexpr char kPrometheusEndpointDefault[] = "http://localhost:8080"; + + auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kPrometheusEndpointEnv); + return endpoint.size() ? endpoint : kPrometheusEndpointDefault; +} + +/** + * Struct to hold Prometheus exporter options. + */ +struct PrometheusExporterOptions +{ + // The endpoint the Prometheus backend can collect metrics from + std::string url = GetOtlpDefaultHttpEndpoint(); +}; + +class PrometheusExporter : public sdk::metrics::MetricExporter +{ +public: + /** + * Constructor - binds an exposer and collector to the exporter + * @param options: options for an exposer that exposes + * an HTTP endpoint for the exporter to connect to + */ + PrometheusExporter(const PrometheusExporterOptions &options); + + /** + * Exports a batch of Metric Records. + * @param records: a collection of records to export + * @return: returns a ReturnCode detailing a success, or type of failure + */ + sdk::common::ExportResult Export(const sdk::metrics::ResourceMetrics &data) noexcept override; + + /** + * Force flush the exporter. + */ + bool ForceFlush( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override; + + /** + * Shuts down the exporter and does cleanup. + * Since Prometheus is a pull based interface, + * we cannot serve data remaining in the intermediate + * collection to to client an HTTP request being sent, + * so we flush the data. + */ + bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override; + + /** + * @return: returns a shared_ptr to + * the PrometheusCollector instance + */ + std::shared_ptr &GetCollector(); + + /** + * @return: Gets the shutdown status of the exporter + */ + bool IsShutdown() const; + +private: + // The configuration options associated with this exporter. + const PrometheusExporterOptions options_; + /** + * exporter shutdown status + */ + bool is_shutdown_; + + /** + * Pointer to a + * PrometheusCollector instance + */ + std::shared_ptr collector_; + + /** + * Pointer to an + * Exposer instance + */ + std::unique_ptr<::prometheus::Exposer> exposer_; + + /** + * friend class for testing + */ + friend class PrometheusExporterTest; + + /** + * PrometheusExporter constructor with no parameters + * Used for testing only + */ + PrometheusExporter(); +}; +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif // ENABLE_METRICS_PREVIEW diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h new file mode 100644 index 0000000000..1cb7202ce5 --- /dev/null +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h @@ -0,0 +1,129 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifndef ENABLE_METRICS_PREVIEW + +# include +# include +# include +# include "opentelemetry/metrics/provider.h" +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace metrics +{ +/** + * The Prometheus Utils contains utility functions for Prometheus Exporter + */ +class PrometheusExporterUtils +{ +public: + /** + * Helper function to convert OpenTelemetry metrics data collection + * to Prometheus metrics data collection + * + * @param records a collection of metrics in OpenTelemetry + * @return a collection of translated metrics that is acceptable by Prometheus + */ + static std::vector<::prometheus::MetricFamily> TranslateToPrometheus( + const std::vector> &data); + +private: + /** + * Set value to metric family according to record + */ + static void SetMetricFamily(sdk::metrics::ResourceMetrics &data, + ::prometheus::MetricFamily *metric_family); + + /** + * Sanitize the given metric name or label according to Prometheus rule. + * + * This function is needed because names in OpenTelemetry can contain + * alphanumeric characters, '_', '.', and '-', whereas in Prometheus the + * name should only contain alphanumeric characters and '_'. + */ + static std::string SanitizeNames(std::string name); + + /** + * Set value to metric family for different aggregator + */ + static void SetMetricFamilyByAggregator(const sdk::metrics::ResourceMetrics &data, + std::string labels_str, + ::prometheus::MetricFamily *metric_family); + + static opentelemetry::sdk::metrics::AggregationType getAggregationType( + const opentelemetry::sdk::metrics::PointType &point_type); + + /** + * Translate the OTel metric type to Prometheus metric type + */ + static ::prometheus::MetricType TranslateType(opentelemetry::sdk::metrics::AggregationType kind); + + /** + * Set metric data for: + * Counter => Prometheus Counter + */ + template + static void SetData(std::vector values, + const std::string &labels, + ::prometheus::MetricType type, + std::chrono::nanoseconds time, + ::prometheus::MetricFamily *metric_family); + + /** + * Set metric data for: + * Histogram => Prometheus Histogram + */ + template + static void SetData(std::vector values, + const opentelemetry::sdk::metrics::ListType &boundaries, + const std::vector &counts, + const std::string &labels, + std::chrono::nanoseconds time, + ::prometheus::MetricFamily *metric_family); + + /** + * Set time and labels to metric data + */ + static void SetMetricBasic(::prometheus::ClientMetric &metric, + std::chrono::nanoseconds time, + const std::string &labels); + + /** + * Parse a string of labels (key:value) into a vector of pairs + * {,} + * {l1:v1,l2:v2,...,} + */ + static std::vector> ParseLabel(std::string labels); + + /** + * Handle Counter and Gauge. + */ + template + static void SetValue(std::vector values, + ::prometheus::MetricType type, + ::prometheus::ClientMetric *metric); + + /** + * Handle Gauge from MinMaxSumCount + */ + static void SetValue(double value, ::prometheus::ClientMetric *metric); + + /** + * Handle Histogram + */ + template + static void SetValue(std::vector values, + const std::list &boundaries, + const std::vector &counts, + ::prometheus::ClientMetric *metric); +}; +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/exporters/prometheus/src/collector.cc b/exporters/prometheus/src/collector.cc new file mode 100644 index 0000000000..03793a8eed --- /dev/null +++ b/exporters/prometheus/src/collector.cc @@ -0,0 +1,89 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW + +# include "opentelemetry/exporters/prometheus/collector.h" + +namespace metric_sdk = opentelemetry::sdk::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace metrics +{ +/** + * Default Constructor. + * + * This constructor initializes the collection for metrics to export + * in this class with default capacity + */ +PrometheusCollector::PrometheusCollector(size_t max_collection_size) + : max_collection_size_(max_collection_size) +{} + +/** + * Collects all metrics data from metricsToCollect collection. + * + * @return all metrics in the metricsToCollect snapshot + */ +std::vector PrometheusCollector::Collect() const +{ + this->collection_lock_.lock(); + if (metrics_to_collect_.empty()) + { + this->collection_lock_.unlock(); + return {}; + } + + std::vector result; + + // copy the intermediate collection, and then clear it + std::vector> copied_data; + copied_data.swap(metrics_to_collect_); + this->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 sdk::metrics::ResourceMetrics &data) +{ + collection_lock_.lock(); + if (metrics_to_collect_.size() + 1 <= max_collection_size_) + { + metrics_to_collect_.emplace_back(new sdk::metrics::ResourceMetrics{data}); + } + 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 metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/exporters/prometheus/src/exporter.cc b/exporters/prometheus/src/exporter.cc new file mode 100644 index 0000000000..a0bd9e27ab --- /dev/null +++ b/exporters/prometheus/src/exporter.cc @@ -0,0 +1,100 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include "opentelemetry/exporters/prometheus/exporter.h" + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace exporter +{ +namespace metrics +{ +/** + * Constructor - binds an exposer and collector to the exporter + * @param address: an address for an exposer that exposes + * an HTTP endpoint for the exporter to connect to + */ +PrometheusExporter::PrometheusExporter(const PrometheusExporterOptions &options) + : options_(options), is_shutdown_(false) +{ + exposer_ = std::unique_ptr<::prometheus::Exposer>(new ::prometheus::Exposer{options_.url}); + collector_ = std::shared_ptr(new PrometheusCollector); + + exposer_->RegisterCollectable(collector_); +} + +/** + * PrometheusExporter constructor with no parameters + * Used for testing only + */ +PrometheusExporter::PrometheusExporter() : is_shutdown_(false) +{ + collector_ = std::unique_ptr(new PrometheusCollector); +} + +/** + * Exports a batch of Metric Records. + * @param records: a collection of records to export + * @return: returns a ReturnCode detailing a success, or type of failure + */ +sdk::common::ExportResult PrometheusExporter::Export( + const sdk::metrics::ResourceMetrics &data) noexcept +{ + if (is_shutdown_) + { + return sdk::common::ExportResult::kFailure; + } + else if (collector_->GetCollection().size() + 1 > (size_t)collector_->GetMaxCollectionSize()) + { + return sdk::common::ExportResult::kFailureFull; + } + else + { + collector_->AddMetricData(data); + return sdk::common::ExportResult::kSuccess; + } + return sdk::common::ExportResult::kSuccess; +} + +bool PrometheusExporter::ForceFlush(std::chrono::microseconds timeout) noexcept +{ + return true; +} + +/** + * Shuts down the exporter and does cleanup. + * Since Prometheus is a pull based interface, + * we cannot serve data remaining in the intermediate + * collection to to client an HTTP request being sent, + * so we flush the data. + */ +bool PrometheusExporter::Shutdown(std::chrono::microseconds timeout) noexcept +{ + is_shutdown_ = true; + return true; + + collector_->GetCollection().clear(); +} + +/** + * @return: returns a shared_ptr to + * the PrometheusCollector instance + */ +std::shared_ptr &PrometheusExporter::GetCollector() +{ + return collector_; +} + +/** + * @return: Gets the shutdown status of the exporter + */ +bool PrometheusExporter::IsShutdown() const +{ + return is_shutdown_; +} + +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif // ENABLE_METRICS_PREVIEW diff --git a/exporters/prometheus/src/exporter_utils.cc b/exporters/prometheus/src/exporter_utils.cc new file mode 100644 index 0000000000..39131e210f --- /dev/null +++ b/exporters/prometheus/src/exporter_utils.cc @@ -0,0 +1,327 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include +# include +# include + +# include +# include "opentelemetry/exporters/prometheus/exporter_utils.h" +# include "opentelemetry/sdk/metrics/export/metric_producer.h" + +namespace prometheus_client = ::prometheus; +namespace metric_sdk = opentelemetry::sdk::metrics; + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace metrics +{ +/** + * Helper function to convert OpenTelemetry metrics data collection + * to Prometheus metrics data collection + * + * @param records a collection of metrics in OpenTelemetry + * @return a collection of translated metrics that is acceptable by Prometheus + */ +std::vector PrometheusExporterUtils::TranslateToPrometheus( + const std::vector> &data) +{ + if (data.empty()) + { + return {}; + } + + // initialize output vector + std::vector output(data.size()); + + // iterate through the vector and set result data into it + int i = 0; + for (const auto &r : data) + { + SetMetricFamily(*r, &output[i]); + i++; + } + + return output; +} + +/** + * Set value to metric family according to record + */ +void PrometheusExporterUtils::SetMetricFamily(sdk::metrics::ResourceMetrics &data, + prometheus_client::MetricFamily *metric_family) +{ + SetMetricFamilyByAggregator(data, "", metric_family); +} + +/** + * Sanitize the given metric name or label according to Prometheus rule. + * + * This function is needed because names in OpenTelemetry can contain + * alphanumeric characters, '_', '.', and '-', whereas in Prometheus the + * name should only contain alphanumeric characters and '_'. + */ +std::string PrometheusExporterUtils::SanitizeNames(std::string name) +{ + // replace all '.' and '-' with '_' + std::replace(name.begin(), name.end(), '.', '_'); + std::replace(name.begin(), name.end(), '-', '_'); + + return name; +} + +/** + * Set value to metric family for different aggregator + */ +void PrometheusExporterUtils::SetMetricFamilyByAggregator( + const sdk::metrics::ResourceMetrics &data, + std::string labels_str, + prometheus_client::MetricFamily *metric_family) +{ + for (const auto &instrumentation_info : data.instrumentation_info_metric_data_) + { + auto origin_name = instrumentation_info.instrumentation_library_->GetName(); + auto sanitized = SanitizeNames(origin_name); + metric_family->name = sanitized; + for (const auto &metric_data : instrumentation_info.metric_data_) + { + auto time = metric_data.start_ts.time_since_epoch(); + for (const auto &point_data_attr : metric_data.point_data_attr_) + { + auto kind = getAggregationType(point_data_attr.point_data); + const prometheus_client::MetricType type = TranslateType(kind); + metric_family->type = type; + if (type == prometheus_client::MetricType::Histogram) // Histogram + { + auto histogram_point_data = + nostd::get(point_data_attr.point_data); + auto boundaries = histogram_point_data.boundaries_; + auto counts = histogram_point_data.counts_; + SetData(std::vector{nostd::get(histogram_point_data.sum_), + (double)histogram_point_data.count_}, + boundaries, counts, labels_str, time, metric_family); + } + else // Counter, Untyped + { + auto sum_point_data = nostd::get(point_data_attr.point_data); + std::vector values{sum_point_data.value_}; + SetData(values, labels_str, type, time, metric_family); + } + } + } + } +} + +metric_sdk::AggregationType PrometheusExporterUtils::getAggregationType( + const metric_sdk::PointType &point_type) +{ + if (nostd::holds_alternative(point_type)) + { + return metric_sdk::AggregationType::kSum; + } + else if (nostd::holds_alternative(point_type)) + { + return metric_sdk::AggregationType::kDrop; + } + else if (nostd::holds_alternative(point_type)) + { + return metric_sdk::AggregationType::kHistogram; + } + else if (nostd::holds_alternative(point_type)) + { + return metric_sdk::AggregationType::kLastValue; + } + return metric_sdk::AggregationType::kDefault; +} + +/** + * Translate the OTel metric type to Prometheus metric type + */ +prometheus_client::MetricType PrometheusExporterUtils::TranslateType( + metric_sdk::AggregationType kind) +{ + switch (kind) + { + case metric_sdk::AggregationType::kSum: + return prometheus_client::MetricType::Counter; + case metric_sdk::AggregationType::kHistogram: + return prometheus_client::MetricType::Histogram; + default: + return prometheus_client::MetricType::Untyped; + } +} + +/** + * Set metric data for: + * sum => Prometheus Counter + */ +template +void PrometheusExporterUtils::SetData(std::vector values, + const std::string &labels, + prometheus_client::MetricType type, + std::chrono::nanoseconds time, + prometheus_client::MetricFamily *metric_family) +{ + metric_family->metric.emplace_back(); + prometheus_client::ClientMetric &metric = metric_family->metric.back(); + SetMetricBasic(metric, time, labels); + SetValue(values, type, &metric); +} + +/** + * Set metric data for: + * Histogram => Prometheus Histogram + */ +template +void PrometheusExporterUtils::SetData(std::vector values, + const opentelemetry::sdk::metrics::ListType &boundaries, + const std::vector &counts, + const std::string &labels, + std::chrono::nanoseconds time, + prometheus_client::MetricFamily *metric_family) +{ + metric_family->metric.emplace_back(); + prometheus_client::ClientMetric &metric = metric_family->metric.back(); + SetMetricBasic(metric, time, labels); + if (nostd::holds_alternative>(boundaries)) + { + SetValue(values, nostd::get>(boundaries), counts, &metric); + } + else + { + SetValue(values, nostd::get>(boundaries), counts, &metric); + } +} + +/** + * Set time and labels to metric data + */ +void PrometheusExporterUtils::SetMetricBasic(prometheus_client::ClientMetric &metric, + std::chrono::nanoseconds time, + const std::string &labels) +{ + metric.timestamp_ms = time.count() / 1000000; + + auto label_pairs = ParseLabel(labels); + if (!label_pairs.empty()) + { + metric.label.resize(label_pairs.size()); + for (size_t i = 0; i < label_pairs.size(); ++i) + { + auto origin_name = label_pairs[i].first; + auto sanitized = SanitizeNames(origin_name); + metric.label[i].name = sanitized; + metric.label[i].value = label_pairs[i].second; + } + } +}; + +/** + * Parse a string of labels (key:value) into a vector of pairs + * {,} + * {l1:v1,l2:v2,...,} + */ +std::vector> PrometheusExporterUtils::ParseLabel( + std::string labels) +{ + if (labels.size() < 3) + { + return {}; + } + labels = labels.substr(1, labels.size() - 2); + + std::vector paired_labels; + std::stringstream s_stream(labels); + while (s_stream.good()) + { + std::string substr; + getline(s_stream, substr, ','); // get first string delimited by comma + if (!substr.empty()) + { + paired_labels.push_back(substr); + } + } + + std::vector> result; + for (auto &paired : paired_labels) + { + std::size_t split_index = paired.find(':'); + std::string label = paired.substr(0, split_index); + std::string value = paired.substr(split_index + 1); + result.emplace_back(std::pair(label, value)); + } + + return result; +} + +/** + * Handle Counter. + */ +template +void PrometheusExporterUtils::SetValue(std::vector values, + prometheus_client::MetricType type, + prometheus_client::ClientMetric *metric) +{ + double value = 0.0; + const auto &value_var = values[0]; + if (nostd::holds_alternative(value_var)) + { + value = nostd::get(value_var); + } + else + { + value = nostd::get(value_var); + } + + switch (type) + { + case prometheus_client::MetricType::Counter: { + metric->counter.value = value; + break; + } + case prometheus_client::MetricType::Untyped: { + metric->untyped.value = value; + break; + } + default: + return; + } +} + +/** + * Handle Histogram + */ +template +void PrometheusExporterUtils::SetValue(std::vector values, + const std::list &boundaries, + const std::vector &counts, + prometheus_client::ClientMetric *metric) +{ + metric->histogram.sample_sum = values[0]; + metric->histogram.sample_count = values[1]; + int cumulative = 0; + std::vector buckets; + uint32_t idx = 0; + for (const auto &boundary : boundaries) + { + prometheus_client::ClientMetric::Bucket bucket; + cumulative += counts[idx]; + bucket.cumulative_count = cumulative; + bucket.upper_bound = boundary; + buckets.emplace_back(bucket); + ++idx; + } + prometheus_client::ClientMetric::Bucket bucket; + cumulative += counts[idx]; + bucket.cumulative_count = cumulative; + bucket.upper_bound = std::numeric_limits::infinity(); + buckets.emplace_back(bucket); + metric->histogram.bucket = buckets; +} + +} // namespace metrics +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE +#endif From 0c74e0b93d2e73bae68a08b7d124d13f752f2216 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Tue, 26 Apr 2022 01:43:13 +0530 Subject: [PATCH 04/17] remove exporter registration to meter provider (#1350) --- examples/metrics_simple/metrics_ostream.cc | 6 +- .../opentelemetry/sdk/metrics/meter_context.h | 18 +----- .../sdk/metrics/meter_provider.h | 13 ---- sdk/src/metrics/meter_context.cc | 60 +++++++------------ sdk/src/metrics/meter_provider.cc | 11 +--- sdk/test/metrics/async_metric_storage_test.cc | 3 +- sdk/test/metrics/meter_provider_sdk_test.cc | 14 ++--- sdk/test/metrics/metric_reader_test.cc | 5 +- 8 files changed, 36 insertions(+), 94 deletions(-) diff --git a/examples/metrics_simple/metrics_ostream.cc b/examples/metrics_simple/metrics_ostream.cc index d0e4dccfeb..ebb8b34b8a 100644 --- a/examples/metrics_simple/metrics_ostream.cc +++ b/examples/metrics_simple/metrics_ostream.cc @@ -30,7 +30,6 @@ namespace void initMetrics(const std::string &name) { std::unique_ptr exporter{new exportermetrics::OStreamMetricExporter}; - std::vector> exporters; std::string version{"1.2.0"}; std::string schema{"https://opentelemetry.io/schemas/1.2.0"}; @@ -41,9 +40,8 @@ void initMetrics(const std::string &name) options.export_timeout_millis = std::chrono::milliseconds(500); std::unique_ptr reader{ new metric_sdk::PeriodicExportingMetricReader(std::move(exporter), options)}; - auto provider = std::shared_ptr( - new metric_sdk::MeterProvider(std::move(exporters))); - auto p = std::static_pointer_cast(provider); + auto provider = std::shared_ptr(new metric_sdk::MeterProvider()); + auto p = std::static_pointer_cast(provider); p->AddMetricReader(std::move(reader)); // counter view diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_context.h b/sdk/include/opentelemetry/sdk/metrics/meter_context.h index 74f67a1c46..e35700175d 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter_context.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter_context.h @@ -24,7 +24,6 @@ namespace metrics // forward declaration class Meter; -class MetricExporter; class MetricReader; /** @@ -36,13 +35,11 @@ class MeterContext : public std::enable_shared_from_this public: /** * Initialize a new meter provider - * @param exporters The exporters to be configured with meter context * @param readers The readers to be configured with meter context. * @param views The views to be configured with meter context. * @param resource The resource for this meter context. */ MeterContext( - std::vector> &&exporters, std::unique_ptr views = std::unique_ptr(new ViewRegistry()), opentelemetry::sdk::resource::Resource resource = opentelemetry::sdk::resource::Resource::Create({})) noexcept; @@ -77,16 +74,6 @@ class MeterContext : public std::enable_shared_from_this */ opentelemetry::common::SystemTimestamp GetSDKStartTime() noexcept; - /** - * Attaches a metric exporter to list of configured exporters for this Meter context. - * @param exporter The metric exporter for this meter context. This - * must not be a nullptr. - * - * Note: This exporter may not receive any in-flight meter data, but will get newly created meter - * data. Note: This method is not thread safe, and should ideally be called from main thread. - */ - void AddMetricExporter(std::unique_ptr exporter) noexcept; - /** * Attaches a metric reader to list of configured readers for this Meter context. * @param reader The metric reader for this meter context. This @@ -118,20 +105,19 @@ class MeterContext : public std::enable_shared_from_this void AddMeter(std::shared_ptr meter); /** - * Force all active Exporters and Collectors to flush any buffered meter data + * Force all active Collectors to flush any buffered meter data * within the given timeout. */ bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept; /** - * Shutdown the Exporters and Collectors associated with this meter provider. + * Shutdown the Collectors associated with this meter provider. */ bool Shutdown() noexcept; private: opentelemetry::sdk::resource::Resource resource_; - std::vector> exporters_; std::vector> collectors_; std::unique_ptr views_; opentelemetry::common::SystemTimestamp sdk_start_ts_; diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h index c6efba6222..685f43e747 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h @@ -22,7 +22,6 @@ namespace metrics // forward declaration class MetricCollector; -class MetricExporter; class MetricReader; class MeterProvider final : public opentelemetry::metrics::MeterProvider @@ -30,12 +29,10 @@ class MeterProvider final : public opentelemetry::metrics::MeterProvider public: /** * Initialize a new meter provider - * @param exporters The span exporters for this meter provider * @param views The views for this meter provider * @param resource The resources for this meter provider. */ MeterProvider( - std::vector> &&exporters, std::unique_ptr views = std::unique_ptr(new ViewRegistry()), sdk::resource::Resource resource = sdk::resource::Resource::Create({})) noexcept; @@ -56,16 +53,6 @@ class MeterProvider final : public opentelemetry::metrics::MeterProvider */ const sdk::resource::Resource &GetResource() const noexcept; - /** - * Attaches a metric exporter to list of configured exporters for this Meter provider. - * @param exporter The metric exporter for this meter provider. This - * must not be a nullptr. - * - * Note: This exporter may not receive any in-flight meter data, but will get newly created meter - * data. Note: This method is not thread safe, and should ideally be called from main thread. - */ - void AddMetricExporter(std::unique_ptr exporter) noexcept; - /** * Attaches a metric reader to list of configured readers for this Meter providers. * @param reader The metric reader for this meter provider. This diff --git a/sdk/src/metrics/meter_context.cc b/sdk/src/metrics/meter_context.cc index f23135fa0c..73721e324d 100644 --- a/sdk/src/metrics/meter_context.cc +++ b/sdk/src/metrics/meter_context.cc @@ -4,7 +4,6 @@ #ifndef ENABLE_METRICS_PREVIEW # include "opentelemetry/sdk/metrics/meter_context.h" # include "opentelemetry/sdk/common/global_log_handler.h" -# include "opentelemetry/sdk/metrics/metric_exporter.h" # include "opentelemetry/sdk/metrics/metric_reader.h" # include "opentelemetry/sdk_config.h" # include "opentelemetry/version.h" @@ -15,13 +14,9 @@ namespace sdk namespace metrics { -MeterContext::MeterContext(std::vector> &&exporters, - std::unique_ptr views, +MeterContext::MeterContext(std::unique_ptr views, opentelemetry::sdk::resource::Resource resource) noexcept - : resource_{resource}, - exporters_(std::move(exporters)), - views_(std::move(views)), - sdk_start_ts_{std::chrono::system_clock::now()} + : resource_{resource}, views_(std::move(views)), sdk_start_ts_{std::chrono::system_clock::now()} {} const resource::Resource &MeterContext::GetResource() const noexcept @@ -49,11 +44,6 @@ opentelemetry::common::SystemTimestamp MeterContext::GetSDKStartTime() noexcept return sdk_start_ts_; } -void MeterContext::AddMetricExporter(std::unique_ptr exporter) noexcept -{ - exporters_.push_back(std::move(exporter)); -} - void MeterContext::AddMetricReader(std::unique_ptr reader) noexcept { auto collector = @@ -75,51 +65,41 @@ void MeterContext::AddMeter(std::shared_ptr meter) bool MeterContext::Shutdown() noexcept { - bool return_status = true; + bool result = true; if (!shutdown_latch_.test_and_set(std::memory_order_acquire)) { - bool result_exporter = true; - bool result_reader = true; - bool result_collector = true; - for (auto &exporter : exporters_) - { - bool status = exporter->Shutdown(); - result_exporter = result_exporter && status; - } - if (!result_exporter) - { - OTEL_INTERNAL_LOG_WARN("[MeterContext::Shutdown] Unable to shutdown all metric exporters"); - } for (auto &collector : collectors_) { - bool status = std::static_pointer_cast(collector)->Shutdown(); - result_collector = result_reader && status; + bool status = std::static_pointer_cast(collector)->Shutdown(); + result = result && status; } - if (!result_collector) + if (!result) { OTEL_INTERNAL_LOG_WARN("[MeterContext::Shutdown] Unable to shutdown all metric readers"); } - return_status = result_exporter && result_collector; } - return return_status; + return result; } bool MeterContext::ForceFlush(std::chrono::microseconds timeout) noexcept { // TODO - Implement timeout logic. - const std::lock_guard locked(forceflush_lock_); - bool result_exporter = true; - for (auto &exporter : exporters_) - { - bool status = exporter->ForceFlush(timeout); - result_exporter = result_exporter && status; - } - if (!result_exporter) + bool result = true; + if (!shutdown_latch_.test_and_set(std::memory_order_acquire)) { - OTEL_INTERNAL_LOG_WARN("[MeterContext::ForceFlush] Unable to force-flush all metric exporters"); + + for (auto &collector : collectors_) + { + bool status = std::static_pointer_cast(collector)->ForceFlush(timeout); + result = result && status; + } + if (!result) + { + OTEL_INTERNAL_LOG_WARN("[MeterContext::ForceFlush] Unable to ForceFlush all metric readers"); + } } - return result_exporter; + return result; } } // namespace metrics diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 8a9572c88c..788811cd61 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -4,7 +4,6 @@ #ifndef ENABLE_METRICS_PREVIEW # include "opentelemetry/sdk/metrics/meter_provider.h" # include "opentelemetry/metrics/meter.h" -# include "opentelemetry/sdk/metrics/metric_exporter.h" # include "opentelemetry/sdk/metrics/metric_reader.h" # include "opentelemetry/sdk/common/global_log_handler.h" @@ -23,10 +22,9 @@ namespace metrics_api = opentelemetry::metrics; MeterProvider::MeterProvider(std::shared_ptr context) noexcept : context_{context} {} -MeterProvider::MeterProvider(std::vector> &&exporters, - std::unique_ptr views, +MeterProvider::MeterProvider(std::unique_ptr views, sdk::resource::Resource resource) noexcept - : context_(std::make_shared(std::move(exporters), std::move(views), resource)) + : context_(std::make_shared(std::move(views), resource)) {} nostd::shared_ptr MeterProvider::GetMeter( @@ -61,11 +59,6 @@ const resource::Resource &MeterProvider::GetResource() const noexcept return context_->GetResource(); } -void MeterProvider::AddMetricExporter(std::unique_ptr exporter) noexcept -{ - return context_->AddMetricExporter(std::move(exporter)); -} - void MeterProvider::AddMetricReader(std::unique_ptr reader) noexcept { return context_->AddMetricReader(std::move(reader)); diff --git a/sdk/test/metrics/async_metric_storage_test.cc b/sdk/test/metrics/async_metric_storage_test.cc index 512e24472c..f939035fb2 100644 --- a/sdk/test/metrics/async_metric_storage_test.cc +++ b/sdk/test/metrics/async_metric_storage_test.cc @@ -46,8 +46,7 @@ TEST(AsyncMetricStorageTest, BasicTests) // Some computation here auto collection_ts = std::chrono::system_clock::now() + std::chrono::seconds(5); - std::vector> exporters; - std::shared_ptr meter_context(new MeterContext(std::move(exporters))); + std::shared_ptr meter_context(new MeterContext()); std::unique_ptr metric_reader(new MockMetricReader(AggregationTemporality::kDelta)); std::shared_ptr collector = std::shared_ptr( diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index 4a2792c3a7..b0fabe50bb 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -38,16 +38,19 @@ class MockMetricExporter : public MetricExporter class MockMetricReader : public MetricReader { public: + MockMetricReader(std::unique_ptr exporter) : exporter_(std::move(exporter)) {} virtual bool OnForceFlush(std::chrono::microseconds timeout) noexcept override { return true; } virtual bool OnShutDown(std::chrono::microseconds timeout) noexcept override { return true; } virtual void OnInitialized() noexcept override {} + +private: + std::unique_ptr exporter_; }; TEST(MeterProvider, GetMeter) { - std::vector> exporters; - MeterProvider mp1(std::move(exporters)); + MeterProvider mp1; // std::unique_ptr view{std::unique_ptr()}; // MeterProvider mp1(std::move(exporters), std::move(readers), std::move(views); auto m1 = mp1.GetMeter("test"); @@ -74,11 +77,8 @@ TEST(MeterProvider, GetMeter) auto sdkMeter1 = static_cast(m1.get()); # endif ASSERT_NE(nullptr, sdkMeter1); - - std::unique_ptr exporter{new MockMetricExporter()}; - ASSERT_NO_THROW(mp1.AddMetricExporter(std::move(exporter))); - - std::unique_ptr reader{new MockMetricReader()}; + std::unique_ptr exporter(new MockMetricExporter()); + std::unique_ptr reader{new MockMetricReader(std::move(exporter))}; ASSERT_NO_THROW(mp1.AddMetricReader(std::move(reader))); std::unique_ptr view{std::unique_ptr()}; diff --git a/sdk/test/metrics/metric_reader_test.cc b/sdk/test/metrics/metric_reader_test.cc index 61a4364934..c9c30853df 100644 --- a/sdk/test/metrics/metric_reader_test.cc +++ b/sdk/test/metrics/metric_reader_test.cc @@ -27,12 +27,11 @@ TEST(MetricReaderTest, BasicTests) std::unique_ptr metric_reader1(new MockMetricReader(aggr_temporality)); EXPECT_EQ(metric_reader1->GetAggregationTemporality(), aggr_temporality); - std::vector> exporters; - std::shared_ptr meter_context1(new MeterContext(std::move(exporters))); + std::shared_ptr meter_context1(new MeterContext()); EXPECT_NO_THROW(meter_context1->AddMetricReader(std::move(metric_reader1))); std::unique_ptr metric_reader2(new MockMetricReader(aggr_temporality)); - std::shared_ptr meter_context2(new MeterContext(std::move(exporters))); + std::shared_ptr meter_context2(new MeterContext()); MetricProducer *metric_producer = new MetricCollector(std::move(meter_context2), std::move(metric_reader2)); EXPECT_NO_THROW(metric_producer->Collect([](ResourceMetrics &metric_data) { return true; })); From 33cb82714efa460481187bfa136e6a0e3fd84b19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Apr 2022 10:55:34 -0700 Subject: [PATCH 05/17] Bump github/codeql-action from 1 to 2 (#1351) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b40b8e5a73..000a0eb0d0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -23,10 +23,10 @@ jobs: sudo ./ci/setup_cmake.sh sudo ./ci/setup_ci_environment.sh - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: cpp - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From c917beda3e5af3628020ad8faf58e61924260c8b Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Tue, 26 Apr 2022 12:42:26 -0700 Subject: [PATCH 06/17] Add explicit type cast in baggage UrlDecode (#1353) --- api/include/opentelemetry/baggage/baggage.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/include/opentelemetry/baggage/baggage.h b/api/include/opentelemetry/baggage/baggage.h index 7f904f09a7..259fd7f3b6 100644 --- a/api/include/opentelemetry/baggage/baggage.h +++ b/api/include/opentelemetry/baggage/baggage.h @@ -249,7 +249,9 @@ class Baggage }; auto from_hex = [](char c) -> char { - return std::isdigit(c) ? c - '0' : std::toupper(c) - 'A' + 10; + // c - '0' produces integer type which could trigger error/warning when casting to char, + // but the cast is safe here. + return static_cast(std::isdigit(c) ? c - '0' : std::toupper(c) - 'A' + 10); }; std::string ret; From e2337912f09b9380b0ca8803426a72313fb8d846 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Tue, 26 Apr 2022 22:27:39 -0700 Subject: [PATCH 07/17] Fix scalar delete against array (#1356) --- exporters/etw/include/opentelemetry/exporters/etw/utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/utils.h b/exporters/etw/include/opentelemetry/exporters/etw/utils.h index 8b0a015821..22a1c4fffc 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/utils.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -193,8 +193,8 @@ static inline GUID GetProviderGuid(const char *providerName) guid.Data4[6] = buffer2[14]; guid.Data4[7] = buffer2[15]; - delete buffer; - delete buffer2; + delete[] buffer; + delete[] buffer2; return guid; } From 3b9bfd41e7d547a8e90df47fb0ac36df0c46a713 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Wed, 27 Apr 2022 14:20:24 +0530 Subject: [PATCH 08/17] conditional include for codecvt header (#1355) --- exporters/etw/include/opentelemetry/exporters/etw/utils.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/utils.h b/exporters/etw/include/opentelemetry/exporters/etw/utils.h index 22a1c4fffc..4d38c1fb6f 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/utils.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -24,6 +23,8 @@ # pragma comment(lib, "Rpcrt4.lib") # include # pragma comment(lib, "Ole32.Lib") +#else +# include #endif OPENTELEMETRY_BEGIN_NAMESPACE From 72360b49f6aa44b5b163e48823952e50933b20f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zsolt=20B=C3=B6l=C3=B6ny?= Date: Wed, 27 Apr 2022 13:18:26 +0200 Subject: [PATCH 09/17] Add missing include guard (#1357) --- .../opentelemetry/context/propagation/composite_propagator.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/include/opentelemetry/context/propagation/composite_propagator.h b/api/include/opentelemetry/context/propagation/composite_propagator.h index 85ad97b0fc..d7a6cbda17 100644 --- a/api/include/opentelemetry/context/propagation/composite_propagator.h +++ b/api/include/opentelemetry/context/propagation/composite_propagator.h @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +#pragma once + #include #include #include From 4008da54fa29c71c6e8b32d5ff7b186136a128ff Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Wed, 27 Apr 2022 18:08:22 +0530 Subject: [PATCH 10/17] Use latest TraceLoggingDynamic.h (#1354) --- .../opentelemetry/exporters/etw/LICENSE | 23 +++++++++++++++++++ .../exporters/etw/TraceLoggingDynamic.h | 19 +++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 exporters/etw/include/opentelemetry/exporters/etw/LICENSE diff --git a/exporters/etw/include/opentelemetry/exporters/etw/LICENSE b/exporters/etw/include/opentelemetry/exporters/etw/LICENSE new file mode 100644 index 0000000000..cfc21fd2cc --- /dev/null +++ b/exporters/etw/include/opentelemetry/exporters/etw/LICENSE @@ -0,0 +1,23 @@ +TraceLogging Dynamic for Windows + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/exporters/etw/include/opentelemetry/exporters/etw/TraceLoggingDynamic.h b/exporters/etw/include/opentelemetry/exporters/etw/TraceLoggingDynamic.h index 5d493b319a..17ee108c64 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/TraceLoggingDynamic.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/TraceLoggingDynamic.h @@ -691,7 +691,7 @@ namespace tld } void AddBytes( - _In_bytecount_(cb) void const* p, + _In_reads_bytes_(cb) void const* p, unsigned cb) { auto pb = static_cast(p); @@ -2064,7 +2064,7 @@ namespace tld void AddTrait( ProviderTraitType type, - _In_bytecount_(cbData) void const* pData, + _In_reads_bytes_(cbData) void const* pData, unsigned cbData) { this->AddU16(static_cast(cbData + 3)); @@ -2232,6 +2232,7 @@ namespace tld return this->BaseEnd(); } + // Note: Do not create structs with 0 fields. template EventMetadataBuilder AddStruct( _In_z_ CharTy const* szUtfStructName, @@ -2242,6 +2243,7 @@ namespace tld return EventMetadataBuilder(this->GetBuffer(), bookmark); } + // Note: Do not create structs with 0 fields. template UINT32 AddStructRaw( _In_z_ CharTy const* szUtfStructName, @@ -2252,6 +2254,7 @@ namespace tld return bookmark; } + // Note: Do not create structs with 0 fields. template EventMetadataBuilder AddStructArray( _In_z_ CharTy const* szUtfStructName, @@ -2262,6 +2265,8 @@ namespace tld return EventMetadataBuilder(this->GetBuffer(), bookmark); } + // Note: Do not use 0 for itemCount. + // Note: Do not create structs with 0 fields. template EventMetadataBuilder AddStructFixedArray( _In_z_ CharTy const* szUtfStructName, @@ -2294,6 +2299,7 @@ namespace tld AddFieldInfo(InMetaVcount, type, fieldTags); } + // Note: Do not use 0 for itemCount. template void AddFieldFixedArray( _In_z_ CharTy const* szUtfFieldName, @@ -2400,7 +2406,7 @@ namespace tld Note: should only be used for blittable POD types with no padding. */ template - void AddValues(_In_count_(cValues) T const* pValues, unsigned cValues) + void AddValues(_In_reads_(cValues) T const* pValues, unsigned cValues) { AddBytes(pValues, sizeof(T) * cValues); } @@ -2917,6 +2923,7 @@ namespace tld of the nested struct. Note: do not call any Add methods on this builder object until you are done calling Add methods on the nested builder object. + Note: Do not create structs with 0 fields. */ template EventBuilder AddStruct( @@ -2933,6 +2940,7 @@ namespace tld of the nested struct. Note: do not call any Add methods on this builder object until you are done calling Add methods on the nested builder object. + Note: Do not create structs with 0 fields. */ template EventBuilder AddStructArray( @@ -2949,6 +2957,8 @@ namespace tld of the nested struct. Note: do not call any Add methods on this builder object until you are done calling Add methods on the nested builder object. + Note: Do not use 0 for itemCount. + Note: Do not create structs with 0 fields. */ template EventBuilder AddStructFixedArray( @@ -2992,6 +3002,7 @@ namespace tld Adds a fixed-length array field to the event's metadata. The length (item count) is encoded in the metadata, so it does not need to be included in the event's payload. + Note: Do not use 0 for itemCount. */ template void AddFieldFixedArray( @@ -3061,7 +3072,7 @@ namespace tld e.g. INT32, FILETIME, GUID, not for strings or structs. */ template - void AddValues(_In_count_(cValues) T const* pValues, unsigned cValues) + void AddValues(_In_reads_(cValues) T const* pValues, unsigned cValues) { m_dataBuilder.AddValues(pValues, cValues); } From a4bd3b0667b6534876003006d5179cef2772cf31 Mon Sep 17 00:00:00 2001 From: Ehsan Saei <71217171+esigo@users.noreply.github.com> Date: Thu, 28 Apr 2022 18:29:26 +0200 Subject: [PATCH 11/17] prometheus example (#1332) --- ci/do_ci.sh | 4 +- examples/CMakeLists.txt | 3 + examples/prometheus/BUILD | 14 +++ examples/prometheus/CMakeLists.txt | 5 + examples/prometheus/main.cc | 118 ++++++++++++++++++ examples/prometheus/prometheus.yml | 16 +++ examples/prometheus/run.sh | 1 + .../exporters/prometheus/exporter.h | 2 +- 8 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 examples/prometheus/BUILD create mode 100644 examples/prometheus/CMakeLists.txt create mode 100644 examples/prometheus/main.cc create mode 100644 examples/prometheus/prometheus.yml create mode 100644 examples/prometheus/run.sh diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 008e983842..14749500ec 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -222,8 +222,8 @@ elif [[ "$1" == "bazel.legacy.test" ]]; then elif [[ "$1" == "bazel.noexcept" ]]; then # there are some exceptions and error handling code from the Prometheus and Jaeger Clients # that make this test always fail. ignore Prometheus and Jaeger exporters in the noexcept here. - bazel $BAZEL_STARTUP_OPTIONS build --copt=-fno-exceptions --build_tag_filters=-jaeger $BAZEL_OPTIONS -- //... -//exporters/prometheus/... -//exporters/jaeger/... - bazel $BAZEL_STARTUP_OPTIONS test --copt=-fno-exceptions --build_tag_filters=-jaeger $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... -//exporters/jaeger/... + bazel $BAZEL_STARTUP_OPTIONS build --copt=-fno-exceptions --build_tag_filters=-jaeger $BAZEL_OPTIONS -- //... -//exporters/prometheus/... -//exporters/jaeger/... -//examples/prometheus/... + bazel $BAZEL_STARTUP_OPTIONS test --copt=-fno-exceptions --build_tag_filters=-jaeger $BAZEL_TEST_OPTIONS -- //... -//exporters/prometheus/... -//exporters/jaeger/... -//examples/prometheus/... exit 0 elif [[ "$1" == "bazel.nortti" ]]; then # there are some exceptions and error handling code from the Prometheus and Jaeger Clients diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index db0fe159be..2367918c7e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -15,6 +15,9 @@ endif() if(WITH_ZIPKIN) add_subdirectory(zipkin) endif() +if(WITH_PROMETHEUS AND NOT WITH_METRICS_PREVIEW) + add_subdirectory(prometheus) +endif() add_subdirectory(plugin) add_subdirectory(simple) add_subdirectory(batch) diff --git a/examples/prometheus/BUILD b/examples/prometheus/BUILD new file mode 100644 index 0000000000..edbfde61e6 --- /dev/null +++ b/examples/prometheus/BUILD @@ -0,0 +1,14 @@ +cc_binary( + name = "prometheus_example", + srcs = [ + "main.cc", + ], + linkopts = ["-pthread"], + tags = ["ostream"], + deps = [ + "//api", + "//examples/common/metrics_foo_library:common_metrics_foo_library", + "//exporters/prometheus:prometheus_exporter", + "//sdk/src/metrics", + ], +) diff --git a/examples/prometheus/CMakeLists.txt b/examples/prometheus/CMakeLists.txt new file mode 100644 index 0000000000..b377920dee --- /dev/null +++ b/examples/prometheus/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(${CMAKE_SOURCE_DIR}/exporters/prometheus/include) +add_executable(prometheus_example main.cc) +target_link_libraries( + prometheus_example ${CMAKE_THREAD_LIBS_INIT} opentelemetry_metrics + prometheus_exporter opentelemetry_resources common_metrics_foo_library) diff --git a/examples/prometheus/main.cc b/examples/prometheus/main.cc new file mode 100644 index 0000000000..77a648f55d --- /dev/null +++ b/examples/prometheus/main.cc @@ -0,0 +1,118 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include +# include +# include "opentelemetry/exporters/prometheus/exporter.h" +# include "opentelemetry/metrics/provider.h" +# include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h" +# include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h" +# include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h" +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/sdk/metrics/meter_provider.h" + +# ifdef BAZEL_BUILD +# include "examples/common/metrics_foo_library/foo_library.h" +# else +# include "metrics_foo_library/foo_library.h" +# endif + +namespace metrics_sdk = opentelemetry::sdk::metrics; +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; +namespace metrics_exporter = opentelemetry::exporter::metrics; +namespace metrics_api = opentelemetry::metrics; + +namespace +{ + +void initMetrics(const std::string &name, const std::string &addr) +{ + metrics_exporter::PrometheusExporterOptions opts; + if (!addr.empty()) + { + opts.url = addr; + } + std::puts("PrometheusExporter example program running ..."); + + std::unique_ptr exporter{ + new metrics_exporter::PrometheusExporter(opts)}; + + std::string version{"1.2.0"}; + std::string schema{"https://opentelemetry.io/schemas/1.2.0"}; + + // Initialize and set the global MeterProvider + metrics_sdk::PeriodicExportingMetricReaderOptions options; + options.export_interval_millis = std::chrono::milliseconds(1000); + options.export_timeout_millis = std::chrono::milliseconds(500); + std::unique_ptr reader{ + new metrics_sdk::PeriodicExportingMetricReader(std::move(exporter), options)}; + auto provider = std::shared_ptr(new metrics_sdk::MeterProvider()); + auto p = std::static_pointer_cast(provider); + p->AddMetricReader(std::move(reader)); + + // counter view + std::string counter_name = name + "_counter"; + std::unique_ptr instrument_selector{ + new metrics_sdk::InstrumentSelector(metrics_sdk::InstrumentType::kCounter, counter_name)}; + std::unique_ptr meter_selector{ + new metrics_sdk::MeterSelector(name, version, schema)}; + std::unique_ptr sum_view{ + new metrics_sdk::View{name, "description", metrics_sdk::AggregationType::kSum}}; + p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(sum_view)); + + // histogram view + std::string histogram_name = name + "_histogram"; + std::unique_ptr histogram_instrument_selector{ + new metrics_sdk::InstrumentSelector(metrics_sdk::InstrumentType::kHistogram, histogram_name)}; + std::unique_ptr histogram_meter_selector{ + new metrics_sdk::MeterSelector(name, version, schema)}; + std::unique_ptr histogram_view{ + new metrics_sdk::View{name, "description", metrics_sdk::AggregationType::kHistogram}}; + p->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector), + std::move(histogram_view)); + metrics_api::Provider::SetMeterProvider(provider); +} +} // namespace + +int main(int argc, char **argv) +{ + std::string example_type; + std::string addr{"localhost:8080"}; + if (argc == 1) + { + std::puts("usage: $prometheus_example "); + } + + if (argc >= 2) + { + example_type = argv[1]; + } + if (argc > 2) + { + addr = argv[2]; + } + + std::string name{"prometheus_metric_example"}; + initMetrics(name, addr); + + if (example_type == "counter") + { + foo_library::counter_example(name); + } + else if (example_type == "histogram") + { + foo_library::histogram_example(name); + } + else + { + std::thread counter_example{&foo_library::counter_example, name}; + std::thread histogram_example{&foo_library::histogram_example, name}; + counter_example.join(); + histogram_example.join(); + } +} +#else +int main() {} +#endif diff --git a/examples/prometheus/prometheus.yml b/examples/prometheus/prometheus.yml new file mode 100644 index 0000000000..3f415d39dc --- /dev/null +++ b/examples/prometheus/prometheus.yml @@ -0,0 +1,16 @@ +global: + scrape_interval: 5s + scrape_timeout: 2s + evaluation_interval: 5s +alerting: + alertmanagers: + - follow_redirects: true + scheme: http + timeout: 5s + api_version: v2 + static_configs: + - targets: [localhost:8080] +scrape_configs: + - job_name: otel + static_configs: + - targets: ['localhost:8080'] \ No newline at end of file diff --git a/examples/prometheus/run.sh b/examples/prometheus/run.sh new file mode 100644 index 0000000000..412c6ef454 --- /dev/null +++ b/examples/prometheus/run.sh @@ -0,0 +1 @@ +docker run -p 9090:9090 -v $(pwd):/etc/prometheus --network="host" prom/prometheus \ No newline at end of file diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h index 6945f09bb9..151244928f 100644 --- a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h @@ -31,7 +31,7 @@ namespace metrics inline const std::string GetOtlpDefaultHttpEndpoint() { constexpr char kPrometheusEndpointEnv[] = "PROMETHEUS_EXPORTER_ENDPOINT"; - constexpr char kPrometheusEndpointDefault[] = "http://localhost:8080"; + constexpr char kPrometheusEndpointDefault[] = "localhost:8080"; auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kPrometheusEndpointEnv); return endpoint.size() ? endpoint : kPrometheusEndpointDefault; From 3a4a3a33ffa5b1ee224818e19a3004bdc9bb3c95 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Thu, 28 Apr 2022 15:57:07 -0700 Subject: [PATCH 12/17] Fix output time in metrics OStream exporter (#1346) --- exporters/ostream/src/metric_exporter.cc | 33 +++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/exporters/ostream/src/metric_exporter.cc b/exporters/ostream/src/metric_exporter.cc index 5cdd3fe78d..bf97db04c2 100644 --- a/exporters/ostream/src/metric_exporter.cc +++ b/exporters/ostream/src/metric_exporter.cc @@ -14,7 +14,34 @@ namespace std::string timeToString(opentelemetry::common::SystemTimestamp time_stamp) { std::time_t epoch_time = std::chrono::system_clock::to_time_t(time_stamp); - return std::ctime(&epoch_time); + + struct tm *tm_ptr = nullptr; +# if defined(_MSC_VER) + struct tm buf_tm; + if (!gmtime_s(&buf_tm, &epoch_time)) + { + tm_ptr = &buf_tm; + } +# else + tm_ptr = std::gmtime(&epoch_time); +# endif + + char buf[100]; + char *date_str = nullptr; + if (tm_ptr == nullptr) + { + OTEL_INTERNAL_LOG_ERROR("[OStream Metric] gmtime failed for " << epoch_time); + } + else if (std::strftime(buf, sizeof(buf), "%c", tm_ptr) > 0) + { + date_str = buf; + } + else + { + OTEL_INTERNAL_LOG_ERROR("[OStream Metric] strftime failed for " << epoch_time); + } + + return std::string{date_str}; } } // namespace @@ -68,8 +95,8 @@ void OStreamMetricExporter::printInstrumentationInfoMetricData( for (const auto &record : info_metric.metric_data_) { sout_ << "\n start time\t: " << timeToString(record.start_ts) - << " end time\t: " << timeToString(record.end_ts) - << " description\t: " << record.instrument_descriptor.description_ + << "\n end time\t: " << timeToString(record.end_ts) + << "\n description\t: " << record.instrument_descriptor.description_ << "\n unit\t\t: " << record.instrument_descriptor.unit_; for (const auto &pd : record.point_data_attr_) From f31452286ce4742cb82a3059eaccb96ae8f1b0d2 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Sat, 30 Apr 2022 06:18:49 +0530 Subject: [PATCH 13/17] Simplify SDK Configuration: Use View with default aggregation if no matching View is configured (#1358) --- .../opentelemetry/sdk/metrics/view/view.h | 2 +- .../sdk/metrics/view/view_registry.h | 2 +- sdk/test/metrics/view_registry_test.cc | 16 +++++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/metrics/view/view.h b/sdk/include/opentelemetry/sdk/metrics/view/view.h index e88e7126c6..3cd9f850e1 100644 --- a/sdk/include/opentelemetry/sdk/metrics/view/view.h +++ b/sdk/include/opentelemetry/sdk/metrics/view/view.h @@ -23,7 +23,7 @@ class View public: View(const std::string &name, const std::string &description = "", - AggregationType aggregation_type = AggregationType::kDrop, + AggregationType aggregation_type = AggregationType::kDefault, std::unique_ptr attributes_processor = std::unique_ptr( new opentelemetry::sdk::metrics::DefaultAttributesProcessor())) diff --git a/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h b/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h index 87b842e46a..795049dd9a 100644 --- a/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h +++ b/sdk/include/opentelemetry/sdk/metrics/view/view_registry.h @@ -64,7 +64,7 @@ class ViewRegistry // return default view if none found; if (!found) { - static View view(""); + static View view("otel-default-view"); if (!callback(view)) { return false; diff --git a/sdk/test/metrics/view_registry_test.cc b/sdk/test/metrics/view_registry_test.cc index c3a9923c50..8151d37545 100644 --- a/sdk/test/metrics/view_registry_test.cc +++ b/sdk/test/metrics/view_registry_test.cc @@ -25,13 +25,15 @@ TEST(ViewRegistry, FindViewsEmptyRegistry) InstrumentationLibrary::Create("default", "1.0.0", "https://opentelemetry.io/schemas/1.7.0"); int count = 0; ViewRegistry registry; - auto status = registry.FindViews(default_instrument_descriptor, - *default_instrumentation_lib.get(), [&count](const View &view) { - count++; - EXPECT_EQ(view.GetName(), ""); - EXPECT_EQ(view.GetDescription(), ""); - return true; - }); + auto status = + registry.FindViews(default_instrument_descriptor, *default_instrumentation_lib.get(), + [&count](const View &view) { + count++; + EXPECT_EQ(view.GetName(), "otel-default-view"); + EXPECT_EQ(view.GetDescription(), ""); + EXPECT_EQ(view.GetAggregationType(), AggregationType::kDefault); + return true; + }); EXPECT_EQ(count, 1); EXPECT_EQ(status, true); } From 8ef6764c2fa15e05f4eaf4f5c397f33740f520bf Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Sat, 30 Apr 2022 07:10:06 +0530 Subject: [PATCH 14/17] Fix class member initialization order (#1360) --- .../etw/include/opentelemetry/exporters/etw/etw_tracer.h | 4 ++-- sdk/src/metrics/meter.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h index 65fe2770f2..82bd6d726c 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h @@ -761,10 +761,10 @@ class Span : public opentelemetry::trace::Span const opentelemetry::trace::StartSpanOptions &options, Span *parent = nullptr) noexcept : opentelemetry::trace::Span(), + start_time_(std::chrono::system_clock::now()), owner_(owner), parent_(parent), - context_(CreateContext()), - start_time_(std::chrono::system_clock::now()) + context_(CreateContext()) { name_ = name; UNREFERENCED_PARAMETER(options); diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index d5af7f9ec9..c0b0ce7a57 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -28,7 +28,7 @@ namespace nostd = opentelemetry::nostd; Meter::Meter(std::shared_ptr meter_context, std::unique_ptr instrumentation_library) noexcept - : meter_context_{meter_context}, instrumentation_library_{std::move(instrumentation_library)} + : instrumentation_library_{std::move(instrumentation_library)}, meter_context_{meter_context} {} nostd::shared_ptr> Meter::CreateLongCounter(nostd::string_view name, From c8bd431be27c71145098a1888dc115ab34997523 Mon Sep 17 00:00:00 2001 From: Ehsan Saei <71217171+esigo@users.noreply.github.com> Date: Sat, 30 Apr 2022 19:29:13 +0200 Subject: [PATCH 15/17] codecov ignore (#1364) --- .github/.codecov.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/.codecov.yaml b/.github/.codecov.yaml index 2b3003ff57..62d96e70f1 100644 --- a/.github/.codecov.yaml +++ b/.github/.codecov.yaml @@ -33,3 +33,10 @@ comment: # to coverage report file paths. fixes: - "/home/runner/::" + +ignore: + - "docs/**/*" + - "docker/**/*" + - "examples/**/*" + - "**/test/**/*" + - "**.md" \ No newline at end of file From c1e6e16e7d7d07969e73e7fc9150d69f21bbf5e6 Mon Sep 17 00:00:00 2001 From: Ehsan Saei <71217171+esigo@users.noreply.github.com> Date: Mon, 2 May 2022 19:12:38 +0200 Subject: [PATCH 16/17] export opentelemetry_otlp_recordable (#1365) --- exporters/otlp/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index 1b1b200504..b5dfa1e1ab 100755 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -100,8 +100,7 @@ install( DIRECTORY include/opentelemetry/exporters/otlp DESTINATION include/opentelemetry/exporters FILES_MATCHING - PATTERN "*.h" - PATTERN "otlp_recordable.h" EXCLUDE) + PATTERN "*.h") if(BUILD_TESTING) add_executable(otlp_recordable_test test/otlp_recordable_test.cc) From 13ac5c30b6f8ae996d05f3c4084c58f952734ac6 Mon Sep 17 00:00:00 2001 From: Tom Tan Date: Mon, 2 May 2022 12:28:51 -0700 Subject: [PATCH 17/17] Disable test on prometheus-cpp which not need (#1363) --- CMakeLists.txt | 5 ++++- exporters/prometheus/test/CMakeLists.txt | 24 +++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09c21fd678..9840aa19a6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,7 +274,10 @@ if(WITH_PROMETHEUS) if(NOT prometheus-cpp_FOUND) message("Trying to use local prometheus-cpp from submodule") if(EXISTS ${PROJECT_SOURCE_DIR}/third_party/prometheus-cpp/.git) + set(SAVED_ENABLE_TESTING ${ENABLE_TESTING}) + set(ENABLE_TESTING OFF) add_subdirectory(third_party/prometheus-cpp) + set(ENABLE_TESTING ${SAVED_ENABLE_TESTING}) else() message( FATAL_ERROR @@ -361,7 +364,7 @@ if(BUILD_TESTING) ${CMAKE_BINARY_DIR}/lib/libgmock.a) elseif(WIN32) # Make sure we are always bootsrapped with vcpkg on Windows - find_package(GTest) + find_package(GTest REQUIRED) if(NOT (GTEST_FOUND OR GTest_FOUND)) install_windows_deps() find_package(GTest REQUIRED) diff --git a/exporters/prometheus/test/CMakeLists.txt b/exporters/prometheus/test/CMakeLists.txt index 6c45e9299c..1a22469792 100644 --- a/exporters/prometheus/test/CMakeLists.txt +++ b/exporters/prometheus/test/CMakeLists.txt @@ -1,11 +1,13 @@ -foreach(testname prometheus_exporter_test prometheus_collector_test - prometheus_exporter_utils_test) - add_executable(${testname} "${testname}.cc") - target_link_libraries( - ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - prometheus_exporter_deprecated prometheus-cpp::pull) - gtest_add_tests( - TARGET ${testname} - TEST_PREFIX exporter. - TEST_LIST ${testname}) -endforeach() +if(WITH_METRICS_PREVIEW) + foreach(testname prometheus_exporter_test prometheus_collector_test + prometheus_exporter_utils_test) + add_executable(${testname} "${testname}.cc") + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + prometheus_exporter_deprecated prometheus-cpp::pull) + gtest_add_tests( + TARGET ${testname} + TEST_PREFIX exporter. + TEST_LIST ${testname}) + endforeach() +endif()