From 21c3ab6b2ef5eb7e6127c77546c208c7625f0b29 Mon Sep 17 00:00:00 2001 From: proost Date: Sat, 18 Jul 2026 14:23:16 +0900 Subject: [PATCH 01/13] feat: examplar filters --- .../exemplar/filtered_exemplar_reservoir.h | 111 ++++++++++++++++++ .../sdk/metrics/exemplar/reservoir.h | 2 +- .../sdk/metrics/exemplar/reservoir_utils.h | 26 ++-- .../sdk/metrics/state/async_metric_storage.h | 11 +- .../sdk/metrics/state/sync_metric_storage.h | 41 +------ sdk/src/metrics/exemplar/reservoir.cc | 11 ++ sdk/src/metrics/meter.cc | 6 +- sdk/test/metrics/async_metric_storage_test.cc | 7 +- .../metrics/bound_sync_instruments_test.cc | 53 ++++----- sdk/test/metrics/cardinality_limit_test.cc | 2 - sdk/test/metrics/exemplar/BUILD | 17 +++ sdk/test/metrics/exemplar/CMakeLists.txt | 7 +- .../exemplar/always_sample_filter_test.cc | 18 --- .../filtered_exemplar_reservoir_test.cc | 108 +++++++++++++++++ .../exemplar/with_trace_sample_filter_test.cc | 17 --- .../sync_metric_storage_counter_test.cc | 11 +- .../metrics/sync_metric_storage_gauge_test.cc | 9 +- .../sync_metric_storage_histogram_test.cc | 7 +- ...ync_metric_storage_up_down_counter_test.cc | 5 +- 19 files changed, 319 insertions(+), 150 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h delete mode 100644 sdk/test/metrics/exemplar/always_sample_filter_test.cc create mode 100644 sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc delete mode 100644 sdk/test/metrics/exemplar/with_trace_sample_filter_test.cc diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h new file mode 100644 index 0000000000..179cf7d533 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h @@ -0,0 +1,111 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW + +# include +# include +# include +# include + +# include "opentelemetry/common/timestamp.h" +# include "opentelemetry/context/context.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/sdk/metrics/data/exemplar_data.h" +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" +# include "opentelemetry/sdk/metrics/exemplar/reservoir.h" +# include "opentelemetry/trace/context.h" +# include "opentelemetry/trace/span_context.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace metrics +{ + +/** + * A reservoir that pre-filters measurements according to an ExemplarFilterType before + * delegating eligible ones to a wrapped reservoir. + */ +class FilteredExemplarReservoir final : public ExemplarReservoir +{ +public: + FilteredExemplarReservoir(ExemplarFilterType filter_type, + nostd::shared_ptr reservoir) + : should_sample_(SelectFilter(filter_type)), reservoir_(std::move(reservoir)) + {} + + void OfferMeasurement(int64_t value, + const MetricAttributes &attributes, + const opentelemetry::context::Context &context, + const opentelemetry::common::SystemTimestamp ×tamp) noexcept override + { + if (should_sample_(context)) + { + reservoir_->OfferMeasurement(value, attributes, context, timestamp); + } + } + + void OfferMeasurement(double value, + const MetricAttributes &attributes, + const opentelemetry::context::Context &context, + const opentelemetry::common::SystemTimestamp ×tamp) noexcept override + { + if (should_sample_(context)) + { + reservoir_->OfferMeasurement(value, attributes, context, timestamp); + } + } + + std::vector> CollectAndReset( + const MetricAttributes &pointAttributes) noexcept override + { + return reservoir_->CollectAndReset(pointAttributes); + } + +private: + using ShouldSampleFn = bool (*)(const opentelemetry::context::Context &context); + + static bool AlwaysOn(const opentelemetry::context::Context & /* context */) noexcept + { + return true; + } + + static bool AlwaysOff(const opentelemetry::context::Context & /* context */) noexcept + { + return false; + } + + static bool TraceBased(const opentelemetry::context::Context &context) noexcept + { + const opentelemetry::trace::SpanContext span_context = + opentelemetry::trace::GetSpanContext(context); + return span_context.IsValid() && span_context.IsSampled(); + } + + static ShouldSampleFn SelectFilter(ExemplarFilterType filter_type) noexcept + { + switch (filter_type) + { + case ExemplarFilterType::kAlwaysOn: + return &AlwaysOn; + case ExemplarFilterType::kAlwaysOff: + return &AlwaysOff; + case ExemplarFilterType::kTraceBased: + return &TraceBased; + } + return &TraceBased; // unreachable; all enumerators handled above + } + + ShouldSampleFn should_sample_; + nostd::shared_ptr reservoir_; +}; + +} // namespace metrics +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE + +#endif // ENABLE_METRICS_EXEMPLAR_PREVIEW diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h index efbd20abc4..19ad5551e6 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h @@ -75,7 +75,7 @@ class ExemplarReservoir static nostd::shared_ptr GetSimpleFilteredExemplarReservoir( ExemplarFilterType filter_type, - std::shared_ptr reservoir); + nostd::shared_ptr reservoir); static nostd::shared_ptr GetSimpleFixedSizeExemplarReservoir( size_t size, diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h index 6ca88411af..e8e2970e89 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" @@ -49,7 +51,8 @@ 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 (agg_type == AggregationType::kHistogram) { @@ -62,18 +65,21 @@ static inline nostd::shared_ptr GetExemplarReservoir( // if (histogram_agg_config != nullptr && histogram_agg_config->boundaries_.size() > 1) { - return nostd::shared_ptr(new AlignedHistogramBucketExemplarReservoir( - histogram_agg_config->boundaries_.size(), - AlignedHistogramBucketExemplarReservoir::GetHistogramCellSelector( - histogram_agg_config->boundaries_), - GetMapAndResetCellMethod(instrument_descriptor))); + return ExemplarReservoir::GetSimpleFilteredExemplarReservoir( + filter_type, + nostd::shared_ptr(new AlignedHistogramBucketExemplarReservoir( + histogram_agg_config->boundaries_.size(), + AlignedHistogramBucketExemplarReservoir::GetHistogramCellSelector( + histogram_agg_config->boundaries_), + GetMapAndResetCellMethod(instrument_descriptor)))); } } - return nostd::shared_ptr(new SimpleFixedSizeExemplarReservoir( - GetSimpleFixedReservoirDefaultSize(agg_type, agg_config), - SimpleFixedSizeExemplarReservoir::GetSimpleFixedSizeCellSelector(), - GetMapAndResetCellMethod(instrument_descriptor))); + return ExemplarReservoir::GetSimpleFilteredExemplarReservoir( + filter_type, nostd::shared_ptr(new SimpleFixedSizeExemplarReservoir( + GetSimpleFixedReservoirDefaultSize(agg_type, agg_config), + SimpleFixedSizeExemplarReservoir::GetSimpleFixedSizeCellSelector(), + 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..017d802578 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h @@ -13,7 +13,6 @@ #include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -37,7 +36,6 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora AsyncMetricStorage(const InstrumentDescriptor &instrument_descriptor, const AggregationType aggregation_type, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType exempler_filter_type, nostd::shared_ptr &&exemplar_reservoir, #endif const AggregationConfig *aggregation_config) @@ -49,7 +47,6 @@ 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_reservoir_(std::move(exemplar_reservoir)), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) @@ -66,11 +63,8 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora for (auto &measurement : measurements) { #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (exemplar_filter_type_ == ExemplarFilterType::kAlwaysOn) - { - exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}, - std::chrono::system_clock::now()); - } + exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}, + std::chrono::system_clock::now()); #endif auto aggr = DefaultAggregation::CreateAggregation(aggregation_type_, instrument_descriptor_); @@ -146,7 +140,6 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora std::unique_ptr delta_hash_map_; opentelemetry::common::SpinLockMutex hashmap_lock_; #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType exemplar_filter_type_; nostd::shared_ptr exemplar_reservoir_; #endif TemporalMetricStorage temporal_metric_storage_; 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 e9aaebe6f5..a3aa7b8d13 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h @@ -36,7 +36,6 @@ #endif #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -48,25 +47,11 @@ 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, nostd::shared_ptr &&exemplar_reservoir, #endif const AggregationConfig *aggregation_config) @@ -76,7 +61,6 @@ 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_reservoir_(std::move(exemplar_reservoir)), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) @@ -97,10 +81,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) - { - exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); - } + exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); #endif static MetricAttributes attr = MetricAttributes{}; std::lock_guard guard(attribute_hashmap_lock_); @@ -123,11 +104,8 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) - { - exemplar_reservoir_->OfferMeasurement(value, attributes, context, - std::chrono::system_clock::now()); - } + exemplar_reservoir_->OfferMeasurement(value, attributes, context, + std::chrono::system_clock::now()); #endif MetricAttributes attr{attributes, attributes_processor_.get()}; @@ -155,10 +133,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) - { - exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); - } + exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); #endif static MetricAttributes attr = MetricAttributes{}; std::lock_guard guard(attribute_hashmap_lock_); @@ -181,11 +156,8 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - if (EnableExamplarFilter(exemplar_filter_type_, context)) - { - exemplar_reservoir_->OfferMeasurement(value, attributes, context, - std::chrono::system_clock::now()); - } + exemplar_reservoir_->OfferMeasurement(value, attributes, context, + std::chrono::system_clock::now()); #endif MetricAttributes attr{attributes, attributes_processor_.get()}; std::lock_guard guard(attribute_hashmap_lock_); @@ -296,7 +268,6 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage std::function()> create_default_aggregation_; std::shared_ptr attributes_processor_; #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType exemplar_filter_type_; nostd::shared_ptr exemplar_reservoir_; #endif TemporalMetricStorage temporal_metric_storage_; diff --git a/sdk/src/metrics/exemplar/reservoir.cc b/sdk/src/metrics/exemplar/reservoir.cc index f5fe4064b6..71e46ba298 100644 --- a/sdk/src/metrics/exemplar/reservoir.cc +++ b/sdk/src/metrics/exemplar/reservoir.cc @@ -4,9 +4,12 @@ #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW # include +# include # include "opentelemetry/nostd/shared_ptr.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/filtered_exemplar_reservoir.h" # include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir_cell.h" @@ -20,6 +23,14 @@ namespace sdk namespace metrics { +nostd::shared_ptr ExemplarReservoir::GetSimpleFilteredExemplarReservoir( + ExemplarFilterType filter_type, + nostd::shared_ptr reservoir) +{ + return nostd::shared_ptr{ + new FilteredExemplarReservoir{filter_type, std::move(reservoir)}}; +} + nostd::shared_ptr ExemplarReservoir::GetSimpleFixedSizeExemplarReservoir( size_t size, const std::shared_ptr &reservoir_cell_selector, diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index 4a4c2f6b68..8acab9f3dd 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -545,9 +545,8 @@ std::unique_ptr Meter::RegisterSyncMetricStorage( sync_storage = std::shared_ptr(new SyncMetricStorage( view_instr_desc, view.GetAggregationType(), view.GetAttributesProcessor(), #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}); @@ -618,9 +617,8 @@ std::unique_ptr Meter::RegisterAsyncMetricStorage( async_storage = std::shared_ptr(new AsyncMetricStorage( view_instr_desc, view.GetAggregationType(), #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/async_metric_storage_test.cc b/sdk/test/metrics/async_metric_storage_test.cc index 4de1a95c4f..3987770420 100644 --- a/sdk/test/metrics/async_metric_storage_test.cc +++ b/sdk/test/metrics/async_metric_storage_test.cc @@ -28,7 +28,6 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -66,7 +65,7 @@ TEST_P(WritableMetricStorageTestFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kSum, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); int64_t get_count1 = 20; @@ -161,7 +160,7 @@ TEST_P(WritableMetricStorageTestUpDownFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kDefault, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); int64_t get_count1 = 20; @@ -257,7 +256,7 @@ TEST_P(WritableMetricStorageTestObservableGaugeFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kLastValue, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); int64_t freq_cpu0 = 3; diff --git a/sdk/test/metrics/bound_sync_instruments_test.cc b/sdk/test/metrics/bound_sync_instruments_test.cc index 756030437e..6b289c6aa4 100644 --- a/sdk/test/metrics/bound_sync_instruments_test.cc +++ b/sdk/test/metrics/bound_sync_instruments_test.cc @@ -40,7 +40,6 @@ # include "opentelemetry/sdk/metrics/view/attributes_processor.h" # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" # endif @@ -75,7 +74,6 @@ class StorageHolder } storage_ = std::make_shared(desc, agg_type, proc_, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif cfg_); @@ -186,12 +184,12 @@ TEST(BoundSyncInstruments, BoundCounterBindInitializerList) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); AggregationConfig cfg; - std::unique_ptr storage(new SyncMetricStorage( - desc, AggregationType::kSum, proc, + std::unique_ptr storage( + new SyncMetricStorage(desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongCounter counter(desc, std::move(storage)); opentelemetry::metrics::Counter &api_counter = counter; @@ -238,12 +236,12 @@ TEST(BoundSyncInstruments, UnboundCounterDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); AggregationConfig cfg; - std::unique_ptr storage(new SyncMetricStorage( - desc, AggregationType::kSum, proc, + std::unique_ptr storage( + new SyncMetricStorage(desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongCounter counter(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -261,12 +259,12 @@ TEST(BoundSyncInstruments, BoundCounterDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); AggregationConfig cfg; - std::unique_ptr storage(new SyncMetricStorage( - desc, AggregationType::kSum, proc, + std::unique_ptr storage( + new SyncMetricStorage(desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongCounter counter(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -315,12 +313,12 @@ TEST(BoundSyncInstruments, UnboundHistogramDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); HistogramAggregationConfig cfg; - std::unique_ptr storage(new SyncMetricStorage( - desc, AggregationType::kHistogram, proc, + std::unique_ptr storage( + new SyncMetricStorage(desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongHistogram histogram(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -354,12 +352,12 @@ TEST(BoundSyncInstruments, BoundHistogramDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); HistogramAggregationConfig cfg; - std::unique_ptr storage(new SyncMetricStorage( - desc, AggregationType::kHistogram, proc, + std::unique_ptr storage( + new SyncMetricStorage(desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongHistogram histogram(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -394,12 +392,12 @@ TEST(BoundSyncInstruments, BoundHistogramBindInitializerList) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); HistogramAggregationConfig cfg; - std::unique_ptr storage(new SyncMetricStorage( - desc, AggregationType::kHistogram, proc, + std::unique_ptr storage( + new SyncMetricStorage(desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongHistogram histogram(desc, std::move(storage)); opentelemetry::metrics::Histogram &api_histogram = histogram; @@ -436,7 +434,6 @@ TEST(BoundSyncInstruments, BoundCounterRespectsDropAggregation) AggregationConfig cfg; SyncMetricStorage storage(desc, AggregationType::kDrop, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg); @@ -472,7 +469,6 @@ TEST(BoundSyncInstruments, BoundCounterRespectsLastValueAggregation) AggregationConfig cfg; SyncMetricStorage storage(desc, AggregationType::kLastValue, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg); @@ -511,7 +507,6 @@ TEST(BoundSyncInstruments, BoundHistogramRespectsCustomBuckets) cfg.boundaries_ = {10.0, 20.0}; SyncMetricStorage storage(desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg); diff --git a/sdk/test/metrics/cardinality_limit_test.cc b/sdk/test/metrics/cardinality_limit_test.cc index cb7dc9b8a0..cd38641a79 100644 --- a/sdk/test/metrics/cardinality_limit_test.cc +++ b/sdk/test/metrics/cardinality_limit_test.cc @@ -32,7 +32,6 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -120,7 +119,6 @@ TEST_P(WritableMetricStorageCardinalityLimitTestFixture, LongCounterSumAggregati new DefaultAttributesProcessor{}}; SyncMetricStorage storage(instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif &aggConfig); diff --git a/sdk/test/metrics/exemplar/BUILD b/sdk/test/metrics/exemplar/BUILD index 9b11a64b9c..10973fd000 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 = "filtered_exemplar_reservoir_test", + srcs = [ + "filtered_exemplar_reservoir_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..32f755e747 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 filtered_exemplar_reservoir_test) add_executable(${testname} "${testname}.cc") target_link_libraries( ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} 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/filtered_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc new file mode 100644 index 0000000000..b839121539 --- /dev/null +++ b/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc @@ -0,0 +1,108 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW + +# include +# include +# include +# include +# include + +# include "opentelemetry/common/timestamp.h" +# include "opentelemetry/context/context.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/nostd/span.h" +# include "opentelemetry/sdk/metrics/data/exemplar_data.h" +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" +# include "opentelemetry/sdk/metrics/exemplar/reservoir.h" +# include "opentelemetry/sdk/metrics/exemplar/reservoir_cell.h" +# include "opentelemetry/sdk/metrics/exemplar/simple_fixed_size_exemplar_reservoir.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; + +nostd::shared_ptr MakeFiltered( + metrics_sdk::ExemplarFilterType filter_type, + metrics_sdk::MapAndResetCellType map_and_reset = &metrics_sdk::ReservoirCell::GetAndResetDouble) +{ + auto inner = metrics_sdk::ExemplarReservoir::GetSimpleFixedSizeExemplarReservoir( + 1, metrics_sdk::SimpleFixedSizeExemplarReservoir::GetSimpleFixedSizeCellSelector(), + map_and_reset); + return metrics_sdk::ExemplarReservoir::GetSimpleFilteredExemplarReservoir(filter_type, inner); +} + +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); +} + +bool OffersDouble(const nostd::shared_ptr &reservoir, + const context_api::Context &context) +{ + reservoir->OfferMeasurement(1.0, metrics_sdk::MetricAttributes{}, context, + std::chrono::system_clock::now()); + return !reservoir->CollectAndReset(metrics_sdk::MetricAttributes{}).empty(); +} +} // namespace + +TEST(FilteredExemplarReservoir, AlwaysOnOffersMeasurement) +{ + EXPECT_TRUE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kAlwaysOn), + context_api::Context{})); +} + +TEST(FilteredExemplarReservoir, AlwaysOnOffersLongMeasurement) +{ + auto reservoir = MakeFiltered(metrics_sdk::ExemplarFilterType::kAlwaysOn, + &metrics_sdk::ReservoirCell::GetAndResetLong); + reservoir->OfferMeasurement(static_cast(1), metrics_sdk::MetricAttributes{}, + context_api::Context{}, std::chrono::system_clock::now()); + EXPECT_FALSE(reservoir->CollectAndReset(metrics_sdk::MetricAttributes{}).empty()); +} + +TEST(FilteredExemplarReservoir, AlwaysOffDropsMeasurement) +{ + EXPECT_FALSE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kAlwaysOff), + context_api::Context{})); +} + +TEST(FilteredExemplarReservoir, TraceBasedDropsWithoutSpan) +{ + EXPECT_FALSE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kTraceBased), + context_api::Context{})); +} + +TEST(FilteredExemplarReservoir, TraceBasedOffersWithSampledSpan) +{ + EXPECT_TRUE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kTraceBased), + ContextWithSpan(true))); +} + +TEST(FilteredExemplarReservoir, TraceBasedDropsUnsampledSpan) +{ + EXPECT_FALSE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kTraceBased), + ContextWithSpan(false))); +} + +#endif // ENABLE_METRICS_EXEMPLAR_PREVIEW 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{})); -} diff --git a/sdk/test/metrics/sync_metric_storage_counter_test.cc b/sdk/test/metrics/sync_metric_storage_counter_test.cc index 89e8df46ff..f31599a8af 100644 --- a/sdk/test/metrics/sync_metric_storage_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_counter_test.cc @@ -27,7 +27,6 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -53,7 +52,7 @@ TEST_P(WritableMetricStorageTestFixture, LongCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -193,7 +192,7 @@ TEST_P(WritableMetricStorageTestFixture, DoubleCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -329,7 +328,7 @@ TEST(SyncMetricStorageTest, DeltaCounterStartTimestampTracksEmptyCycles) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -407,7 +406,7 @@ TEST(SyncMetricStorageTest, DeltaCounterFirstIntervalUsesInstrumentCreationTime) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); auto after_creation = std::chrono::system_clock::now(); @@ -460,7 +459,7 @@ TEST(SyncMetricStorageTest, DeltaCounterMultiCollectorFirstIntervalUsesInstrumen opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); auto after_creation = std::chrono::system_clock::now(); diff --git a/sdk/test/metrics/sync_metric_storage_gauge_test.cc b/sdk/test/metrics/sync_metric_storage_gauge_test.cc index 1dc0a4d2cd..2675a9aaf8 100644 --- a/sdk/test/metrics/sync_metric_storage_gauge_test.cc +++ b/sdk/test/metrics/sync_metric_storage_gauge_test.cc @@ -26,7 +26,6 @@ # include "opentelemetry/nostd/variant.h" # include "opentelemetry/sdk/metrics/data/metric_data.h" # include "opentelemetry/sdk/metrics/data/point_data.h" -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" # include "opentelemetry/sdk/metrics/state/metric_collector.h" # include "opentelemetry/sdk/metrics/state/sync_metric_storage.h" @@ -58,7 +57,7 @@ TEST_P(WritableMetricStorageTestFixture, LongGaugeLastValueAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); @@ -142,7 +141,7 @@ TEST_P(WritableMetricStorageTestFixture, DoubleGaugeLastValueAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); @@ -236,7 +235,7 @@ TEST_P(WritableMetricStorageDeltaMultiReaderTestFixture, opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); auto after_creation = std::chrono::system_clock::now(); @@ -417,7 +416,7 @@ TEST_P(WritableMetricStorageDeltaMultiReaderTestFixture, opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); auto after_creation = std::chrono::system_clock::now(); diff --git a/sdk/test/metrics/sync_metric_storage_histogram_test.cc b/sdk/test/metrics/sync_metric_storage_histogram_test.cc index ee3af6e8c4..d363a6413f 100644 --- a/sdk/test/metrics/sync_metric_storage_histogram_test.cc +++ b/sdk/test/metrics/sync_metric_storage_histogram_test.cc @@ -27,7 +27,6 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -57,7 +56,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, LongHistogram) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -198,7 +197,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, DoubleHistogram) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -346,7 +345,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, Base2ExponentialDoubleHistogra opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kBase2ExponentialHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); diff --git a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc index cf54165341..3b36aaa940 100644 --- a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc @@ -26,7 +26,6 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -52,7 +51,7 @@ TEST_P(WritableMetricStorageTestFixture, LongUpDownCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -202,7 +201,7 @@ TEST_P(WritableMetricStorageTestFixture, DoubleUpDownCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); From b13986fbf3bdb4af36f83be38b97ccc8ef3f3fb5 Mon Sep 17 00:00:00 2001 From: proost Date: Sat, 18 Jul 2026 14:23:46 +0900 Subject: [PATCH 02/13] test: using mock --- .../filtered_exemplar_reservoir_test.cc | 77 +++++++++++-------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc index b839121539..22d4616370 100644 --- a/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc +++ b/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc @@ -16,8 +16,6 @@ # include "opentelemetry/sdk/metrics/data/exemplar_data.h" # include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" -# include "opentelemetry/sdk/metrics/exemplar/reservoir_cell.h" -# include "opentelemetry/sdk/metrics/exemplar/simple_fixed_size_exemplar_reservoir.h" # include "opentelemetry/trace/context.h" # include "opentelemetry/trace/default_span.h" # include "opentelemetry/trace/span.h" @@ -33,15 +31,33 @@ namespace trace_api = opentelemetry::trace; namespace context_api = opentelemetry::context; namespace nostd = opentelemetry::nostd; -nostd::shared_ptr MakeFiltered( - metrics_sdk::ExemplarFilterType filter_type, - metrics_sdk::MapAndResetCellType map_and_reset = &metrics_sdk::ReservoirCell::GetAndResetDouble) +class CountingReservoir : public metrics_sdk::ExemplarReservoir { - auto inner = metrics_sdk::ExemplarReservoir::GetSimpleFixedSizeExemplarReservoir( - 1, metrics_sdk::SimpleFixedSizeExemplarReservoir::GetSimpleFixedSizeCellSelector(), - map_and_reset); - return metrics_sdk::ExemplarReservoir::GetSimpleFilteredExemplarReservoir(filter_type, inner); -} +public: + void OfferMeasurement(int64_t, + const metrics_sdk::MetricAttributes &, + const context_api::Context &, + const opentelemetry::common::SystemTimestamp &) noexcept override + { + ++offered; + } + + void OfferMeasurement(double, + const metrics_sdk::MetricAttributes &, + const context_api::Context &, + const opentelemetry::common::SystemTimestamp &) noexcept override + { + ++offered; + } + + std::vector> CollectAndReset( + const metrics_sdk::MetricAttributes &) noexcept override + { + return {}; + } + + int offered = 0; +}; context_api::Context ContextWithSpan(bool sampled) { @@ -57,52 +73,53 @@ context_api::Context ContextWithSpan(bool sampled) return trace_api::SetSpan(context, span); } -bool OffersDouble(const nostd::shared_ptr &reservoir, - const context_api::Context &context) +int ForwardedCount(metrics_sdk::ExemplarFilterType filter_type, const context_api::Context &context) { - reservoir->OfferMeasurement(1.0, metrics_sdk::MetricAttributes{}, context, - std::chrono::system_clock::now()); - return !reservoir->CollectAndReset(metrics_sdk::MetricAttributes{}).empty(); + auto *spy = new CountingReservoir(); + auto filtered = metrics_sdk::ExemplarReservoir::GetSimpleFilteredExemplarReservoir( + filter_type, nostd::shared_ptr(spy)); + filtered->OfferMeasurement(1.0, metrics_sdk::MetricAttributes{}, context, + std::chrono::system_clock::now()); + return spy->offered; } } // namespace TEST(FilteredExemplarReservoir, AlwaysOnOffersMeasurement) { - EXPECT_TRUE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kAlwaysOn), - context_api::Context{})); + EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kAlwaysOn, context_api::Context{}), 1); } TEST(FilteredExemplarReservoir, AlwaysOnOffersLongMeasurement) { - auto reservoir = MakeFiltered(metrics_sdk::ExemplarFilterType::kAlwaysOn, - &metrics_sdk::ReservoirCell::GetAndResetLong); - reservoir->OfferMeasurement(static_cast(1), metrics_sdk::MetricAttributes{}, - context_api::Context{}, std::chrono::system_clock::now()); - EXPECT_FALSE(reservoir->CollectAndReset(metrics_sdk::MetricAttributes{}).empty()); + auto *spy = new CountingReservoir(); + auto filtered = metrics_sdk::ExemplarReservoir::GetSimpleFilteredExemplarReservoir( + metrics_sdk::ExemplarFilterType::kAlwaysOn, + nostd::shared_ptr(spy)); + filtered->OfferMeasurement(static_cast(1), metrics_sdk::MetricAttributes{}, + context_api::Context{}, std::chrono::system_clock::now()); + EXPECT_EQ(spy->offered, 1); } TEST(FilteredExemplarReservoir, AlwaysOffDropsMeasurement) { - EXPECT_FALSE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kAlwaysOff), - context_api::Context{})); + EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kAlwaysOff, context_api::Context{}), 0); } TEST(FilteredExemplarReservoir, TraceBasedDropsWithoutSpan) { - EXPECT_FALSE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kTraceBased), - context_api::Context{})); + EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kTraceBased, context_api::Context{}), + 0); } TEST(FilteredExemplarReservoir, TraceBasedOffersWithSampledSpan) { - EXPECT_TRUE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kTraceBased), - ContextWithSpan(true))); + EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kTraceBased, ContextWithSpan(true)), 1); } TEST(FilteredExemplarReservoir, TraceBasedDropsUnsampledSpan) { - EXPECT_FALSE(OffersDouble(MakeFiltered(metrics_sdk::ExemplarFilterType::kTraceBased), - ContextWithSpan(false))); + EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kTraceBased, ContextWithSpan(false)), + 0); } #endif // ENABLE_METRICS_EXEMPLAR_PREVIEW From 8dc295b22664ddc02462f926a7cff377cd115dcf Mon Sep 17 00:00:00 2001 From: proost Date: Sat, 18 Jul 2026 14:51:41 +0900 Subject: [PATCH 03/13] doc: update change log --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad43a3e6e9..d71a75cf6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ Increment the: ## [Unreleased] +* [SDK] Complete exemplar filtering: the exemplar filter (`AlwaysOn`/`AlwaysOff`/`TraceBased`) + is now applied through a `FilteredExemplarReservoir` decorator instead of an inline check + duplicated across the sync and async metric storage (metrics exemplar preview feature). + [#4267](https://github.com/open-telemetry/opentelemetry-cpp/pull/4267) + * docs: update supported development platforms [#4260](https://github.com/open-telemetry/opentelemetry-cpp/pull/4260) From f99c77b7c519c42fed214f2bc061984d3dcb6f51 Mon Sep 17 00:00:00 2001 From: proost Date: Sat, 18 Jul 2026 14:53:08 +0900 Subject: [PATCH 04/13] style: follow lint --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d71a75cf6f..616b16d776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,8 @@ Increment the: ## [Unreleased] -* [SDK] Complete exemplar filtering: the exemplar filter (`AlwaysOn`/`AlwaysOff`/`TraceBased`) - is now applied through a `FilteredExemplarReservoir` decorator instead of an inline check - duplicated across the sync and async metric storage (metrics exemplar preview feature). +* [SDK] Complete exemplar filtering: the exemplar filter(`AlwaysOn`/ + `AlwaysOff`/`TraceBased`) [#4267](https://github.com/open-telemetry/opentelemetry-cpp/pull/4267) * docs: update supported development platforms From a12d4c3988c6f7ae70afb964e9969b675aaf26b6 Mon Sep 17 00:00:00 2001 From: proost Date: Fri, 24 Jul 2026 23:23:01 +0900 Subject: [PATCH 05/13] ci: higher test timeout --- ci/do_ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index cc825c37f1..287319b4de 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -632,7 +632,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 From ca5c78ef57143f28126cbaf3d48f18328c7fe9fa Mon Sep 17 00:00:00 2001 From: proost Date: Thu, 30 Jul 2026 15:35:21 +0900 Subject: [PATCH 06/13] BREAKING: remove timestamp from OfferMeasurement --- .../exemplar/filtered_exemplar_reservoir.h | 10 ++++------ .../exemplar/fixed_size_exemplar_reservoir.h | 16 ++++++---------- .../sdk/metrics/exemplar/no_exemplar_reservoir.h | 16 ++++++---------- .../sdk/metrics/exemplar/reservoir.h | 16 ++++++---------- .../sdk/metrics/state/async_metric_storage.h | 3 +-- .../sdk/metrics/state/sync_metric_storage.h | 10 ++++------ ...d_histogram_bucket_exemplar_reservoir_test.cc | 16 ++++++---------- .../exemplar/filtered_exemplar_reservoir_test.cc | 13 ++++--------- .../exemplar/no_exemplar_reservoir_test.cc | 7 ++----- 9 files changed, 39 insertions(+), 68 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h index 179cf7d533..648f7190a5 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h @@ -40,23 +40,21 @@ class FilteredExemplarReservoir final : public ExemplarReservoir void OfferMeasurement(int64_t value, const MetricAttributes &attributes, - const opentelemetry::context::Context &context, - const opentelemetry::common::SystemTimestamp ×tamp) noexcept override + const opentelemetry::context::Context &context) noexcept override { if (should_sample_(context)) { - reservoir_->OfferMeasurement(value, attributes, context, timestamp); + reservoir_->OfferMeasurement(value, attributes, context); } } void OfferMeasurement(double value, const MetricAttributes &attributes, - const opentelemetry::context::Context &context, - const opentelemetry::common::SystemTimestamp ×tamp) noexcept override + const opentelemetry::context::Context &context) noexcept override { if (should_sample_(context)) { - reservoir_->OfferMeasurement(value, attributes, context, timestamp); + reservoir_->OfferMeasurement(value, attributes, context); } } 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 f41e78fb59..53cb76747b 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 19ad5551e6..6f8b27ab4e 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h @@ -47,18 +47,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. 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 017d802578..cec8c5ad7e 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h @@ -63,8 +63,7 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora for (auto &measurement : measurements) { #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}, - std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}); #endif auto aggr = DefaultAggregation::CreateAggregation(aggregation_type_, instrument_descriptor_); 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 a3aa7b8d13..f7133c4f97 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h @@ -81,7 +81,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, {}, context); #endif static MetricAttributes attr = MetricAttributes{}; std::lock_guard guard(attribute_hashmap_lock_); @@ -104,8 +104,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, attributes, context, - std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, attributes, context); #endif MetricAttributes attr{attributes, attributes_processor_.get()}; @@ -133,7 +132,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, {}, context); #endif static MetricAttributes attr = MetricAttributes{}; std::lock_guard guard(attribute_hashmap_lock_); @@ -156,8 +155,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, attributes, context, - std::chrono::system_clock::now()); + exemplar_reservoir_->OfferMeasurement(value, attributes, context); #endif MetricAttributes attr{attributes, attributes_processor_.get()}; std::lock_guard guard(attribute_hashmap_lock_); 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 d6effcef3d..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 @@ -5,12 +5,10 @@ # 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/filtered_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc index 22d4616370..5571c22013 100644 --- a/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc +++ b/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc @@ -5,11 +5,9 @@ # include # include -# include # include # include -# include "opentelemetry/common/timestamp.h" # include "opentelemetry/context/context.h" # include "opentelemetry/nostd/shared_ptr.h" # include "opentelemetry/nostd/span.h" @@ -36,16 +34,14 @@ class CountingReservoir : public metrics_sdk::ExemplarReservoir public: void OfferMeasurement(int64_t, const metrics_sdk::MetricAttributes &, - const context_api::Context &, - const opentelemetry::common::SystemTimestamp &) noexcept override + const context_api::Context &) noexcept override { ++offered; } void OfferMeasurement(double, const metrics_sdk::MetricAttributes &, - const context_api::Context &, - const opentelemetry::common::SystemTimestamp &) noexcept override + const context_api::Context &) noexcept override { ++offered; } @@ -78,8 +74,7 @@ int ForwardedCount(metrics_sdk::ExemplarFilterType filter_type, const context_ap auto *spy = new CountingReservoir(); auto filtered = metrics_sdk::ExemplarReservoir::GetSimpleFilteredExemplarReservoir( filter_type, nostd::shared_ptr(spy)); - filtered->OfferMeasurement(1.0, metrics_sdk::MetricAttributes{}, context, - std::chrono::system_clock::now()); + filtered->OfferMeasurement(1.0, metrics_sdk::MetricAttributes{}, context); return spy->offered; } } // namespace @@ -96,7 +91,7 @@ TEST(FilteredExemplarReservoir, AlwaysOnOffersLongMeasurement) metrics_sdk::ExemplarFilterType::kAlwaysOn, nostd::shared_ptr(spy)); filtered->OfferMeasurement(static_cast(1), metrics_sdk::MetricAttributes{}, - context_api::Context{}, std::chrono::system_clock::now()); + context_api::Context{}); EXPECT_EQ(spy->offered, 1); } diff --git a/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc index 3e8e81f3d9..cb8b602212 100644 --- a/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc +++ b/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc @@ -5,12 +5,10 @@ # 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()); } From af8d0529a73f718db4e0885e11148df5710c47ac Mon Sep 17 00:00:00 2001 From: proost Date: Fri, 31 Jul 2026 07:44:31 +0000 Subject: [PATCH 07/13] perf: use ExemplarFilterEnabled --- .../sdk/metrics/exemplar/filter_predicate.h | 47 +++++++ .../exemplar/filtered_exemplar_reservoir.h | 109 ---------------- .../sdk/metrics/exemplar/reservoir.h | 5 - .../sdk/metrics/exemplar/reservoir_utils.h | 26 ++-- .../sdk/metrics/state/async_metric_storage.h | 10 +- .../sdk/metrics/state/sync_metric_storage.h | 25 +++- sdk/src/metrics/exemplar/reservoir.cc | 11 -- sdk/src/metrics/meter.cc | 2 + sdk/test/metrics/async_metric_storage_test.cc | 7 +- .../metrics/bound_sync_instruments_test.cc | 53 ++++---- sdk/test/metrics/cardinality_limit_test.cc | 2 + sdk/test/metrics/exemplar/BUILD | 4 +- sdk/test/metrics/exemplar/CMakeLists.txt | 2 +- .../metrics/exemplar/filter_predicate_test.cc | 67 ++++++++++ .../filtered_exemplar_reservoir_test.cc | 120 ------------------ .../sync_metric_storage_counter_test.cc | 11 +- .../metrics/sync_metric_storage_gauge_test.cc | 9 +- .../sync_metric_storage_histogram_test.cc | 7 +- ...ync_metric_storage_up_down_counter_test.cc | 5 +- 19 files changed, 216 insertions(+), 306 deletions(-) create mode 100644 sdk/include/opentelemetry/sdk/metrics/exemplar/filter_predicate.h delete mode 100644 sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h create mode 100644 sdk/test/metrics/exemplar/filter_predicate_test.cc delete mode 100644 sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc 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/filtered_exemplar_reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h deleted file mode 100644 index 648f7190a5..0000000000 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/filtered_exemplar_reservoir.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - -# include -# include -# include -# include - -# include "opentelemetry/common/timestamp.h" -# include "opentelemetry/context/context.h" -# include "opentelemetry/nostd/shared_ptr.h" -# include "opentelemetry/sdk/metrics/data/exemplar_data.h" -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" -# include "opentelemetry/sdk/metrics/exemplar/reservoir.h" -# include "opentelemetry/trace/context.h" -# include "opentelemetry/trace/span_context.h" -# include "opentelemetry/version.h" - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace metrics -{ - -/** - * A reservoir that pre-filters measurements according to an ExemplarFilterType before - * delegating eligible ones to a wrapped reservoir. - */ -class FilteredExemplarReservoir final : public ExemplarReservoir -{ -public: - FilteredExemplarReservoir(ExemplarFilterType filter_type, - nostd::shared_ptr reservoir) - : should_sample_(SelectFilter(filter_type)), reservoir_(std::move(reservoir)) - {} - - void OfferMeasurement(int64_t value, - const MetricAttributes &attributes, - const opentelemetry::context::Context &context) noexcept override - { - if (should_sample_(context)) - { - reservoir_->OfferMeasurement(value, attributes, context); - } - } - - void OfferMeasurement(double value, - const MetricAttributes &attributes, - const opentelemetry::context::Context &context) noexcept override - { - if (should_sample_(context)) - { - reservoir_->OfferMeasurement(value, attributes, context); - } - } - - std::vector> CollectAndReset( - const MetricAttributes &pointAttributes) noexcept override - { - return reservoir_->CollectAndReset(pointAttributes); - } - -private: - using ShouldSampleFn = bool (*)(const opentelemetry::context::Context &context); - - static bool AlwaysOn(const opentelemetry::context::Context & /* context */) noexcept - { - return true; - } - - static bool AlwaysOff(const opentelemetry::context::Context & /* context */) noexcept - { - return false; - } - - static bool TraceBased(const opentelemetry::context::Context &context) noexcept - { - const opentelemetry::trace::SpanContext span_context = - opentelemetry::trace::GetSpanContext(context); - return span_context.IsValid() && span_context.IsSampled(); - } - - static ShouldSampleFn SelectFilter(ExemplarFilterType filter_type) noexcept - { - switch (filter_type) - { - case ExemplarFilterType::kAlwaysOn: - return &AlwaysOn; - case ExemplarFilterType::kAlwaysOff: - return &AlwaysOff; - case ExemplarFilterType::kTraceBased: - return &TraceBased; - } - return &TraceBased; // unreachable; all enumerators handled above - } - - ShouldSampleFn should_sample_; - nostd::shared_ptr reservoir_; -}; - -} // namespace metrics -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE - -#endif // ENABLE_METRICS_EXEMPLAR_PREVIEW diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir.h index 6f8b27ab4e..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" @@ -69,10 +68,6 @@ class ExemplarReservoir virtual std::vector> CollectAndReset( const MetricAttributes &pointAttributes) noexcept = 0; - static nostd::shared_ptr GetSimpleFilteredExemplarReservoir( - ExemplarFilterType filter_type, - nostd::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_utils.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h index 36bbba8cd0..26d47ff388 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_utils.h @@ -53,6 +53,11 @@ static inline nostd::shared_ptr GetExemplarReservoir( 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); @@ -64,21 +69,18 @@ static inline nostd::shared_ptr GetExemplarReservoir( // if (histogram_agg_config != nullptr && histogram_agg_config->boundaries_.size() > 1) { - return ExemplarReservoir::GetSimpleFilteredExemplarReservoir( - filter_type, - nostd::shared_ptr(new AlignedHistogramBucketExemplarReservoir( - histogram_agg_config->boundaries_.size(), - AlignedHistogramBucketExemplarReservoir::GetHistogramCellSelector( - histogram_agg_config->boundaries_), - GetMapAndResetCellMethod(instrument_descriptor)))); + return ExemplarReservoir::GetAlignedHistogramBucketExemplarReservoir( + histogram_agg_config->boundaries_.size(), + AlignedHistogramBucketExemplarReservoir::GetHistogramCellSelector( + histogram_agg_config->boundaries_), + GetMapAndResetCellMethod(instrument_descriptor)); } } - return ExemplarReservoir::GetSimpleFilteredExemplarReservoir( - filter_type, nostd::shared_ptr(new SimpleFixedSizeExemplarReservoir( - GetSimpleFixedReservoirDefaultSize(agg_type, agg_config), - SimpleFixedSizeExemplarReservoir::GetSimpleFixedSizeCellSelector(), - GetMapAndResetCellMethod(instrument_descriptor)))); + return ExemplarReservoir::GetSimpleFixedSizeExemplarReservoir( + GetSimpleFixedReservoirDefaultSize(agg_type, agg_config), + SimpleFixedSizeExemplarReservoir::GetSimpleFixedSizeCellSelector(), + 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 cec8c5ad7e..6a499bdd04 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,8 @@ #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,6 +39,7 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora const AggregationType aggregation_type, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW nostd::shared_ptr &&exemplar_reservoir, + ExemplarFilterType exemplar_filter_type, #endif const AggregationConfig *aggregation_config) : instrument_descriptor_(instrument_descriptor), @@ -48,6 +51,7 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora std::make_unique(aggregation_config_->cardinality_limit_)), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_reservoir_(std::move(exemplar_reservoir)), + exemplar_filter_type_(exemplar_filter_type), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) {} @@ -63,7 +67,10 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora for (auto &measurement : measurements) { #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}); + if (ExemplarFilterEnabled(exemplar_filter_type_, opentelemetry::context::Context{})) + { + exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}); + } #endif auto aggr = DefaultAggregation::CreateAggregation(aggregation_type_, instrument_descriptor_); @@ -140,6 +147,7 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora opentelemetry::common::SpinLockMutex hashmap_lock_; #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW nostd::shared_ptr exemplar_reservoir_; + ExemplarFilterType exemplar_filter_type_; #endif TemporalMetricStorage temporal_metric_storage_; }; 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 f7133c4f97..8238dd86db 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,8 @@ #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 @@ -53,6 +55,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage std::shared_ptr attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW nostd::shared_ptr &&exemplar_reservoir, + ExemplarFilterType exemplar_filter_type, #endif const AggregationConfig *aggregation_config) : instrument_descriptor_(instrument_descriptor), @@ -62,6 +65,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage attributes_processor_(std::move(attributes_processor)), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_reservoir_(std::move(exemplar_reservoir)), + exemplar_filter_type_(exemplar_filter_type), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) { @@ -81,7 +85,10 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, {}, context); + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) + { + exemplar_reservoir_->OfferMeasurement(value, {}, context); + } #endif static MetricAttributes attr = MetricAttributes{}; std::lock_guard guard(attribute_hashmap_lock_); @@ -104,7 +111,10 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, attributes, context); + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) + { + exemplar_reservoir_->OfferMeasurement(value, attributes, context); + } #endif MetricAttributes attr{attributes, attributes_processor_.get()}; @@ -132,7 +142,10 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, {}, context); + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) + { + exemplar_reservoir_->OfferMeasurement(value, {}, context); + } #endif static MetricAttributes attr = MetricAttributes{}; std::lock_guard guard(attribute_hashmap_lock_); @@ -155,7 +168,10 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage return; } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_->OfferMeasurement(value, attributes, context); + if (ExemplarFilterEnabled(exemplar_filter_type_, context)) + { + exemplar_reservoir_->OfferMeasurement(value, attributes, context); + } #endif MetricAttributes attr{attributes, attributes_processor_.get()}; std::lock_guard guard(attribute_hashmap_lock_); @@ -267,6 +283,7 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage std::shared_ptr attributes_processor_; #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW nostd::shared_ptr exemplar_reservoir_; + ExemplarFilterType exemplar_filter_type_; #endif TemporalMetricStorage temporal_metric_storage_; opentelemetry::common::SpinLockMutex attribute_hashmap_lock_; diff --git a/sdk/src/metrics/exemplar/reservoir.cc b/sdk/src/metrics/exemplar/reservoir.cc index 71e46ba298..f5fe4064b6 100644 --- a/sdk/src/metrics/exemplar/reservoir.cc +++ b/sdk/src/metrics/exemplar/reservoir.cc @@ -4,12 +4,9 @@ #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW # include -# include # include "opentelemetry/nostd/shared_ptr.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/filtered_exemplar_reservoir.h" # include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir_cell.h" @@ -23,14 +20,6 @@ namespace sdk namespace metrics { -nostd::shared_ptr ExemplarReservoir::GetSimpleFilteredExemplarReservoir( - ExemplarFilterType filter_type, - nostd::shared_ptr reservoir) -{ - return nostd::shared_ptr{ - new FilteredExemplarReservoir{filter_type, std::move(reservoir)}}; -} - nostd::shared_ptr ExemplarReservoir::GetSimpleFixedSizeExemplarReservoir( size_t size, const std::shared_ptr &reservoir_cell_selector, diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index 8acab9f3dd..7b295a3851 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -547,6 +547,7 @@ std::unique_ptr Meter::RegisterSyncMetricStorage( #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW GetExemplarReservoir(view.GetAggregationType(), view.GetAggregationConfig(), view_instr_desc, exemplar_filter_type), + exemplar_filter_type, #endif view.GetAggregationConfig())); storage_registry_.insert({view_instr_desc, sync_storage}); @@ -619,6 +620,7 @@ std::unique_ptr Meter::RegisterAsyncMetricStorage( #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW GetExemplarReservoir(view.GetAggregationType(), view.GetAggregationConfig(), view_instr_desc, exemplar_filter_type), + exemplar_filter_type, #endif view.GetAggregationConfig())); storage_registry_.insert({view_instr_desc, async_storage}); diff --git a/sdk/test/metrics/async_metric_storage_test.cc b/sdk/test/metrics/async_metric_storage_test.cc index be3a9fdfa6..269217261a 100644 --- a/sdk/test/metrics/async_metric_storage_test.cc +++ b/sdk/test/metrics/async_metric_storage_test.cc @@ -28,6 +28,7 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -69,7 +70,7 @@ TEST_P(AsyncWritableMetricStorageTestFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kSum, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); int64_t get_count1 = 20; @@ -164,7 +165,7 @@ TEST_P(WritableMetricStorageTestUpDownFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kDefault, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); int64_t get_count1 = 20; @@ -260,7 +261,7 @@ TEST_P(WritableMetricStorageTestObservableGaugeFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kLastValue, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); int64_t freq_cpu0 = 3; diff --git a/sdk/test/metrics/bound_sync_instruments_test.cc b/sdk/test/metrics/bound_sync_instruments_test.cc index 6b289c6aa4..b0eef28049 100644 --- a/sdk/test/metrics/bound_sync_instruments_test.cc +++ b/sdk/test/metrics/bound_sync_instruments_test.cc @@ -40,6 +40,7 @@ # include "opentelemetry/sdk/metrics/view/attributes_processor.h" # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" # endif @@ -75,6 +76,7 @@ class StorageHolder storage_ = std::make_shared(desc, agg_type, proc_, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarFilterType::kAlwaysOff, # endif cfg_); } @@ -184,12 +186,12 @@ TEST(BoundSyncInstruments, BoundCounterBindInitializerList) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); AggregationConfig cfg; - std::unique_ptr storage( - new SyncMetricStorage(desc, AggregationType::kSum, proc, + std::unique_ptr storage(new SyncMetricStorage( + desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongCounter counter(desc, std::move(storage)); opentelemetry::metrics::Counter &api_counter = counter; @@ -236,12 +238,12 @@ TEST(BoundSyncInstruments, UnboundCounterDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); AggregationConfig cfg; - std::unique_ptr storage( - new SyncMetricStorage(desc, AggregationType::kSum, proc, + std::unique_ptr storage(new SyncMetricStorage( + desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongCounter counter(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -259,12 +261,12 @@ TEST(BoundSyncInstruments, BoundCounterDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); AggregationConfig cfg; - std::unique_ptr storage( - new SyncMetricStorage(desc, AggregationType::kSum, proc, + std::unique_ptr storage(new SyncMetricStorage( + desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongCounter counter(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -313,12 +315,12 @@ TEST(BoundSyncInstruments, UnboundHistogramDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); HistogramAggregationConfig cfg; - std::unique_ptr storage( - new SyncMetricStorage(desc, AggregationType::kHistogram, proc, + std::unique_ptr storage(new SyncMetricStorage( + desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongHistogram histogram(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -352,12 +354,12 @@ TEST(BoundSyncInstruments, BoundHistogramDropsValueAboveInt64Max) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); HistogramAggregationConfig cfg; - std::unique_ptr storage( - new SyncMetricStorage(desc, AggregationType::kHistogram, proc, + std::unique_ptr storage(new SyncMetricStorage( + desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongHistogram histogram(desc, std::move(storage)); M attrs = {{"key", "v"}}; @@ -392,12 +394,12 @@ TEST(BoundSyncInstruments, BoundHistogramBindInitializerList) InstrumentValueType::kLong}; std::shared_ptr proc(new DefaultAttributesProcessor{}); HistogramAggregationConfig cfg; - std::unique_ptr storage( - new SyncMetricStorage(desc, AggregationType::kHistogram, proc, + std::unique_ptr storage(new SyncMetricStorage( + desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif - &cfg)); + &cfg)); SyncMetricStorage *storage_ptr = storage.get(); LongHistogram histogram(desc, std::move(storage)); opentelemetry::metrics::Histogram &api_histogram = histogram; @@ -435,6 +437,7 @@ TEST(BoundSyncInstruments, BoundCounterRespectsDropAggregation) SyncMetricStorage storage(desc, AggregationType::kDrop, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarFilterType::kAlwaysOff, # endif &cfg); M attrs = {{"k", "v"}}; @@ -470,6 +473,7 @@ TEST(BoundSyncInstruments, BoundCounterRespectsLastValueAggregation) SyncMetricStorage storage(desc, AggregationType::kLastValue, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarFilterType::kAlwaysOff, # endif &cfg); M attrs = {{"k", "v"}}; @@ -508,6 +512,7 @@ TEST(BoundSyncInstruments, BoundHistogramRespectsCustomBuckets) SyncMetricStorage storage(desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarFilterType::kAlwaysOff, # endif &cfg); M attrs = {{"k", "v"}}; diff --git a/sdk/test/metrics/cardinality_limit_test.cc b/sdk/test/metrics/cardinality_limit_test.cc index cd38641a79..2ca7f2e6c9 100644 --- a/sdk/test/metrics/cardinality_limit_test.cc +++ b/sdk/test/metrics/cardinality_limit_test.cc @@ -32,6 +32,7 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -120,6 +121,7 @@ TEST_P(WritableMetricStorageCardinalityLimitTestFixture, LongCounterSumAggregati SyncMetricStorage storage(instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarFilterType::kAlwaysOff, #endif &aggConfig); diff --git a/sdk/test/metrics/exemplar/BUILD b/sdk/test/metrics/exemplar/BUILD index 10973fd000..2dbfd39f8d 100644 --- a/sdk/test/metrics/exemplar/BUILD +++ b/sdk/test/metrics/exemplar/BUILD @@ -55,9 +55,9 @@ cc_test( ) cc_test( - name = "filtered_exemplar_reservoir_test", + name = "filter_predicate_test", srcs = [ - "filtered_exemplar_reservoir_test.cc", + "filter_predicate_test.cc", ], tags = [ "metrics", diff --git a/sdk/test/metrics/exemplar/CMakeLists.txt b/sdk/test/metrics/exemplar/CMakeLists.txt index 32f755e747..2dfb891ee2 100644 --- a/sdk/test/metrics/exemplar/CMakeLists.txt +++ b/sdk/test/metrics/exemplar/CMakeLists.txt @@ -4,7 +4,7 @@ foreach( testname no_exemplar_reservoir_test aligned_histogram_bucket_exemplar_reservoir_test - reservoir_cell_test filtered_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/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/filtered_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc deleted file mode 100644 index 5571c22013..0000000000 --- a/sdk/test/metrics/exemplar/filtered_exemplar_reservoir_test.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -#ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - -# include -# include -# include -# include - -# include "opentelemetry/context/context.h" -# include "opentelemetry/nostd/shared_ptr.h" -# include "opentelemetry/nostd/span.h" -# include "opentelemetry/sdk/metrics/data/exemplar_data.h" -# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" -# include "opentelemetry/sdk/metrics/exemplar/reservoir.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; - -class CountingReservoir : public metrics_sdk::ExemplarReservoir -{ -public: - void OfferMeasurement(int64_t, - const metrics_sdk::MetricAttributes &, - const context_api::Context &) noexcept override - { - ++offered; - } - - void OfferMeasurement(double, - const metrics_sdk::MetricAttributes &, - const context_api::Context &) noexcept override - { - ++offered; - } - - std::vector> CollectAndReset( - const metrics_sdk::MetricAttributes &) noexcept override - { - return {}; - } - - int offered = 0; -}; - -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); -} - -int ForwardedCount(metrics_sdk::ExemplarFilterType filter_type, const context_api::Context &context) -{ - auto *spy = new CountingReservoir(); - auto filtered = metrics_sdk::ExemplarReservoir::GetSimpleFilteredExemplarReservoir( - filter_type, nostd::shared_ptr(spy)); - filtered->OfferMeasurement(1.0, metrics_sdk::MetricAttributes{}, context); - return spy->offered; -} -} // namespace - -TEST(FilteredExemplarReservoir, AlwaysOnOffersMeasurement) -{ - EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kAlwaysOn, context_api::Context{}), 1); -} - -TEST(FilteredExemplarReservoir, AlwaysOnOffersLongMeasurement) -{ - auto *spy = new CountingReservoir(); - auto filtered = metrics_sdk::ExemplarReservoir::GetSimpleFilteredExemplarReservoir( - metrics_sdk::ExemplarFilterType::kAlwaysOn, - nostd::shared_ptr(spy)); - filtered->OfferMeasurement(static_cast(1), metrics_sdk::MetricAttributes{}, - context_api::Context{}); - EXPECT_EQ(spy->offered, 1); -} - -TEST(FilteredExemplarReservoir, AlwaysOffDropsMeasurement) -{ - EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kAlwaysOff, context_api::Context{}), 0); -} - -TEST(FilteredExemplarReservoir, TraceBasedDropsWithoutSpan) -{ - EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kTraceBased, context_api::Context{}), - 0); -} - -TEST(FilteredExemplarReservoir, TraceBasedOffersWithSampledSpan) -{ - EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kTraceBased, ContextWithSpan(true)), 1); -} - -TEST(FilteredExemplarReservoir, TraceBasedDropsUnsampledSpan) -{ - EXPECT_EQ(ForwardedCount(metrics_sdk::ExemplarFilterType::kTraceBased, ContextWithSpan(false)), - 0); -} - -#endif // ENABLE_METRICS_EXEMPLAR_PREVIEW diff --git a/sdk/test/metrics/sync_metric_storage_counter_test.cc b/sdk/test/metrics/sync_metric_storage_counter_test.cc index 9bc6d48797..6a8450de35 100644 --- a/sdk/test/metrics/sync_metric_storage_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_counter_test.cc @@ -27,6 +27,7 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -56,7 +57,7 @@ TEST_P(CounterWritableMetricStorageTestFixture, LongCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); @@ -196,7 +197,7 @@ TEST_P(CounterWritableMetricStorageTestFixture, DoubleCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); @@ -332,7 +333,7 @@ TEST(SyncMetricStorageTest, DeltaCounterStartTimestampTracksEmptyCycles) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); @@ -410,7 +411,7 @@ TEST(SyncMetricStorageTest, DeltaCounterFirstIntervalUsesInstrumentCreationTime) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); auto after_creation = std::chrono::system_clock::now(); @@ -463,7 +464,7 @@ TEST(SyncMetricStorageTest, DeltaCounterMultiCollectorFirstIntervalUsesInstrumen opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); auto after_creation = std::chrono::system_clock::now(); diff --git a/sdk/test/metrics/sync_metric_storage_gauge_test.cc b/sdk/test/metrics/sync_metric_storage_gauge_test.cc index ab298b71a9..18e7c553d1 100644 --- a/sdk/test/metrics/sync_metric_storage_gauge_test.cc +++ b/sdk/test/metrics/sync_metric_storage_gauge_test.cc @@ -26,6 +26,7 @@ # include "opentelemetry/nostd/variant.h" # include "opentelemetry/sdk/metrics/data/metric_data.h" # include "opentelemetry/sdk/metrics/data/point_data.h" +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" # include "opentelemetry/sdk/metrics/state/metric_collector.h" # include "opentelemetry/sdk/metrics/state/sync_metric_storage.h" @@ -61,7 +62,7 @@ TEST_P(GaugeWritableMetricStorageTestFixture, LongGaugeLastValueAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif nullptr); @@ -145,7 +146,7 @@ TEST_P(GaugeWritableMetricStorageTestFixture, DoubleGaugeLastValueAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif nullptr); @@ -239,7 +240,7 @@ TEST_P(WritableMetricStorageDeltaMultiReaderTestFixture, opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif nullptr); auto after_creation = std::chrono::system_clock::now(); @@ -420,7 +421,7 @@ TEST_P(WritableMetricStorageDeltaMultiReaderTestFixture, opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, # endif nullptr); auto after_creation = std::chrono::system_clock::now(); diff --git a/sdk/test/metrics/sync_metric_storage_histogram_test.cc b/sdk/test/metrics/sync_metric_storage_histogram_test.cc index d363a6413f..689b3e6a93 100644 --- a/sdk/test/metrics/sync_metric_storage_histogram_test.cc +++ b/sdk/test/metrics/sync_metric_storage_histogram_test.cc @@ -27,6 +27,7 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -56,7 +57,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, LongHistogram) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); @@ -197,7 +198,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, DoubleHistogram) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); @@ -345,7 +346,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, Base2ExponentialDoubleHistogra opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kBase2ExponentialHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); diff --git a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc index 4a781b9472..9f61d2ceae 100644 --- a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc @@ -26,6 +26,7 @@ #include "opentelemetry/sdk/metrics/view/attributes_processor.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW +# include "opentelemetry/sdk/metrics/exemplar/filter_type.h" # include "opentelemetry/sdk/metrics/exemplar/reservoir.h" #endif @@ -55,7 +56,7 @@ TEST_P(UpDownCounterWritableMetricStorageTestFixture, LongUpDownCounterSumAggreg opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); @@ -205,7 +206,7 @@ TEST_P(UpDownCounterWritableMetricStorageTestFixture, DoubleUpDownCounterSumAggr opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), + ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, #endif nullptr); From 30496c0494520d0481355d5e631319a7773ee7dd Mon Sep 17 00:00:00 2001 From: proost Date: Fri, 31 Jul 2026 19:45:12 +0900 Subject: [PATCH 08/13] fix: remove span context validation --- .../sdk/metrics/exemplar/reservoir_cell.h | 7 ++----- sdk/test/metrics/exemplar/reservoir_cell_test.cc | 11 +++++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h index be22ba9e61..fcd6bd072a 100644 --- a/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h +++ b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h @@ -134,11 +134,8 @@ 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_.reset( + new opentelemetry::trace::SpanContext{opentelemetry::trace::GetSpanContext(context)}); } // Cell stores either long or double values, but must not store both diff --git a/sdk/test/metrics/exemplar/reservoir_cell_test.cc b/sdk/test/metrics/exemplar/reservoir_cell_test.cc index 93f1b72121..9d0188617c 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,16 @@ 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, Filtered) { FilteredTest(); From 47625e6216a1b82d79e1c70a3af962c966dc4935 Mon Sep 17 00:00:00 2001 From: proost Date: Fri, 31 Jul 2026 23:18:54 +0900 Subject: [PATCH 09/13] style: rollback ctor order --- .../sdk/metrics/state/async_metric_storage.h | 12 +++++++---- .../sdk/metrics/state/sync_metric_storage.h | 6 +++--- sdk/src/metrics/meter.cc | 4 ++-- sdk/test/metrics/async_metric_storage_test.cc | 6 +++--- .../metrics/bound_sync_instruments_test.cc | 20 +++++++++---------- sdk/test/metrics/cardinality_limit_test.cc | 2 +- .../sync_metric_storage_counter_test.cc | 10 +++++----- .../metrics/sync_metric_storage_gauge_test.cc | 8 ++++---- .../sync_metric_storage_histogram_test.cc | 6 +++--- ...ync_metric_storage_up_down_counter_test.cc | 4 ++-- 10 files changed, 41 insertions(+), 37 deletions(-) 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 6a499bdd04..122819e3d3 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h @@ -38,8 +38,8 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora AsyncMetricStorage(const InstrumentDescriptor &instrument_descriptor, const AggregationType aggregation_type, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - nostd::shared_ptr &&exemplar_reservoir, ExemplarFilterType exemplar_filter_type, + nostd::shared_ptr &&exemplar_reservoir, #endif const AggregationConfig *aggregation_config) : instrument_descriptor_(instrument_descriptor), @@ -50,8 +50,8 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora delta_hash_map_( std::make_unique(aggregation_config_->cardinality_limit_)), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - exemplar_reservoir_(std::move(exemplar_reservoir)), exemplar_filter_type_(exemplar_filter_type), + exemplar_reservoir_(std::move(exemplar_reservoir)), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) {} @@ -64,10 +64,14 @@ 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 (ExemplarFilterEnabled(exemplar_filter_type_, opentelemetry::context::Context{})) + if (offer_exemplars) { exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}); } @@ -146,8 +150,8 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora std::unique_ptr delta_hash_map_; opentelemetry::common::SpinLockMutex hashmap_lock_; #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - nostd::shared_ptr exemplar_reservoir_; ExemplarFilterType exemplar_filter_type_; + nostd::shared_ptr exemplar_reservoir_; #endif TemporalMetricStorage temporal_metric_storage_; }; 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 8238dd86db..f496398a8f 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h @@ -54,8 +54,8 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage const AggregationType aggregation_type, std::shared_ptr attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - nostd::shared_ptr &&exemplar_reservoir, ExemplarFilterType exemplar_filter_type, + nostd::shared_ptr &&exemplar_reservoir, #endif const AggregationConfig *aggregation_config) : instrument_descriptor_(instrument_descriptor), @@ -64,8 +64,8 @@ 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_reservoir_(std::move(exemplar_reservoir)), exemplar_filter_type_(exemplar_filter_type), + exemplar_reservoir_(std::move(exemplar_reservoir)), #endif temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) { @@ -282,8 +282,8 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage std::function()> create_default_aggregation_; std::shared_ptr attributes_processor_; #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - nostd::shared_ptr exemplar_reservoir_; ExemplarFilterType exemplar_filter_type_; + nostd::shared_ptr exemplar_reservoir_; #endif TemporalMetricStorage temporal_metric_storage_; opentelemetry::common::SpinLockMutex attribute_hashmap_lock_; diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index 7b295a3851..9850d122bc 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -545,9 +545,9 @@ std::unique_ptr Meter::RegisterSyncMetricStorage( sync_storage = std::shared_ptr(new SyncMetricStorage( view_instr_desc, view.GetAggregationType(), view.GetAttributesProcessor(), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW + exemplar_filter_type, GetExemplarReservoir(view.GetAggregationType(), view.GetAggregationConfig(), view_instr_desc, exemplar_filter_type), - exemplar_filter_type, #endif view.GetAggregationConfig())); storage_registry_.insert({view_instr_desc, sync_storage}); @@ -618,9 +618,9 @@ std::unique_ptr Meter::RegisterAsyncMetricStorage( async_storage = std::shared_ptr(new AsyncMetricStorage( view_instr_desc, view.GetAggregationType(), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW + exemplar_filter_type, GetExemplarReservoir(view.GetAggregationType(), view.GetAggregationConfig(), view_instr_desc, exemplar_filter_type), - exemplar_filter_type, #endif view.GetAggregationConfig())); storage_registry_.insert({view_instr_desc, async_storage}); diff --git a/sdk/test/metrics/async_metric_storage_test.cc b/sdk/test/metrics/async_metric_storage_test.cc index 269217261a..54eec782ec 100644 --- a/sdk/test/metrics/async_metric_storage_test.cc +++ b/sdk/test/metrics/async_metric_storage_test.cc @@ -70,7 +70,7 @@ TEST_P(AsyncWritableMetricStorageTestFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kSum, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); int64_t get_count1 = 20; @@ -165,7 +165,7 @@ TEST_P(WritableMetricStorageTestUpDownFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kDefault, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); int64_t get_count1 = 20; @@ -261,7 +261,7 @@ TEST_P(WritableMetricStorageTestObservableGaugeFixture, TestAggregation) opentelemetry::sdk::metrics::AsyncMetricStorage storage( instr_desc, AggregationType::kLastValue, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); int64_t freq_cpu0 = 3; diff --git a/sdk/test/metrics/bound_sync_instruments_test.cc b/sdk/test/metrics/bound_sync_instruments_test.cc index b0eef28049..756030437e 100644 --- a/sdk/test/metrics/bound_sync_instruments_test.cc +++ b/sdk/test/metrics/bound_sync_instruments_test.cc @@ -75,8 +75,8 @@ class StorageHolder } storage_ = std::make_shared(desc, agg_type, proc_, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarReservoir::GetNoExemplarReservoir(), # endif cfg_); } @@ -189,7 +189,7 @@ TEST(BoundSyncInstruments, BoundCounterBindInitializerList) std::unique_ptr storage(new SyncMetricStorage( desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg)); SyncMetricStorage *storage_ptr = storage.get(); @@ -241,7 +241,7 @@ TEST(BoundSyncInstruments, UnboundCounterDropsValueAboveInt64Max) std::unique_ptr storage(new SyncMetricStorage( desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg)); SyncMetricStorage *storage_ptr = storage.get(); @@ -264,7 +264,7 @@ TEST(BoundSyncInstruments, BoundCounterDropsValueAboveInt64Max) std::unique_ptr storage(new SyncMetricStorage( desc, AggregationType::kSum, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg)); SyncMetricStorage *storage_ptr = storage.get(); @@ -318,7 +318,7 @@ TEST(BoundSyncInstruments, UnboundHistogramDropsValueAboveInt64Max) std::unique_ptr storage(new SyncMetricStorage( desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg)); SyncMetricStorage *storage_ptr = storage.get(); @@ -357,7 +357,7 @@ TEST(BoundSyncInstruments, BoundHistogramDropsValueAboveInt64Max) std::unique_ptr storage(new SyncMetricStorage( desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg)); SyncMetricStorage *storage_ptr = storage.get(); @@ -397,7 +397,7 @@ TEST(BoundSyncInstruments, BoundHistogramBindInitializerList) std::unique_ptr storage(new SyncMetricStorage( desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg)); SyncMetricStorage *storage_ptr = storage.get(); @@ -436,8 +436,8 @@ TEST(BoundSyncInstruments, BoundCounterRespectsDropAggregation) AggregationConfig cfg; SyncMetricStorage storage(desc, AggregationType::kDrop, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg); M attrs = {{"k", "v"}}; @@ -472,8 +472,8 @@ TEST(BoundSyncInstruments, BoundCounterRespectsLastValueAggregation) AggregationConfig cfg; SyncMetricStorage storage(desc, AggregationType::kLastValue, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg); M attrs = {{"k", "v"}}; @@ -511,8 +511,8 @@ TEST(BoundSyncInstruments, BoundHistogramRespectsCustomBuckets) cfg.boundaries_ = {10.0, 20.0}; SyncMetricStorage storage(desc, AggregationType::kHistogram, proc, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarReservoir::GetNoExemplarReservoir(), # endif &cfg); M attrs = {{"k", "v"}}; diff --git a/sdk/test/metrics/cardinality_limit_test.cc b/sdk/test/metrics/cardinality_limit_test.cc index 2ca7f2e6c9..cb7dc9b8a0 100644 --- a/sdk/test/metrics/cardinality_limit_test.cc +++ b/sdk/test/metrics/cardinality_limit_test.cc @@ -120,8 +120,8 @@ TEST_P(WritableMetricStorageCardinalityLimitTestFixture, LongCounterSumAggregati new DefaultAttributesProcessor{}}; SyncMetricStorage storage(instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarReservoir::GetNoExemplarReservoir(), #endif &aggConfig); diff --git a/sdk/test/metrics/sync_metric_storage_counter_test.cc b/sdk/test/metrics/sync_metric_storage_counter_test.cc index 6a8450de35..9d55708c6f 100644 --- a/sdk/test/metrics/sync_metric_storage_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_counter_test.cc @@ -57,7 +57,7 @@ TEST_P(CounterWritableMetricStorageTestFixture, LongCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -197,7 +197,7 @@ TEST_P(CounterWritableMetricStorageTestFixture, DoubleCounterSumAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -333,7 +333,7 @@ TEST(SyncMetricStorageTest, DeltaCounterStartTimestampTracksEmptyCycles) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -411,7 +411,7 @@ TEST(SyncMetricStorageTest, DeltaCounterFirstIntervalUsesInstrumentCreationTime) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); auto after_creation = std::chrono::system_clock::now(); @@ -464,7 +464,7 @@ TEST(SyncMetricStorageTest, DeltaCounterMultiCollectorFirstIntervalUsesInstrumen opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); auto after_creation = std::chrono::system_clock::now(); diff --git a/sdk/test/metrics/sync_metric_storage_gauge_test.cc b/sdk/test/metrics/sync_metric_storage_gauge_test.cc index 18e7c553d1..bda5226a63 100644 --- a/sdk/test/metrics/sync_metric_storage_gauge_test.cc +++ b/sdk/test/metrics/sync_metric_storage_gauge_test.cc @@ -62,7 +62,7 @@ TEST_P(GaugeWritableMetricStorageTestFixture, LongGaugeLastValueAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); @@ -146,7 +146,7 @@ TEST_P(GaugeWritableMetricStorageTestFixture, DoubleGaugeLastValueAggregation) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); @@ -240,7 +240,7 @@ TEST_P(WritableMetricStorageDeltaMultiReaderTestFixture, opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); auto after_creation = std::chrono::system_clock::now(); @@ -421,7 +421,7 @@ TEST_P(WritableMetricStorageDeltaMultiReaderTestFixture, opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kLastValue, default_attributes_processor, # ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), # endif nullptr); auto after_creation = std::chrono::system_clock::now(); diff --git a/sdk/test/metrics/sync_metric_storage_histogram_test.cc b/sdk/test/metrics/sync_metric_storage_histogram_test.cc index 689b3e6a93..ee3af6e8c4 100644 --- a/sdk/test/metrics/sync_metric_storage_histogram_test.cc +++ b/sdk/test/metrics/sync_metric_storage_histogram_test.cc @@ -57,7 +57,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, LongHistogram) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -198,7 +198,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, DoubleHistogram) opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -346,7 +346,7 @@ TEST_P(WritableMetricStorageHistogramTestFixture, Base2ExponentialDoubleHistogra opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kBase2ExponentialHistogram, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); diff --git a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc index 9f61d2ceae..d1f4112a09 100644 --- a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc @@ -56,7 +56,7 @@ TEST_P(UpDownCounterWritableMetricStorageTestFixture, LongUpDownCounterSumAggreg opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); @@ -206,7 +206,7 @@ TEST_P(UpDownCounterWritableMetricStorageTestFixture, DoubleUpDownCounterSumAggr opentelemetry::sdk::metrics::SyncMetricStorage storage( instr_desc, AggregationType::kSum, default_attributes_processor, #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW - ExemplarReservoir::GetNoExemplarReservoir(), ExemplarFilterType::kAlwaysOff, + ExemplarFilterType::kAlwaysOff, ExemplarReservoir::GetNoExemplarReservoir(), #endif nullptr); From 5eddcd2aa851fcde40ba2630b9ecacaf887d53e9 Mon Sep 17 00:00:00 2001 From: proost Date: Sat, 1 Aug 2026 14:59:40 +0900 Subject: [PATCH 10/13] doc: update breaking change --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56eaf34432..f116184f8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,12 @@ Increment the: Breaking changes: +* [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] Rename Base2 Exponential Histogram Aggregation config field [#4253](https://github.com/open-telemetry/opentelemetry-cpp/pull/4253) * The public configuration member `max_buckets_` was renamed to `max_size_` to From 7bf25852a479d87490f9b76c85d78c1503ddc1f5 Mon Sep 17 00:00:00 2001 From: proost Date: Wed, 5 Aug 2026 16:40:14 +0900 Subject: [PATCH 11/13] perf: remove allocation to heap --- .../opentelemetry/sdk/metrics/data/exemplar_data.h | 8 +++----- .../sdk/metrics/exemplar/reservoir_cell.h | 12 +++++++----- ...igned_histogram_bucket_exemplar_reservoir_test.cc | 2 -- .../metrics/exemplar/no_exemplar_reservoir_test.cc | 2 -- 4 files changed, 10 insertions(+), 14 deletions(-) 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/reservoir_cell.h b/sdk/include/opentelemetry/sdk/metrics/exemplar/reservoir_cell.h index bb6831b8de..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,12 +135,13 @@ class ReservoirCell { attributes_ = attributes; record_time_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); - context_.reset( - new opentelemetry::trace::SpanContext{opentelemetry::trace::GetSpanContext(context)}); + 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/test/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/aligned_histogram_bucket_exemplar_reservoir_test.cc index 9210c25c9f..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 @@ -5,8 +5,6 @@ # include # include -# include -# include # include # include # include diff --git a/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc b/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc index 6ee96e8028..cb8b602212 100644 --- a/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc +++ b/sdk/test/metrics/exemplar/no_exemplar_reservoir_test.cc @@ -5,8 +5,6 @@ # include # include -# include -# include # include # include # include From 36454568bde664ff79d70d2e0fb8816ba02a754d Mon Sep 17 00:00:00 2001 From: proost Date: Wed, 5 Aug 2026 16:54:18 +0900 Subject: [PATCH 12/13] doc: update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcba124fa8..0307b9ca2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -164,6 +164,12 @@ Breaking changes: * 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 From b314b34cc9551ba2eb7ce5485303541bb19d5d21 Mon Sep 17 00:00:00 2001 From: proost Date: Wed, 5 Aug 2026 20:44:05 +0900 Subject: [PATCH 13/13] fix: offer with attributes --- .../sdk/metrics/state/async_metric_storage.h | 2 +- sdk/test/metrics/exemplar/reservoir_cell_test.cc | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) 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 122819e3d3..674863428b 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h @@ -73,7 +73,7 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW if (offer_exemplars) { - exemplar_reservoir_->OfferMeasurement(measurement.second, {}, {}); + exemplar_reservoir_->OfferMeasurement(measurement.second, measurement.first, {}); } #endif diff --git a/sdk/test/metrics/exemplar/reservoir_cell_test.cc b/sdk/test/metrics/exemplar/reservoir_cell_test.cc index d78b414108..5bd0194835 100644 --- a/sdk/test/metrics/exemplar/reservoir_cell_test.cc +++ b/sdk/test/metrics/exemplar/reservoir_cell_test.cc @@ -85,6 +85,15 @@ TEST_F(ReservoirCellTestPeer, ProducesExemplarWithoutSpanContext) 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();