diff --git a/CHANGELOG.md b/CHANGELOG.md index a666b35c30..610d00e6f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -185,6 +185,10 @@ Increment the: `trace_based` to match the specification. [#4328](https://github.com/open-telemetry/opentelemetry-cpp/pull/4328) +* [SDK] Complete exemplar filtering: the exemplar filter(`AlwaysOn`/ + `AlwaysOff`/`TraceBased`) + [#4267](https://github.com/open-telemetry/opentelemetry-cpp/pull/4267) + Breaking changes: * [CONFIGURATION] SDK default component builder libraries and example @@ -231,6 +235,18 @@ Breaking changes: rebuilt. [#4328](https://github.com/open-telemetry/opentelemetry-cpp/pull/4328) +* [METRICS SDK] Remove the `SystemTimestamp` parameter from the preview + `ExemplarReservoir::OfferMeasurement()` overloads + [#4267](https://github.com/open-telemetry/opentelemetry-cpp/pull/4267) + * This is an incompatible API and ABI change for custom exemplar reservoirs. + Implementations and callers must remove the timestamp parameter. + +* [METRICS SDK] Breaking change to the preview metrics exemplar surface: the + `SyncMetricStorage`/`AsyncMetricStorage` constructors now take an + `ExemplarFilterType`, and `ExemplarData::Create` takes the `SpanContext` + by value. + [#4267](https://github.com/open-telemetry/opentelemetry-cpp/pull/4267) + ## [1.28.0] 2026-07-16 * [RELEASE] Bump main branch to 1.28.0-dev diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 24205c75ef..7fc4d304b1 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -633,7 +633,7 @@ elif [[ "$1" == "bazel.tsan" ]]; then exit 0 elif [[ "$1" == "bazel.valgrind" ]]; then bazel $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS_ASYNC //... - bazel $BAZEL_STARTUP_OPTIONS test --test_timeout=600 --run_under="/usr/bin/valgrind --leak-check=full --error-exitcode=1 --errors-for-leak-kinds=definite --suppressions=\"${SRC_DIR}/ci/valgrind-suppressions\"" $BAZEL_TEST_OPTIONS_ASYNC //... + bazel $BAZEL_STARTUP_OPTIONS test --test_timeout=900 --run_under="/usr/bin/valgrind --leak-check=full --error-exitcode=1 --errors-for-leak-kinds=definite --suppressions=\"${SRC_DIR}/ci/valgrind-suppressions\"" $BAZEL_TEST_OPTIONS_ASYNC //... exit 0 elif [[ "$1" == "benchmark" ]]; then [ -z "${BENCHMARK_DIR}" ] && export BENCHMARK_DIR=$HOME/benchmark diff --git a/sdk/include/opentelemetry/sdk/metrics/data/exemplar_data.h b/sdk/include/opentelemetry/sdk/metrics/data/exemplar_data.h index 8359c04075..929e56b541 100644 --- a/sdk/include/opentelemetry/sdk/metrics/data/exemplar_data.h +++ b/sdk/include/opentelemetry/sdk/metrics/data/exemplar_data.h @@ -3,8 +3,6 @@ #pragma once -#include - #include "opentelemetry/common/timestamp.h" #include "opentelemetry/sdk/metrics/data/metric_data.h" #include "opentelemetry/sdk/metrics/state/filtered_ordered_attribute_map.h" @@ -26,7 +24,7 @@ using MetricAttributes = opentelemetry::sdk::metrics::FilteredOrderedAttributeMa class ExemplarData { public: - static ExemplarData Create(const std::shared_ptr &context, + static ExemplarData Create(const opentelemetry::trace::SpanContext &context, const opentelemetry::common::SystemTimestamp ×tamp, const PointDataAttributes &point_data_attr) { @@ -68,10 +66,10 @@ class ExemplarData static PointType CreateDropPointData() { return DropPointData{}; } private: - ExemplarData(const std::shared_ptr &context, + ExemplarData(const opentelemetry::trace::SpanContext &context, opentelemetry::common::SystemTimestamp timestamp, const PointDataAttributes &point_data_attr) - : context_(*context.get()), timestamp_(timestamp), point_data_attr_(point_data_attr) + : context_(context), timestamp_(timestamp), point_data_attr_(point_data_attr) {} opentelemetry::trace::SpanContext context_; diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/filter_predicate.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/filter_predicate.h new file mode 100644 index 0000000000..6c30f5787f --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/filter_predicate.h @@ -0,0 +1,47 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW + +# include "opentelemetry/context/context.h" +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" +# include "opentelemetry/trace/context.h" +# include "opentelemetry/trace/span_context.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +/** + * Decides whether a measurement is eligible to be offered to the exemplar reservoir. + * + * - kAlwaysOff : no measurement is eligible (exemplar sampling disabled). + * - kAlwaysOn : every measurement is eligible. + * - kTraceBased : eligible only when recorded inside a valid, sampled span. + */ +inline bool ExemplarFilterEnabled(ExemplarFilterType filter_type, + const opentelemetry::context::Context &context) noexcept +{ + switch (filter_type) + { + case ExemplarFilterType::kAlwaysOn: + return true; + case ExemplarFilterType::kAlwaysOff: + return false; + default: // TraceBased. + const opentelemetry::trace::SpanContext span_context = + opentelemetry::trace::GetSpanContext(context); + return span_context.IsValid() && span_context.IsSampled(); + } +} + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE + +#endif // ENABLE_METRICS_EXEMPLAR_PREVIEW diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/fixed_size_exemplar_reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/fixed_size_exemplar_reservoir.h index 5be8b2513e..c455c0188b 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/fixed_size_exemplar_reservoir.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/fixed_size_exemplar_reservoir.h @@ -36,11 +36,9 @@ class FixedSizeExemplarReservoir : public ExemplarReservoir using ExemplarReservoir::OfferMeasurement; - void OfferMeasurement( - int64_t value, - const MetricAttributes &attributes, - const opentelemetry::context::Context &context, - const opentelemetry::common::SystemTimestamp & /* timestamp */) noexcept override + void OfferMeasurement(int64_t value, + const MetricAttributes &attributes, + const opentelemetry::context::Context &context) noexcept override { if (!reservoir_cell_selector_) { @@ -54,11 +52,9 @@ class FixedSizeExemplarReservoir : public ExemplarReservoir } } - void OfferMeasurement( - double value, - const MetricAttributes &attributes, - const opentelemetry::context::Context &context, - const opentelemetry::common::SystemTimestamp & /* timestamp */) noexcept override + void OfferMeasurement(double value, + const MetricAttributes &attributes, + const opentelemetry::context::Context &context) noexcept override { if (!reservoir_cell_selector_) { diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h index 58e9c368ca..905745abf3 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h @@ -26,20 +26,16 @@ class NoExemplarReservoir final : public ExemplarReservoir { public: - void OfferMeasurement( - int64_t /* value */, - const MetricAttributes & /* attributes */, - const opentelemetry::context::Context & /* context */, - const opentelemetry::common::SystemTimestamp & /* timestamp */) noexcept override + void OfferMeasurement(int64_t /* value */, + const MetricAttributes & /* attributes */, + const opentelemetry::context::Context & /* context */) noexcept override { // Stores nothing } - void OfferMeasurement( - double /* value */, - const MetricAttributes & /* attributes */, - const opentelemetry::context::Context & /* context */, - const opentelemetry::common::SystemTimestamp & /* timestamp */) noexcept override + void OfferMeasurement(double /* value */, + const MetricAttributes & /* attributes */, + const opentelemetry::context::Context & /* context */) noexcept override { // Stores nothing. } diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h index efbd20abc4..23b6d67770 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h @@ -8,7 +8,6 @@ # include # include -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir_cell_selector.h" # include "opentelemetry/version.h" @@ -47,18 +46,14 @@ class ExemplarReservoir virtual ~ExemplarReservoir() = default; /** Offers a long measurement to be sampled. */ - virtual void OfferMeasurement( - int64_t value, - const MetricAttributes &attributes, - const opentelemetry::context::Context &context, - const opentelemetry::common::SystemTimestamp ×tamp) noexcept = 0; + virtual void OfferMeasurement(int64_t value, + const MetricAttributes &attributes, + const opentelemetry::context::Context &context) noexcept = 0; /** Offers a double measurement to be sampled. */ - virtual void OfferMeasurement( - double value, - const MetricAttributes &attributes, - const opentelemetry::context::Context &context, - const opentelemetry::common::SystemTimestamp ×tamp) noexcept = 0; + virtual void OfferMeasurement(double value, + const MetricAttributes &attributes, + const opentelemetry::context::Context &context) noexcept = 0; /** * Builds vector of Exemplars for exporting from the current reservoir. @@ -73,10 +68,6 @@ class ExemplarReservoir virtual std::vector> CollectAndReset( const MetricAttributes &pointAttributes) noexcept = 0; - static nostd::shared_ptr GetSimpleFilteredExemplarReservoir( - ExemplarFilterType filter_type, - std::shared_ptr reservoir); - static nostd::shared_ptr GetSimpleFixedSizeExemplarReservoir( size_t size, const std::shared_ptr &reservoir_cell_selector, diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h index 64746ff0f6..2a52a2ba4d 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h @@ -63,7 +63,7 @@ class ReservoirCell */ std::shared_ptr GetAndResetLong(const MetricAttributes &point_attributes) { - if (!context_) + if (!populated_) { return nullptr; } @@ -88,7 +88,7 @@ class ReservoirCell */ std::shared_ptr GetAndResetDouble(const MetricAttributes &point_attributes) { - if (!context_) + if (!populated_) { return nullptr; } @@ -109,6 +109,7 @@ class ReservoirCell { value_ = 0.0; record_time_ = opentelemetry::common::SystemTimestamp{}; + populated_ = false; } private: @@ -134,15 +135,13 @@ class ReservoirCell { attributes_ = attributes; record_time_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); - const auto current_ctx = opentelemetry::trace::GetSpanContext(context); - if (current_ctx.IsValid()) - { - context_.reset(new opentelemetry::trace::SpanContext{current_ctx}); - } + context_ = opentelemetry::trace::GetSpanContext(context); + populated_ = true; } // Cell stores either long or double values, but must not store both - std::shared_ptr context_; + bool populated_ = false; + opentelemetry::trace::SpanContext context_ = opentelemetry::trace::SpanContext::GetInvalid(); nostd::variant value_; opentelemetry::common::SystemTimestamp record_time_; MetricAttributes attributes_; diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h index f820eddc25..26d47ff388 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h @@ -10,6 +10,8 @@ # include "opentelemetry/common/macros.h" # include "opentelemetry/sdk/metrics/aggregation/aggregation_config.h" # include "opentelemetry/sdk/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir.h" +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" +# include "opentelemetry/sdk/metrics/exemplar/reservoir.h" # include "opentelemetry/sdk/metrics/exemplar/simple_fixed_size_exemplar_reservoir.h" # include "opentelemetry/version.h" @@ -48,8 +50,14 @@ static inline size_t GetSimpleFixedReservoirDefaultSize(const AggregationType ag static inline nostd::shared_ptr GetExemplarReservoir( const AggregationType agg_type, const AggregationConfig *agg_config, - const InstrumentDescriptor &instrument_descriptor) + const InstrumentDescriptor &instrument_descriptor, + ExemplarFilterType filter_type) { + if (filter_type == ExemplarFilterType::kAlwaysOff) + { + return ExemplarReservoir::GetNoExemplarReservoir(); + } + if (agg_type == AggregationType::kHistogram) { const auto *histogram_agg_config = static_cast(agg_config); @@ -61,18 +69,18 @@ static inline nostd::shared_ptr GetExemplarReservoir( // if (histogram_agg_config != nullptr && histogram_agg_config->boundaries_.size() > 1) { - return nostd::shared_ptr(new AlignedHistogramBucketExemplarReservoir( + return ExemplarReservoir::GetAlignedHistogramBucketExemplarReservoir( histogram_agg_config->boundaries_.size(), AlignedHistogramBucketExemplarReservoir::GetHistogramCellSelector( histogram_agg_config->boundaries_), - GetMapAndResetCellMethod(instrument_descriptor))); + GetMapAndResetCellMethod(instrument_descriptor)); } } - return nostd::shared_ptr(new SimpleFixedSizeExemplarReservoir( + return ExemplarReservoir::GetSimpleFixedSizeExemplarReservoir( GetSimpleFixedReservoirDefaultSize(agg_type, agg_config), SimpleFixedSizeExemplarReservoir::GetSimpleFixedSizeCellSelector(), - GetMapAndResetCellMethod(instrument_descriptor))); + GetMapAndResetCellMethod(instrument_descriptor)); } } // namespace metrics } // namespace sdk diff --git a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h index a3f56ef64d..674863428b 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h @@ -13,6 +13,7 @@ #include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_predicate.h" # include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -37,7 +38,7 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora AsyncMetricStorage(const InstrumentDescriptor &instrument_descriptor, const AggregationType aggregation_type, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType exempler_filter_type, + ExemplarFilterType exemplar_filter_type, nostd::shared_ptr &&exemplar_reservoir, #endif const AggregationConfig *aggregation_config) @@ -49,7 +50,7 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora delta_hash_map_( std::make_unique(aggregation_config_->cardinality_limit_)), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_filter_type_(exempler_filter_type), + exemplar_filter_type_(exemplar_filter_type), exemplar_reservoir_(std::move(exemplar_reservoir)), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) @@ -63,13 +64,16 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora // exporter/reader can request either for delta or cumulative value. // So we convert the async counter value to delta before passing it to temporal storage. std::lock_guard guard(hashmap_lock_); +#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW + const bool offer_exemplars = + ExemplarFilterEnabled(exemplar_filter_type_, opentelemetry::context::Context{}); +#endif for (auto &measurement : measurements) { #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (exemplar_filter_type_ == ExemplarFilterType::kAlwaysOn) + if (offer_exemplars) { - exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}, - std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(measurement.second, measurement.first, {}); } #endif diff --git a/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h b/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h index be94f926e2..c8d58bb7b2 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h @@ -36,6 +36,7 @@ #endif #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_predicate.h" # include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -48,25 +49,12 @@ namespace metrics class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage { -#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - - static inline bool EnableExamplarFilter(ExemplarFilterType filter_type, - const opentelemetry::context::Context &context) - { - return filter_type == ExemplarFilterType::kAlwaysOn || - (filter_type == ExemplarFilterType::kTraceBased && - opentelemetry::trace::GetSpan(context)->GetContext().IsValid() && - opentelemetry::trace::GetSpan(context)->GetContext().IsSampled()); - } - -#endif // ENABLE_METRICS_EXEMPLAR_PREVIEW - public: SyncMetricStorage(const InstrumentDescriptor &instrument_descriptor, const AggregationType aggregation_type, std::shared_ptr attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType exempler_filter_type, + ExemplarFilterType exemplar_filter_type, nostd::shared_ptr &&exemplar_reservoir, #endif const AggregationConfig *aggregation_config) @@ -76,7 +64,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage std::make_unique(aggregation_config_->cardinality_limit_)), attributes_processor_(std::move(attributes_processor)), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_filter_type_(exempler_filter_type), + exemplar_filter_type_(exemplar_filter_type), exemplar_reservoir_(std::move(exemplar_reservoir)), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) @@ -97,9 +85,9 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) { - exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, {}, context); } #endif static MetricAttributes attr = MetricAttributes{}; @@ -123,10 +111,9 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) { - exemplar_reservoir_->OfferMeasurement(value, attributes, context, - std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, attributes, context); } #endif @@ -155,9 +142,9 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) { - exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, {}, context); } #endif static MetricAttributes attr = MetricAttributes{}; @@ -181,10 +168,9 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) { - exemplar_reservoir_->OfferMeasurement(value, attributes, context, - std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, attributes, context); } #endif MetricAttributes attr{attributes, attributes_processor_.get()}; diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index 3daf0b4017..0abd75265e 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -546,7 +546,7 @@ std::unique_ptr Meter::RegisterSyncMetricStorage( #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_filter_type, GetExemplarReservoir(view.GetAggregationType(), view.GetAggregationConfig(), - view_instr_desc), + view_instr_desc, exemplar_filter_type), #endif view.GetAggregationConfig())); storage_registry_.insert({view_instr_desc, sync_storage}); @@ -619,7 +619,7 @@ std::unique_ptr Meter::RegisterAsyncMetricStorage( #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_filter_type, GetExemplarReservoir(view.GetAggregationType(), view.GetAggregationConfig(), - view_instr_desc), + view_instr_desc, exemplar_filter_type), #endif view.GetAggregationConfig())); storage_registry_.insert({view_instr_desc, async_storage}); diff --git a/sdk/test/metrics/exemplar/BUILD b/sdk/test/metrics/exemplar/BUILD index 9b11a64b9c..2dbfd39f8d 100644 --- a/sdk/test/metrics/exemplar/BUILD +++ b/sdk/test/metrics/exemplar/BUILD @@ -53,3 +53,20 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "filter_predicate_test", + srcs = [ + "filter_predicate_test.cc", + ], + tags = [ + "metrics", + "test", + ], + deps = [ + "//api", + "//sdk:headers", + "//sdk/src/metrics", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/metrics/exemplar/CMakeLists.txt b/sdk/test/metrics/exemplar/CMakeLists.txt index 04a715b2f8..2dfb891ee2 100644 --- a/sdk/test/metrics/exemplar/CMakeLists.txt +++ b/sdk/test/metrics/exemplar/CMakeLists.txt @@ -1,9 +1,10 @@ # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 -foreach(testname - no_exemplar_reservoir_test - aligned_histogram_bucket_exemplar_reservoir_test reservoir_cell_test) +foreach( + testname + no_exemplar_reservoir_test aligned_histogram_bucket_exemplar_reservoir_test + reservoir_cell_test filter_predicate_test) add_executable(${testname} "${testname}.cc") target_link_libraries( ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} diff --git a/sdk/test/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir_test.cc index 49e6247d14..32402bcfd5 100644 --- a/sdk/test/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir_test.cc +++ b/sdk/test/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir_test.cc @@ -4,13 +4,11 @@ #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW # include -# include -# include +# include # include # include # include -# include "opentelemetry/common/timestamp.h" # include "opentelemetry/context/context.h" # include "opentelemetry/sdk/metrics/data/exemplar_data.h" # include "opentelemetry/sdk/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir.h" @@ -37,11 +35,10 @@ TEST_F(AlignedHistogramBucketExemplarReservoirTestPeer, OfferMeasurement) auto histogram_exemplar_reservoir = ExemplarReservoir::GetAlignedHistogramBucketExemplarReservoir( boundaries.size(), AlignedHistogramBucketExemplarReservoir::GetHistogramCellSelector(boundaries), nullptr); - histogram_exemplar_reservoir->OfferMeasurement( - 1.0, MetricAttributes{}, opentelemetry::context::Context{}, std::chrono::system_clock::now()); + histogram_exemplar_reservoir->OfferMeasurement(1.0, MetricAttributes{}, + opentelemetry::context::Context{}); histogram_exemplar_reservoir->OfferMeasurement(static_cast(1), MetricAttributes{}, - opentelemetry::context::Context{}, - std::chrono::system_clock::now()); + opentelemetry::context::Context{}); auto exemplar_data = histogram_exemplar_reservoir->CollectAndReset(MetricAttributes{}); ASSERT_TRUE(exemplar_data.empty()); } @@ -53,11 +50,10 @@ TEST_F(AlignedHistogramBucketExemplarReservoirTestPeer, OfferMeasurementWithNonE boundaries.size(), AlignedHistogramBucketExemplarReservoir::GetHistogramCellSelector(boundaries), &ReservoirCell::GetAndResetDouble); - histogram_exemplar_reservoir->OfferMeasurement( - 1.0, MetricAttributes{}, opentelemetry::context::Context{}, std::chrono::system_clock::now()); + histogram_exemplar_reservoir->OfferMeasurement(1.0, MetricAttributes{}, + opentelemetry::context::Context{}); histogram_exemplar_reservoir->OfferMeasurement(static_cast(1), MetricAttributes{}, - opentelemetry::context::Context{}, - std::chrono::system_clock::now()); + opentelemetry::context::Context{}); auto exemplar_data = histogram_exemplar_reservoir->CollectAndReset(MetricAttributes{}); ASSERT_TRUE(!exemplar_data.empty()); } diff --git a/sdk/test/metrics/exemplar/always_sample_filter_test.cc b/sdk/test/metrics/exemplar/always_sample_filter_test.cc deleted file mode 100644 index f78cd412bd..0000000000 --- a/sdk/test/metrics/exemplar/always_sample_filter_test.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -#include - -#include "opentelemetry/context/context.h" -#include "opentelemetry/sdk/metrics/exemplar/filter.h" - -using namespace opentelemetry::sdk::metrics; - -TEST(AlwaysSampleFilter, SampleMeasurement) -{ - auto filter = opentelemetry::sdk::metrics::ExemplarFilter::GetAlwaysSampleFilter(); - ASSERT_TRUE( - filter->ShouldSampleMeasurement(1.0, MetricAttributes{}, opentelemetry::context::Context{})); - ASSERT_TRUE(filter->ShouldSampleMeasurement(static_cast(1), MetricAttributes{}, - opentelemetry::context::Context{})); -} diff --git a/sdk/test/metrics/exemplar/filter_predicate_test.cc b/sdk/test/metrics/exemplar/filter_predicate_test.cc new file mode 100644 index 0000000000..6001bf0254 --- /dev/null +++ b/sdk/test/metrics/exemplar/filter_predicate_test.cc @@ -0,0 +1,67 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW + +# include +# include +# include + +# include "opentelemetry/context/context.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/nostd/span.h" +# include "opentelemetry/sdk/metrics/exemplar/filter_predicate.h" +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" +# include "opentelemetry/trace/context.h" +# include "opentelemetry/trace/default_span.h" +# include "opentelemetry/trace/span.h" +# include "opentelemetry/trace/span_context.h" +# include "opentelemetry/trace/span_id.h" +# include "opentelemetry/trace/trace_flags.h" +# include "opentelemetry/trace/trace_id.h" + +namespace +{ +namespace metrics_sdk = opentelemetry::sdk::metrics; +namespace trace_api = opentelemetry::trace; +namespace context_api = opentelemetry::context; +namespace nostd = opentelemetry::nostd; + +context_api::Context ContextWithSpan(bool sampled) +{ + const uint8_t trace_id_bytes[trace_api::TraceId::kSize] = {1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16}; + const uint8_t span_id_bytes[trace_api::SpanId::kSize] = {1, 2, 3, 4, 5, 6, 7, 8}; + trace_api::SpanContext span_context( + trace_api::TraceId(trace_id_bytes), trace_api::SpanId(span_id_bytes), + sampled ? trace_api::TraceFlags(trace_api::TraceFlags::kIsSampled) : trace_api::TraceFlags(), + false); + nostd::shared_ptr span(new trace_api::DefaultSpan(span_context)); + context_api::Context context; + return trace_api::SetSpan(context, span); +} +} // namespace + +TEST(ExemplarFilterEnabled, AlwaysOnIsEligibleWithoutASpan) +{ + EXPECT_TRUE(metrics_sdk::ExemplarFilterEnabled(metrics_sdk::ExemplarFilterType::kAlwaysOn, + context_api::Context{})); +} + +TEST(ExemplarFilterEnabled, AlwaysOffIsNeverEligible) +{ + EXPECT_FALSE(metrics_sdk::ExemplarFilterEnabled(metrics_sdk::ExemplarFilterType::kAlwaysOff, + ContextWithSpan(true))); +} + +TEST(ExemplarFilterEnabled, TraceBasedRequiresSampledSpan) +{ + EXPECT_TRUE(metrics_sdk::ExemplarFilterEnabled(metrics_sdk::ExemplarFilterType::kTraceBased, + ContextWithSpan(true))); + EXPECT_FALSE(metrics_sdk::ExemplarFilterEnabled(metrics_sdk::ExemplarFilterType::kTraceBased, + ContextWithSpan(false))); + EXPECT_FALSE(metrics_sdk::ExemplarFilterEnabled(metrics_sdk::ExemplarFilterType::kTraceBased, + context_api::Context{})); +} + +#endif // ENABLE_METRICS_EXEMPLAR_PREVIEW diff --git a/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc index f776c5bdf7..cb8b602212 100644 --- a/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc +++ b/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc @@ -4,13 +4,11 @@ #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW # include -# include -# include +# include # include # include # include -# include "opentelemetry/common/timestamp.h" # include "opentelemetry/context/context.h" # include "opentelemetry/sdk/metrics/data/exemplar_data.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" @@ -20,10 +18,9 @@ using namespace opentelemetry::sdk::metrics; TEST(NoExemplarReservoir, OfferMeasurement) { auto reservoir = opentelemetry::sdk::metrics::ExemplarReservoir::GetNoExemplarReservoir(); - reservoir->OfferMeasurement(1.0, MetricAttributes{}, opentelemetry::context::Context{}, - std::chrono::system_clock::now()); + reservoir->OfferMeasurement(1.0, MetricAttributes{}, opentelemetry::context::Context{}); reservoir->OfferMeasurement(static_cast(1), MetricAttributes{}, - opentelemetry::context::Context{}, std::chrono::system_clock::now()); + opentelemetry::context::Context{}); auto exemplar_data = reservoir->CollectAndReset(MetricAttributes{}); ASSERT_TRUE(exemplar_data.empty()); } diff --git a/sdk/test/metrics/exemplar/reservoir_cell_test.cc b/sdk/test/metrics/exemplar/reservoir_cell_test.cc index 6d0990ccca..5bd0194835 100644 --- a/sdk/test/metrics/exemplar/reservoir_cell_test.cc +++ b/sdk/test/metrics/exemplar/reservoir_cell_test.cc @@ -14,6 +14,7 @@ # include "opentelemetry/nostd/variant.h" # include "opentelemetry/sdk/metrics/data/exemplar_data.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir_cell.h" +# include "opentelemetry/trace/span_context.h" # include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -74,6 +75,25 @@ TEST_F(ReservoirCellTestPeer, GetAndReset) ASSERT_TRUE(long_data == nullptr); } +TEST_F(ReservoirCellTestPeer, ProducesExemplarWithoutSpanContext) +{ + opentelemetry::sdk::metrics::ReservoirCell reservoir_cell; + reservoir_cell.RecordLongMeasurement(static_cast(42), MetricAttributes{}, + opentelemetry::context::Context{}); + auto data = reservoir_cell.GetAndResetLong(MetricAttributes{}); + ASSERT_NE(data, nullptr); + EXPECT_FALSE(data->GetSpanContext().IsValid()); +} + +TEST_F(ReservoirCellTestPeer, GetAndResetClearsCell) +{ + opentelemetry::sdk::metrics::ReservoirCell reservoir_cell; + reservoir_cell.RecordLongMeasurement(static_cast(42), MetricAttributes{}, + opentelemetry::context::Context{}); + ASSERT_NE(reservoir_cell.GetAndResetLong(MetricAttributes{}), nullptr); + EXPECT_EQ(reservoir_cell.GetAndResetLong(MetricAttributes{}), nullptr); +} + TEST_F(ReservoirCellTestPeer, Filtered) { FilteredTest(); diff --git a/sdk/test/metrics/exemplar/with_trace_sample_filter_test.cc b/sdk/test/metrics/exemplar/with_trace_sample_filter_test.cc deleted file mode 100644 index fcf9d6344e..0000000000 --- a/sdk/test/metrics/exemplar/with_trace_sample_filter_test.cc +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -#include -#include "opentelemetry/context/context.h" -#include "opentelemetry/sdk/metrics/exemplar/filter.h" - -using namespace opentelemetry::sdk::metrics; - -TEST(WithTraceSampleFilter, SampleMeasurement) -{ - auto filter = opentelemetry::sdk::metrics::ExemplarFilter::GetWithTraceSampleFilter(); - ASSERT_FALSE( - filter->ShouldSampleMeasurement(1.0, MetricAttributes{}, opentelemetry::context::Context{})); - ASSERT_FALSE(filter->ShouldSampleMeasurement(static_cast(1), MetricAttributes{}, - opentelemetry::context::Context{})); -}