From b1b1f6409a3a95e783f746920ba48006d8d32926 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Mon, 29 Nov 2021 16:20:33 -0800 Subject: [PATCH] Add Meter and MeterProvider in the SDK (#1078) --- api/include/opentelemetry/metrics/meter.h | 24 +-- .../sdk/common/global_log_handler.h | 12 +- sdk/include/opentelemetry/sdk/metrics/meter.h | 109 ++++++++++++ .../opentelemetry/sdk/metrics/meter_context.h | 98 +++++++++++ .../sdk/metrics/meter_provider.h | 102 +++++++++++ .../sdk/metrics/metric_exporter.h | 50 ++++++ .../opentelemetry/sdk/metrics/metric_reader.h | 38 ++++ .../opentelemetry/sdk/metrics/recordable.h | 23 +++ sdk/include/opentelemetry/sdk/metrics/view.h | 27 +++ sdk/src/CMakeLists.txt | 2 + sdk/src/metrics/BUILD | 27 +++ sdk/src/metrics/CMakeLists.txt | 16 ++ sdk/src/metrics/meter.cc | 164 ++++++++++++++++++ sdk/src/metrics/meter_context.cc | 90 ++++++++++ sdk/src/metrics/meter_provider.cc | 97 +++++++++++ sdk/test/CMakeLists.txt | 2 + sdk/test/metrics/BUILD | 11 ++ sdk/test/metrics/CMakeLists.txt | 10 ++ sdk/test/metrics/meter_provider_sdk_test.cc | 82 +++++++++ 19 files changed, 966 insertions(+), 18 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/metrics/meter.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/meter_context.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/meter_provider.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/metric_exporter.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/metric_reader.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/recordable.h create mode 100644 sdk/include/opentelemetry/sdk/metrics/view.h create mode 100644 sdk/src/metrics/BUILD create mode 100644 sdk/src/metrics/CMakeLists.txt create mode 100644 sdk/src/metrics/meter.cc create mode 100644 sdk/src/metrics/meter_context.cc create mode 100644 sdk/src/metrics/meter_provider.cc create mode 100644 sdk/test/metrics/BUILD create mode 100644 sdk/test/metrics/CMakeLists.txt create mode 100644 sdk/test/metrics/meter_provider_sdk_test.cc diff --git a/api/include/opentelemetry/metrics/meter.h b/api/include/opentelemetry/metrics/meter.h index cd176d3157..9f7f2d2b0a 100644 --- a/api/include/opentelemetry/metrics/meter.h +++ b/api/include/opentelemetry/metrics/meter.h @@ -39,12 +39,12 @@ class Meter virtual nostd::shared_ptr> CreateLongCounter( nostd::string_view name, nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; virtual nostd::shared_ptr> CreateDoubleCounter( nostd::string_view name, nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; /** * Creates a Asynchronouse (Observable) counter with the passed characteristics and returns a @@ -60,13 +60,13 @@ class Meter nostd::string_view name, void (*callback)(ObserverResult &), nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; virtual nostd::shared_ptr> CreateDoubleObservableCounter( nostd::string_view name, void (*callback)(ObserverResult &), nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; /** * Creates a Histogram with the passed characteristics and returns a shared_ptr to that Histogram. @@ -79,12 +79,12 @@ class Meter virtual nostd::shared_ptr> CreateLongHistogram( nostd::string_view name, nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; virtual nostd::shared_ptr> CreateDoubleHistogram( nostd::string_view name, nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; /** * Creates a Asynchronouse (Observable) Gauge with the passed characteristics and returns a @@ -100,13 +100,13 @@ class Meter nostd::string_view name, void (*callback)(ObserverResult &), nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; virtual nostd::shared_ptr> CreateDoubleObservableGauge( nostd::string_view name, void (*callback)(ObserverResult &), nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; /** * Creates an UpDownCounter with the passed characteristics and returns a shared_ptr to that @@ -120,12 +120,12 @@ class Meter virtual nostd::shared_ptr> CreateLongUpDownCounter( nostd::string_view name, nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; virtual nostd::shared_ptr> CreateDoubleUpDownCounter( nostd::string_view name, nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; /** * Creates a Asynchronouse (Observable) UpDownCounter with the passed characteristics and returns @@ -141,13 +141,13 @@ class Meter nostd::string_view name, void (*callback)(ObserverResult &), nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; virtual nostd::shared_ptr> CreateDoubleObservableUpDownCounter( nostd::string_view name, void (*callback)(ObserverResult &), nostd::string_view description = "", - nostd::string_view unit = "1") noexcept = 0; + nostd::string_view unit = "") noexcept = 0; }; } // namespace metrics OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/common/global_log_handler.h b/sdk/include/opentelemetry/sdk/common/global_log_handler.h index f967111e3a..0ef5d54c46 100644 --- a/sdk/include/opentelemetry/sdk/common/global_log_handler.h +++ b/sdk/include/opentelemetry/sdk/common/global_log_handler.h @@ -164,12 +164,12 @@ OPENTELEMETRY_END_NAMESPACE #endif #if OTEL_INTERNAL_LOG_LEVEL >= OTEL_INTERNAL_LOG_LEVEL_WARN -# define OTEL_INTERNAL_LOG_WARN_1_ARGS(message) \ - OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Warn, message, \ - {}) -# define OTEL_INTERNAL_LOG_WARN_2_ARGS(message, attributes) \ - OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Warn, message, \ - attributes) +# define OTEL_INTERNAL_LOG_WARN_1_ARGS(message) \ + OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Warning, \ + message, {}) +# define OTEL_INTERNAL_LOG_WARN_2_ARGS(message, attributes) \ + OTEL_INTERNAL_LOG_DISPATCH(opentelemetry::sdk::common::internal_log::LogLevel::Warning, \ + message, attributes) # define OTEL_INTERNAL_LOG_WARN_MACRO(...) \ OTEL_INTERNAL_LOG_GET_3RD_ARG(__VA_ARGS__, OTEL_INTERNAL_LOG_WARN_2_ARGS, \ OTEL_INTERNAL_LOG_WARN_1_ARGS) diff --git a/sdk/include/opentelemetry/sdk/metrics/meter.h b/sdk/include/opentelemetry/sdk/metrics/meter.h new file mode 100644 index 0000000000..b1a4e304d7 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/meter.h @@ -0,0 +1,109 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include +# include "opentelemetry/metrics/meter.h" +# include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h" +# include "opentelemetry/sdk/metrics/meter_context.h" +# include "opentelemetry/sdk/resource/resource.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +class Meter final : public opentelemetry::metrics::Meter +{ +public: + /** Construct a new Meter with the given pipeline. */ + explicit Meter(std::shared_ptr context, + std::unique_ptr + instrumentation_library = + opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary::Create( + "")) noexcept; + + nostd::shared_ptr> CreateLongCounter( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> CreateDoubleCounter( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> CreateLongObservableCounter( + nostd::string_view name, + void (*callback)(opentelemetry::metrics::ObserverResult &), + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> + CreateDoubleObservableCounter(nostd::string_view name, + void (*callback)(opentelemetry::metrics::ObserverResult &), + nostd::string_view description = "", + nostd::string_view unit = "1") noexcept override; + + nostd::shared_ptr> CreateLongHistogram( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> CreateDoubleHistogram( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> CreateLongObservableGauge( + nostd::string_view name, + void (*callback)(opentelemetry::metrics::ObserverResult &), + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> CreateDoubleObservableGauge( + nostd::string_view name, + void (*callback)(opentelemetry::metrics::ObserverResult &), + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> CreateLongUpDownCounter( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> CreateDoubleUpDownCounter( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> + CreateLongObservableUpDownCounter( + nostd::string_view name, + void (*callback)(opentelemetry::metrics::ObserverResult &), + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::shared_ptr> + CreateDoubleObservableUpDownCounter( + nostd::string_view name, + void (*callback)(opentelemetry::metrics::ObserverResult &), + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + /** Returns the associated instruementation library */ + const sdk::instrumentationlibrary::InstrumentationLibrary &GetInstrumentationLibrary() + const noexcept; + +private: + // order of declaration is important here - instrumentation library should destroy after + // meter-context. + std::shared_ptr instrumentation_library_; + std::shared_ptr context_; +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_context.h b/sdk/include/opentelemetry/sdk/metrics/meter_context.h new file mode 100644 index 0000000000..c9e14fd88f --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/meter_context.h @@ -0,0 +1,98 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include +# include +# include +# include "opentelemetry/sdk/metrics/metric_exporter.h" +# include "opentelemetry/sdk/metrics/metric_reader.h" +# include "opentelemetry/sdk/metrics/view.h" +# include "opentelemetry/sdk/resource/resource.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +/** + * A class which stores the MeterProvider context. + + */ +class MeterContext +{ +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::vector> &&readers, + std::vector> &&views, + opentelemetry::sdk::resource::Resource resource = + opentelemetry::sdk::resource::Resource::Create({})) noexcept; + + /** + * Obtain the resource associated with this meter context. + * @return The resource for this meter context + */ + const opentelemetry::sdk::resource::Resource &GetResource() const 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 + * must not be a nullptr. + * + * Note: This reader 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 AddMetricReader(std::unique_ptr reader) noexcept; + + /** + * Attaches a View to list of configured Views for this Meter context. + * @param view The Views for this meter context. This + * must not be a nullptr. + * + * Note: This view 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 AddView(std::unique_ptr view) noexcept; + + /** + * Force all active Exporters and Readers 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 Readers associated with this meter provider. + */ + bool Shutdown() noexcept; + +private: + opentelemetry::sdk::resource::Resource resource_; + std::vector> exporters_; + std::vector> readers_; + std::vector> views_; +}; + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h new file mode 100644 index 0000000000..88cedec81b --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h @@ -0,0 +1,102 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include +# include +# include +# include "opentelemetry/metrics/meter_provider.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/sdk/metrics/meter_context.h" +# include "opentelemetry/sdk/resource/resource.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +class MeterProvider final : public opentelemetry::metrics::MeterProvider +{ +public: + /** + * Initialize a new meter provider + * @param exporters The span exporters for this meter provider + * @param readers The readers 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::vector> &&readers, + std::vector> &&views, + sdk::resource::Resource resource = sdk::resource::Resource::Create({})) noexcept; + + /** + * Initialize a new meter provider with a specified context + * @param context The shared meter configuration/pipeline for this provider. + */ + explicit MeterProvider(std::shared_ptr context) noexcept; + + nostd::shared_ptr GetMeter( + nostd::string_view name, + nostd::string_view version = "", + nostd::string_view schema_url = "") noexcept override; + + /** + * Obtain the resource associated with this meter provider. + * @return The resource for this meter provider. + */ + 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 + * must not be a nullptr. + * + * Note: This reader 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 AddMetricReader(std::unique_ptr reader) noexcept; + + /** + * Attaches a View to list of configured Views for this Meter provider. + * @param view The Views for this meter provider. This + * must not be a nullptr. + * + * Note: This view 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 AddView(std::unique_ptr view) noexcept; + + /** + * Shutdown the meter provider. + */ + bool Shutdown() noexcept; + + /** + * Force flush the meter provider. + */ + bool ForceFlush(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept; + +private: + // // order of declaration is important here - meter should destroy only after resource. + std::vector> meters_; + std::shared_ptr context_; + std::mutex lock_; +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/metrics/metric_exporter.h b/sdk/include/opentelemetry/sdk/metrics/metric_exporter.h new file mode 100644 index 0000000000..4dedd80b4c --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/metric_exporter.h @@ -0,0 +1,50 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include +# include "opentelemetry/sdk/common/exporter_utils.h" +# include "opentelemetry/sdk/metrics/recordable.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +/** + * MetricExporter defines the interface to be used by metrics libraries to + * push metrics data to the OpenTelemetry exporters. + */ +class MetricExporter +{ +public: + virtual ~MetricExporter() = default; + + /** + * Exports a batch of metrics recordables. This method must not be called + * concurrently for the same exporter instance. + * @param spans a span of unique pointers to metrics recordables + */ + virtual opentelemetry::sdk::common::ExportResult Export( + const nostd::span> + &spans) noexcept = 0; + + /** + * Force flush the exporter. + */ + virtual bool ForceFlush( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept = 0; + + /** + * Shut down the metric exporter. + * @param timeout an optional timeout. + * @return return the status of the operation. + */ + virtual bool Shutdown() noexcept = 0; +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/metrics/metric_reader.h b/sdk/include/opentelemetry/sdk/metrics/metric_reader.h new file mode 100644 index 0000000000..92b4f9f219 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/metric_reader.h @@ -0,0 +1,38 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +/** + * MetricReader defines the interface to collect metrics from SDK + */ +class MetricReader +{ +public: + virtual ~MetricReader() = default; + + /** + * Collect the metrics from SDK. + * @return return the status of the operation. + */ + virtual bool Collect() noexcept = 0; + + /** + * Shut down the metric reader. + * @param timeout an optional timeout. + * @return return the status of the operation. + */ + virtual bool Shutdown() noexcept = 0; +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/metrics/recordable.h b/sdk/include/opentelemetry/sdk/metrics/recordable.h new file mode 100644 index 0000000000..7daee592b1 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/recordable.h @@ -0,0 +1,23 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +class Recordable +{ +public: + virtual ~Recordable() = default; + + // TBD +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE; +#endif diff --git a/sdk/include/opentelemetry/sdk/metrics/view.h b/sdk/include/opentelemetry/sdk/metrics/view.h new file mode 100644 index 0000000000..7ec6cbb37d --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/view.h @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifndef ENABLE_METRICS_PREVIEW +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +/** + * View defines the interface to allow SDK user to + * customize the metrics before exported. + */ + +class View +{ +public: + virtual ~View() = default; + // TBD +}; +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/CMakeLists.txt b/sdk/src/CMakeLists.txt index 1c868a1bf4..aab294b6de 100644 --- a/sdk/src/CMakeLists.txt +++ b/sdk/src/CMakeLists.txt @@ -2,6 +2,8 @@ add_subdirectory(common) add_subdirectory(trace) if(WITH_METRICS_PREVIEW) add_subdirectory(_metrics) +else() + add_subdirectory(metrics) endif() if(WITH_LOGS_PREVIEW) add_subdirectory(logs) diff --git a/sdk/src/metrics/BUILD b/sdk/src/metrics/BUILD new file mode 100644 index 0000000000..d21daa765c --- /dev/null +++ b/sdk/src/metrics/BUILD @@ -0,0 +1,27 @@ +# Copyright 2020, 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. + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "metrics", + srcs = glob(["**/*.cc"]), + hdrs = glob(["**/*.h"]), + include_prefix = "src/metrics", + deps = [ + "//api", + "//sdk:headers", + "//sdk/src/resource", + ], +) diff --git a/sdk/src/metrics/CMakeLists.txt b/sdk/src/metrics/CMakeLists.txt new file mode 100644 index 0000000000..d1d7ae97bc --- /dev/null +++ b/sdk/src/metrics/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(opentelemetry_metrics meter_provider.cc meter.cc meter_context.cc) + +set_target_properties(opentelemetry_metrics PROPERTIES EXPORT_NAME metrics) + +target_link_libraries(opentelemetry_metrics PUBLIC opentelemetry_common) + +target_include_directories( + opentelemetry_metrics + PUBLIC "$") + +install( + TARGETS opentelemetry_metrics + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc new file mode 100644 index 0000000000..6c759158a4 --- /dev/null +++ b/sdk/src/metrics/meter.cc @@ -0,0 +1,164 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/metrics/noop.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/sdk/common/global_log_handler.h" +# include "opentelemetry/version.h" + +# include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +namespace metrics = opentelemetry::metrics; +namespace nostd = opentelemetry::nostd; + +Meter::Meter(std::shared_ptr context, + std::unique_ptr + instrumentation_library) noexcept + : context_{context}, instrumentation_library_{std::move(instrumentation_library)} +{} + +nostd::shared_ptr> Meter::CreateLongCounter(nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateLongCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopCounter(name, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateDoubleCounter( + nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateDoubleCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopCounter(name, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateLongObservableCounter( + nostd::string_view name, + void (*callback)(metrics::ObserverResult &), + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateLongObservableCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopObservableCounter(name, callback, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateDoubleObservableCounter( + nostd::string_view name, + void (*callback)(metrics::ObserverResult &), + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateDoubleObservableCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopObservableCounter(name, callback, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateLongHistogram( + nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateLongHistogram] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopHistogram(name, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateDoubleHistogram( + nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateDoubleHistogram] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopHistogram(name, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateLongObservableGauge( + nostd::string_view name, + void (*callback)(metrics::ObserverResult &), + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateLongObservableGauge] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopObservableGauge(name, callback, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateDoubleObservableGauge( + nostd::string_view name, + void (*callback)(metrics::ObserverResult &), + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateDoubleObservableGauge] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopObservableGauge(name, callback, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateLongUpDownCounter( + nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateLongUpDownCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopUpDownCounter(name, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateDoubleUpDownCounter( + nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN("[Meter::CreateDoubleUpDownCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopUpDownCounter(name, description, unit)}; +} + +nostd::shared_ptr> Meter::CreateLongObservableUpDownCounter( + nostd::string_view name, + void (*callback)(metrics::ObserverResult &), + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN( + "[Meter::CreateLongObservableUpDownCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopObservableUpDownCounter(name, callback, description, unit)}; +} + +nostd::shared_ptr> +Meter::CreateDoubleObservableUpDownCounter(nostd::string_view name, + void (*callback)(metrics::ObserverResult &), + nostd::string_view description, + nostd::string_view unit) noexcept +{ + OTEL_INTERNAL_LOG_WARN( + "[Meter::CreateDoubleObservableUpDownCounter] Not Implemented - Returns Noop."); + return nostd::shared_ptr>{ + new metrics::NoopObservableUpDownCounter(name, callback, description, unit)}; +} + +const sdk::instrumentationlibrary::InstrumentationLibrary &Meter::GetInstrumentationLibrary() + const noexcept +{ + return *instrumentation_library_; +} + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/metrics/meter_context.cc b/sdk/src/metrics/meter_context.cc new file mode 100644 index 0000000000..3ece2bee78 --- /dev/null +++ b/sdk/src/metrics/meter_context.cc @@ -0,0 +1,90 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include "opentelemetry/sdk/common/global_log_handler.h" +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/sdk_config.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +MeterContext::MeterContext(std::vector> &&exporters, + std::vector> &&readers, + std::vector> &&views, + opentelemetry::sdk::resource::Resource resource) noexcept + : exporters_(std::move(exporters)), + readers_(std::move(readers)), + views_(std::move(views)), + resource_{resource} +{} + +const resource::Resource &MeterContext::GetResource() const noexcept +{ + return resource_; +} + +void MeterContext::AddMetricExporter(std::unique_ptr exporter) noexcept +{ + exporters_.push_back(std::move(exporter)); +} + +void MeterContext::AddMetricReader(std::unique_ptr reader) noexcept +{ + readers_.push_back(std::move(reader)); +} + +void MeterContext::AddView(std::unique_ptr view) noexcept +{ + views_.push_back(std::move(view)); +} + +bool MeterContext::Shutdown() noexcept +{ + bool result_exporter = true; + bool result_reader = 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 &reader : readers_) + { + bool status = reader->Shutdown(); + result_reader = result_reader && status; + } + if (!result_reader) + { + OTEL_INTERNAL_LOG_WARN("[MeterContext::Shutdown] Unable to shutdown all metric readers"); + } + return result_exporter && result_reader; +} + +bool MeterContext::ForceFlush(std::chrono::microseconds timeout) noexcept +{ + // TODO - Implement timeout logic. + bool result_exporter = true; + for (auto &exporter : exporters_) + { + bool status = exporter->ForceFlush(timeout); + result_exporter = result_exporter && status; + } + if (!result_exporter) + { + OTEL_INTERNAL_LOG_WARN("[MeterContext::ForceFlush] Unable to force-flush all metric exporters"); + } + return result_exporter; +} + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc new file mode 100644 index 0000000000..337e45c6be --- /dev/null +++ b/sdk/src/metrics/meter_provider.cc @@ -0,0 +1,97 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include "opentelemetry/sdk/metrics/meter_provider.h" +# include "opentelemetry/sdk/common/global_log_handler.h" +# include "opentelemetry/sdk_config.h" +# include "opentelemetry/version.h" + +# include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ +namespace resource = opentelemetry::sdk::resource; +namespace metrics_api = opentelemetry::metrics; + +MeterProvider::MeterProvider(std::shared_ptr context) noexcept : context_{context} {} + +MeterProvider::MeterProvider(std::vector> &&exporters, + std::vector> &&readers, + std::vector> &&views, + sdk::resource::Resource resource) noexcept + : context_(std::make_shared(std::move(exporters), + std::move(readers), + std::move(views), + resource)) +{} + +nostd::shared_ptr MeterProvider::GetMeter( + nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url) noexcept +{ + if (name.data() == nullptr || name == "") + { + OTEL_INTERNAL_LOG_WARN("[MeterProvider::GetMeter] Library name is empty."); + name = ""; + } + + const std::lock_guard guard(lock_); + + for (auto &meter : meters_) + { + auto &meter_lib = meter->GetInstrumentationLibrary(); + if (meter_lib.equal(name, version, schema_url)) + { + return nostd::shared_ptr{meter}; + } + } + auto lib = instrumentationlibrary::InstrumentationLibrary::Create(name, version, schema_url); + meters_.push_back(std::shared_ptr(new Meter(context_, std::move(lib)))); + return nostd::shared_ptr{meters_.back()}; +} + +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)); +} + +void MeterProvider::AddView(std::unique_ptr view) noexcept +{ + return context_->AddView(std::move(view)); +} + +/** + * Shutdown the meter provider. + */ +bool MeterProvider::Shutdown() noexcept +{ + return context_->Shutdown(); +} + +/** + * Force flush the meter provider. + */ +bool MeterProvider::ForceFlush(std::chrono::microseconds timeout) noexcept +{ + return context_->ForceFlush(timeout); +} + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/test/CMakeLists.txt b/sdk/test/CMakeLists.txt index 445568665a..dc8cc2b22c 100644 --- a/sdk/test/CMakeLists.txt +++ b/sdk/test/CMakeLists.txt @@ -2,6 +2,8 @@ add_subdirectory(common) add_subdirectory(trace) if(WITH_METRICS_PREVIEW) add_subdirectory(_metrics) +else() + add_subdirectory(metrics) endif() if(WITH_LOGS_PREVIEW) add_subdirectory(logs) diff --git a/sdk/test/metrics/BUILD b/sdk/test/metrics/BUILD new file mode 100644 index 0000000000..6ba99b4f7a --- /dev/null +++ b/sdk/test/metrics/BUILD @@ -0,0 +1,11 @@ +cc_test( + name = "meter_provider_sdk_test", + srcs = [ + "meter_provider_sdk_test.cc", + ], + deps = [ + "//sdk/src/metrics", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt new file mode 100644 index 0000000000..b7a8112aba --- /dev/null +++ b/sdk/test/metrics/CMakeLists.txt @@ -0,0 +1,10 @@ +foreach(testname meter_provider_sdk_test) + add_executable(${testname} "${testname}.cc") + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_resources opentelemetry_metrics) + gtest_add_tests( + TARGET ${testname} + TEST_PREFIX metrics. + TEST_LIST ${testname}) +endforeach() diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc new file mode 100644 index 0000000000..c001da87b2 --- /dev/null +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -0,0 +1,82 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ENABLE_METRICS_PREVIEW +# include +# include "opentelemetry/sdk/metrics/meter.h" +# include "opentelemetry/sdk/metrics/meter_provider.h" + +using namespace opentelemetry::sdk::metrics; + +class MockMetricExporter : public MetricExporter +{ + +public: + MockMetricExporter() = default; + opentelemetry::sdk::common::ExportResult Export( + const opentelemetry::nostd::span> &spans) noexcept override + { + return opentelemetry::sdk::common::ExportResult::kSuccess; + } + + bool ForceFlush( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override + { + return true; + } + + bool Shutdown() noexcept override { return true; } +}; + +class MockMetricReader : public MetricReader +{ +public: + bool Collect() noexcept override { return true; } + + bool Shutdown() noexcept override { return true; } +}; + +class MockView : public View +{}; + +TEST(MeterProvider, GetMeter) +{ + std::vector> exporters; + std::vector> readers; + std::vector> views; + MeterProvider mp1(std::move(exporters), std::move(readers), std::move(views)); + auto m1 = mp1.GetMeter("test"); + auto m2 = mp1.GetMeter("test"); + auto m3 = mp1.GetMeter("different", "1.0.0"); + auto m4 = mp1.GetMeter(""); + auto m5 = mp1.GetMeter(opentelemetry::nostd::string_view{}); + auto m6 = mp1.GetMeter("different", "1.0.0", "https://opentelemetry.io/schemas/1.2.0"); + ASSERT_NE(nullptr, m1); + ASSERT_NE(nullptr, m2); + ASSERT_NE(nullptr, m3); + ASSERT_NE(nullptr, m6); + + // Should return the same instance each time. + ASSERT_EQ(m1, m2); + ASSERT_NE(m1, m3); + ASSERT_EQ(m4, m5); + ASSERT_NE(m3, m6); + + // Should be an sdk::trace::Tracer with the processor attached. +# ifdef RTTI_ENABLED + auto sdkMeter1 = dynamic_cast(m1.get()); +# else + 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()}; + ASSERT_NO_THROW(mp1.AddMetricReader(std::move(reader))); + + std::unique_ptr view{new MockView()}; + ASSERT_NO_THROW(mp1.AddView(std::move(view))); +} +#endif