diff --git a/api/include/opentelemetry/metrics/meter.h b/api/include/opentelemetry/metrics/meter.h index 8784fe788e..8f6e8e97a5 100644 --- a/api/include/opentelemetry/metrics/meter.h +++ b/api/include/opentelemetry/metrics/meter.h @@ -21,6 +21,9 @@ class Histogram; template class UpDownCounter; +template +class Gauge; + class ObservableInstrument; /** @@ -91,6 +94,27 @@ class Meter nostd::string_view description = "", nostd::string_view unit = "") noexcept = 0; +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + /** + * Creates a Gauge with the passed characteristics and returns a + * unique_ptr to that Gauge + * @since ABI_VERSION 2 + * + * @param name the name of the new Gauge. + * @param description a brief description of what the Gauge is used for. + * @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html. + */ + virtual nostd::unique_ptr> CreateInt64Gauge( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept = 0; + + virtual nostd::unique_ptr> CreateDoubleGauge( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept = 0; +#endif + /** * Creates a Asynchronouse (Observable) Gauge with the passed characteristics and returns a * shared_ptr to that Observable Gauge diff --git a/api/include/opentelemetry/metrics/noop.h b/api/include/opentelemetry/metrics/noop.h index f20e855cb7..c6d53f1da0 100644 --- a/api/include/opentelemetry/metrics/noop.h +++ b/api/include/opentelemetry/metrics/noop.h @@ -44,6 +44,13 @@ class NoopHistogram : public Histogram const common::KeyValueIterable & /* attributes */, const context::Context & /* context */) noexcept override {} +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + void Record(T /*value*/, + const opentelemetry::common::KeyValueIterable & /*attributes*/) noexcept override + {} + + void Record(T /*value*/) noexcept override {} +#endif }; template @@ -64,6 +71,23 @@ class NoopUpDownCounter : public UpDownCounter {} }; +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + +template +class NoopGauge : public Gauge +{ +public: + NoopGauge(nostd::string_view /* name */, + nostd::string_view /* description */, + nostd::string_view /* unit */) noexcept + {} + void Record(T /* value */, + const common::KeyValueIterable * /* attributes */, + const context::Context * /* context */) noexcept override + {} +}; +#endif + class NoopObservableInstrument : public ObservableInstrument { public: @@ -133,6 +157,25 @@ class NoopMeter final : public Meter return nostd::unique_ptr>{new NoopHistogram(name, description, unit)}; } +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + + nostd::unique_ptr> CreateInt64Gauge( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override + { + return nostd::unique_ptr>(new NoopGauge(name, description, unit)); + } + + nostd::unique_ptr> CreateDoubleGauge(nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override + { + return nostd::unique_ptr>(new NoopGauge(name, description, unit)); + } + +#endif + nostd::shared_ptr CreateInt64ObservableGauge( nostd::string_view name, nostd::string_view description = "", diff --git a/api/include/opentelemetry/metrics/sync_instruments.h b/api/include/opentelemetry/metrics/sync_instruments.h index b26e527c2c..43a5d69fc6 100644 --- a/api/include/opentelemetry/metrics/sync_instruments.h +++ b/api/include/opentelemetry/metrics/sync_instruments.h @@ -22,31 +22,44 @@ class SynchronousInstrument virtual ~SynchronousInstrument() = default; }; +/* A Counter instrument that adds values. */ + template class Counter : public SynchronousInstrument { public: /** - * Add adds the value to the counter's sum + * Record a value * * @param value The increment amount. MUST be non-negative. */ virtual void Add(T value) noexcept = 0; + /** + * Record a value + * + * @param value The increment amount. MUST be non-negative. + * @param context The explicit context to associate with this measurement. + */ virtual void Add(T value, const context::Context &context) noexcept = 0; /** - * Add adds the value to the counter's sum. The attributes should contain - * the keys and values to be associated with this value. Counters only - * accept positive valued updates. + * Record a value with a set of attributes. * * @param value The increment amount. MUST be non-negative. - * @param attributes the set of attributes, as key-value pairs + * @param attributes A set of attributes to associate with the value. */ virtual void Add(T value, const common::KeyValueIterable &attributes) noexcept = 0; + /** + * Record a value with a set of attributes. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ virtual void Add(T value, const common::KeyValueIterable &attributes, const context::Context &context) noexcept = 0; @@ -55,8 +68,7 @@ class Counter : public SynchronousInstrument nostd::enable_if_t::value> * = nullptr> void Add(T value, const U &attributes) noexcept { - auto context = context::Context{}; - this->Add(value, common::KeyValueIterableView{attributes}, context); + this->Add(value, common::KeyValueIterableView{attributes}); } template > attributes) noexcept { - auto context = context::Context{}; - this->Add(value, - nostd::span>{ - attributes.begin(), attributes.end()}, - context); + this->Add(value, nostd::span>{ + attributes.begin(), attributes.end()}); } void Add(T value, @@ -94,10 +103,45 @@ template class Histogram : public SynchronousInstrument { public: +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + /** + * @since ABI_VERSION 2 + * Records a value. + * + * @param value The measurement value. MUST be non-negative. + */ + virtual void Record(T value) noexcept = 0; + + /** + * @since ABI_VERSION 2 + * Records a value with a set of attributes. + * + * @param value The measurement value. MUST be non-negative. + * @param attribute A set of attributes to associate with the value. + */ + virtual void Record(T value, const common::KeyValueIterable &attribute) noexcept = 0; + + template ::value> * = nullptr> + void Record(T value, const U &attributes) noexcept + { + this->Record(value, common::KeyValueIterableView{attributes}); + } + + void Record(T value, + std::initializer_list> + attributes) noexcept + { + this->Record(value, nostd::span>{ + attributes.begin(), attributes.end()}); + } +#endif + /** * Records a value. * * @param value The measurement value. MUST be non-negative. + * @param context The explicit context to associate with this measurement. */ virtual void Record(T value, const context::Context &context) noexcept = 0; @@ -105,7 +149,8 @@ class Histogram : public SynchronousInstrument * Records a value with a set of attributes. * * @param value The measurement value. MUST be non-negative. - * @param attributes A set of attributes to associate with the count. + * @param attributes A set of attributes to associate with the value.. + * @param context The explicit context to associate with this measurement. */ virtual void Record(T value, const common::KeyValueIterable &attributes, @@ -137,22 +182,35 @@ class UpDownCounter : public SynchronousInstrument { public: /** - * Adds a value. + * Record a value. * - * @param value The amount of the measurement. + * @param value The increment amount. May be positive, negative or zero. */ virtual void Add(T value) noexcept = 0; + /** + * Record a value. + * + * @param value The increment amount. May be positive, negative or zero. + * @param context The explicit context to associate with this measurement. + */ virtual void Add(T value, const context::Context &context) noexcept = 0; /** - * Add a value with a set of attributes. + * Record a value with a set of attributes. * * @param value The increment amount. May be positive, negative or zero. * @param attributes A set of attributes to associate with the count. */ virtual void Add(T value, const common::KeyValueIterable &attributes) noexcept = 0; + /** + * Record a value with a set of attributes. + * + * @param value The increment amount. May be positive, negative or zero. + * @param attributes A set of attributes to associate with the count. + * @param context The explicit context to associate with this measurement. + */ virtual void Add(T value, const common::KeyValueIterable &attributes, const context::Context &context) noexcept = 0; @@ -161,8 +219,7 @@ class UpDownCounter : public SynchronousInstrument nostd::enable_if_t::value> * = nullptr> void Add(T value, const U &attributes) noexcept { - auto context = context::Context{}; - this->Add(value, common::KeyValueIterableView{attributes}, context); + this->Add(value, common::KeyValueIterableView{attributes}); } template > attributes) noexcept { - auto context = context::Context{}; - this->Add(value, - nostd::span>{ - attributes.begin(), attributes.end()}, - context); + this->Add(value, nostd::span>{ + attributes.begin(), attributes.end()}); } void Add(T value, @@ -194,5 +248,105 @@ class UpDownCounter : public SynchronousInstrument } }; +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + +/** An Gauge instrument that records value. + * @since ABI_VERSION 2 + */ + +template +class Gauge : public SynchronousInstrument +{ +public: + /** + * Record a value with a set of attributes. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + virtual void Record(T value, + const common::KeyValueIterable *attributes, + const context::Context *context) noexcept = 0; + + /** + * Record a value with a set of attributes. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + void Record(T value, + const common::KeyValueIterable &attributes, + const context::Context &context) noexcept + { + this->Record(value, &attributes, &context); + } + + /** + * Record a value + * + * @param value The increment amount. MUST be non-negative. + */ + void Record(T value) noexcept { this->Record(value, nullptr, nullptr); } + + /** + * Record a value + * + * @param value The increment amount. MUST be non-negative. + * @param context The explicit context to associate with this measurement. + */ + void Record(T value, const context::Context &context) noexcept + { + this->Record(value, nullptr, &context); + } + + /** + * Record a value with a set of attributes. + * + * @param value The increment amount. MUST be non-negative. + * @param attributes A set of attributes to associate with the value. + */ + + void Record(T value, const common::KeyValueIterable &attributes) noexcept + { + this->Record(value, &attributes, nullptr); + } + + template ::value> * = nullptr> + void Record(T value, const U &attributes) noexcept + { + this->Record(value, common::KeyValueIterableView{attributes}); + } + + template ::value> * = nullptr> + void Record(T value, const U &attributes, const context::Context &context) noexcept + { + this->Record(value, common::KeyValueIterableView{attributes}, context); + } + + void Record(T value, + std::initializer_list> + attributes) noexcept + { + this->Record(value, nostd::span>{ + attributes.begin(), attributes.end()}); + } + + void Record( + T value, + std::initializer_list> attributes, + const context::Context &context) noexcept + { + this->Record(value, + nostd::span>{ + attributes.begin(), attributes.end()}, + context); + } +}; +#endif + } // namespace metrics OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/src/otlp_metric_utils.cc b/exporters/otlp/src/otlp_metric_utils.cc index 50c5fdd9cc..f78a9618a3 100644 --- a/exporters/otlp/src/otlp_metric_utils.cc +++ b/exporters/otlp/src/otlp_metric_utils.cc @@ -39,7 +39,8 @@ metric_sdk::AggregationType OtlpMetricUtils::GetAggregationType( { return metric_sdk::AggregationType::kHistogram; } - else if (instrument_type == metric_sdk::InstrumentType::kObservableGauge) + else if (instrument_type == metric_sdk::InstrumentType::kObservableGauge || + instrument_type == metric_sdk::InstrumentType::kGauge) { return metric_sdk::AggregationType::kLastValue; } @@ -269,6 +270,7 @@ sdk::metrics::AggregationTemporality OtlpMetricUtils::DeltaTemporalitySelector( case sdk::metrics::InstrumentType::kObservableCounter: case sdk::metrics::InstrumentType::kHistogram: case sdk::metrics::InstrumentType::kObservableGauge: + case sdk::metrics::InstrumentType::kGauge: return sdk::metrics::AggregationTemporality::kDelta; case sdk::metrics::InstrumentType::kUpDownCounter: case sdk::metrics::InstrumentType::kObservableUpDownCounter: @@ -292,6 +294,7 @@ sdk::metrics::AggregationTemporality OtlpMetricUtils::LowMemoryTemporalitySelect case sdk::metrics::InstrumentType::kHistogram: return sdk::metrics::AggregationTemporality::kDelta; case sdk::metrics::InstrumentType::kObservableCounter: + case sdk::metrics::InstrumentType::kGauge: case sdk::metrics::InstrumentType::kObservableGauge: case sdk::metrics::InstrumentType::kUpDownCounter: case sdk::metrics::InstrumentType::kObservableUpDownCounter: diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h b/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h index 4f3346707f..b33afb9d4e 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h @@ -180,6 +180,7 @@ class DefaultAggregation return AggregationType::kSum; case InstrumentType::kHistogram: return AggregationType::kHistogram; + case InstrumentType::kGauge: case InstrumentType::kObservableGauge: return AggregationType::kLastValue; default: diff --git a/sdk/include/opentelemetry/sdk/metrics/instruments.h b/sdk/include/opentelemetry/sdk/metrics/instruments.h index 84244128a4..375c4d70e8 100644 --- a/sdk/include/opentelemetry/sdk/metrics/instruments.h +++ b/sdk/include/opentelemetry/sdk/metrics/instruments.h @@ -19,6 +19,7 @@ enum class InstrumentType kCounter, kHistogram, kUpDownCounter, + kGauge, kObservableCounter, kObservableGauge, kObservableUpDownCounter diff --git a/sdk/include/opentelemetry/sdk/metrics/meter.h b/sdk/include/opentelemetry/sdk/metrics/meter.h index 7e89d444ab..fda25d0112 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter.h @@ -74,6 +74,18 @@ class Meter final : public opentelemetry::metrics::Meter nostd::string_view description = "", nostd::string_view unit = "") noexcept override; +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + nostd::unique_ptr> CreateInt64Gauge( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; + + nostd::unique_ptr> CreateDoubleGauge( + nostd::string_view name, + nostd::string_view description = "", + nostd::string_view unit = "") noexcept override; +#endif + nostd::shared_ptr CreateInt64ObservableGauge( nostd::string_view name, nostd::string_view description = "", diff --git a/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h b/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h index 825547a846..9f7485b970 100644 --- a/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h +++ b/sdk/include/opentelemetry/sdk/metrics/sync_instruments.h @@ -33,61 +33,22 @@ class Synchronous std::unique_ptr storage_; }; -template -class LongCounter : public Synchronous, public opentelemetry::metrics::Counter +class LongCounter : public Synchronous, public opentelemetry::metrics::Counter { public: LongCounter(InstrumentDescriptor instrument_descriptor, - std::unique_ptr storage) - : Synchronous(instrument_descriptor, std::move(storage)) - { - if (!storage_) - { - OTEL_INTERNAL_LOG_ERROR("[LongCounter::LongCounter] - Error during constructing LongCounter." - << "The metric storage is invalid" - << "No value will be added"); - } - } - - void Add(T value, const opentelemetry::common::KeyValueIterable &attributes) noexcept override - { - if (!storage_) - { - return; - } - auto context = opentelemetry::context::Context{}; - return storage_->RecordLong(value, attributes, context); - } - - void Add(T value, + std::unique_ptr storage); + + void Add(uint64_t value, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override; + + void Add(uint64_t value, const opentelemetry::common::KeyValueIterable &attributes, - const opentelemetry::context::Context &context) noexcept override - { - if (!storage_) - { - return; - } - return storage_->RecordLong(value, attributes, context); - } - - void Add(T value) noexcept override - { - auto context = opentelemetry::context::Context{}; - if (!storage_) - { - return; - } - return storage_->RecordLong(value, context); - } - - void Add(T value, const opentelemetry::context::Context &context) noexcept override - { - if (!storage_) - { - return; - } - return storage_->RecordLong(value, context); - } + const opentelemetry::context::Context &context) noexcept override; + + void Add(uint64_t value) noexcept override; + + void Add(uint64_t value, const opentelemetry::context::Context &context) noexcept override; }; class DoubleCounter : public Synchronous, public opentelemetry::metrics::Counter @@ -139,48 +100,24 @@ class DoubleUpDownCounter : public Synchronous, public opentelemetry::metrics::U void Add(double value, const opentelemetry::context::Context &context) noexcept override; }; -template -class LongHistogram : public Synchronous, public opentelemetry::metrics::Histogram +class LongHistogram : public Synchronous, public opentelemetry::metrics::Histogram { public: LongHistogram(InstrumentDescriptor instrument_descriptor, - std::unique_ptr storage) - : Synchronous(instrument_descriptor, std::move(storage)) - { - if (!storage_) - { - OTEL_INTERNAL_LOG_ERROR( - "[LongHistogram::LongHistogram] - Error during constructing LongHistogram." - << "The metric storage is invalid" - << "No value will be added"); - } - } - - void Record(T value, + std::unique_ptr storage); + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + void Record(uint64_t value, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override; + + void Record(uint64_t value) noexcept override; +#endif + + void Record(uint64_t value, const opentelemetry::common::KeyValueIterable &attributes, - const opentelemetry::context::Context &context) noexcept override - { - if (value < 0) - { - OTEL_INTERNAL_LOG_WARN( - "[LongHistogram::Record(value, attributes)] negative value provided to histogram Name:" - << instrument_descriptor_.name_ << " Value:" << value); - return; - } - return storage_->RecordLong(value, attributes, context); - } - - void Record(T value, const opentelemetry::context::Context &context) noexcept override - { - if (value < 0) - { - OTEL_INTERNAL_LOG_WARN( - "[LongHistogram::Record(value)] negative value provided to histogram Name:" - << instrument_descriptor_.name_ << " Value:" << value); - return; - } - return storage_->RecordLong(value, context); - } + const opentelemetry::context::Context &context) noexcept override; + + void Record(uint64_t value, const opentelemetry::context::Context &context) noexcept override; }; class DoubleHistogram : public Synchronous, public opentelemetry::metrics::Histogram @@ -189,6 +126,13 @@ class DoubleHistogram : public Synchronous, public opentelemetry::metrics::Histo DoubleHistogram(InstrumentDescriptor instrument_descriptor, std::unique_ptr storage); +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + void Record(double value, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override; + + void Record(double value) noexcept override; +#endif + void Record(double value, const opentelemetry::common::KeyValueIterable &attributes, const opentelemetry::context::Context &context) noexcept override; @@ -196,6 +140,31 @@ class DoubleHistogram : public Synchronous, public opentelemetry::metrics::Histo void Record(double value, const opentelemetry::context::Context &context) noexcept override; }; +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + +class LongGauge : public Synchronous, public opentelemetry::metrics::Gauge +{ +public: + LongGauge(InstrumentDescriptor instrument_descriptor, + std::unique_ptr storage); + + void Record(uint64_t value, + const opentelemetry::common::KeyValueIterable *attributes, + const opentelemetry::context::Context *context) noexcept override; +}; + +class DoubleGauge : public Synchronous, public opentelemetry::metrics::Gauge +{ +public: + DoubleGauge(InstrumentDescriptor instrument_descriptor, + std::unique_ptr storage); + + void Record(double value, + const opentelemetry::common::KeyValueIterable *attributes, + const opentelemetry::context::Context *context) noexcept override; +}; +#endif + } // namespace metrics } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index 4f7c4c1207..9cc09e1119 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -52,7 +52,7 @@ nostd::unique_ptr> Meter::CreateUInt64Counter( std::string{unit.data(), unit.size()}, InstrumentType::kCounter, InstrumentValueType::kLong}; auto storage = RegisterSyncMetricStorage(instrument_descriptor); return nostd::unique_ptr>( - new LongCounter(instrument_descriptor, std::move(storage))); + new LongCounter(instrument_descriptor, std::move(storage))); } nostd::unique_ptr> Meter::CreateDoubleCounter( @@ -138,7 +138,7 @@ nostd::unique_ptr> Meter::CreateUInt64Histogram( InstrumentValueType::kLong}; auto storage = RegisterSyncMetricStorage(instrument_descriptor); return nostd::unique_ptr>{ - new LongHistogram(instrument_descriptor, std::move(storage))}; + new LongHistogram(instrument_descriptor, std::move(storage))}; } nostd::unique_ptr> Meter::CreateDoubleHistogram( @@ -163,6 +163,51 @@ nostd::unique_ptr> Meter::CreateDoubleHistogram( new DoubleHistogram(instrument_descriptor, std::move(storage))}; } +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + +nostd::unique_ptr> Meter::CreateInt64Gauge( + nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + if (!ValidateInstrument(name, description, unit)) + { + OTEL_INTERNAL_LOG_ERROR("Meter::CreateInt64Gauge - failed. Invalid parameters." + << name << " " << description << " " << unit + << ". Measurements won't be recorded."); + return nostd::unique_ptr>( + new metrics::NoopGauge(name, description, unit)); + } + InstrumentDescriptor instrument_descriptor = { + std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, + std::string{unit.data(), unit.size()}, InstrumentType::kGauge, InstrumentValueType::kLong}; + auto storage = RegisterSyncMetricStorage(instrument_descriptor); + return nostd::unique_ptr>{ + new LongGauge(instrument_descriptor, std::move(storage))}; +} + +nostd::unique_ptr> Meter::CreateDoubleGauge( + nostd::string_view name, + nostd::string_view description, + nostd::string_view unit) noexcept +{ + if (!ValidateInstrument(name, description, unit)) + { + OTEL_INTERNAL_LOG_ERROR("Meter::CreateDoubleGauge - failed. Invalid parameters." + << name << " " << description << " " << unit + << ". Measurements won't be recorded."); + return nostd::unique_ptr>( + new metrics::NoopGauge(name, description, unit)); + } + InstrumentDescriptor instrument_descriptor = { + std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, + std::string{unit.data(), unit.size()}, InstrumentType::kGauge, InstrumentValueType::kLong}; + auto storage = RegisterSyncMetricStorage(instrument_descriptor); + return nostd::unique_ptr>{ + new DoubleGauge(instrument_descriptor, std::move(storage))}; +} +#endif + nostd::shared_ptr Meter::CreateInt64ObservableGauge( nostd::string_view name, nostd::string_view description, diff --git a/sdk/src/metrics/sync_instruments.cc b/sdk/src/metrics/sync_instruments.cc index 6fe72b55bf..511976ba80 100644 --- a/sdk/src/metrics/sync_instruments.cc +++ b/sdk/src/metrics/sync_instruments.cc @@ -10,27 +10,94 @@ namespace sdk { namespace metrics { + +LongCounter::LongCounter(InstrumentDescriptor instrument_descriptor, + std::unique_ptr storage) + : Synchronous(instrument_descriptor, std::move(storage)) +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_ERROR("[LongCounter::LongCounter] - Error constructing LongCounter." + << "The metric storage is invalid for " << instrument_descriptor.name_); + } +} + +void LongCounter::Add(uint64_t value, + const opentelemetry::common::KeyValueIterable &attributes) noexcept +{ + auto context = opentelemetry::context::Context{}; + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongCounter::Add(V,A)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordLong(value, attributes, context); +} + +void LongCounter::Add(uint64_t value, + const opentelemetry::common::KeyValueIterable &attributes, + const opentelemetry::context::Context &context) noexcept +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongCounter::Add(V,A,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordLong(value, attributes, context); +} + +void LongCounter::Add(uint64_t value) noexcept +{ + auto context = opentelemetry::context::Context{}; + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongCounter::Add(V)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordLong(value, context); +} + +void LongCounter::Add(uint64_t value, const opentelemetry::context::Context &context) noexcept +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongCounter::Add(V,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordLong(value, context); +} + DoubleCounter::DoubleCounter(InstrumentDescriptor instrument_descriptor, std::unique_ptr storage) : Synchronous(instrument_descriptor, std::move(storage)) { if (!storage_) { - OTEL_INTERNAL_LOG_ERROR( - "[DoubleCounter::DoubleCounter] - Error during constructing DoubleCounter." - << "The metric storage is invalid" - << "No value will be added"); + OTEL_INTERNAL_LOG_ERROR("[DoubleCounter::DoubleCounter] - Error constructing DoubleCounter." + << "The metric storage is invalid for " << instrument_descriptor.name_); } } void DoubleCounter::Add(double value, const opentelemetry::common::KeyValueIterable &attributes) noexcept { - auto context = opentelemetry::context::Context{}; + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V,A)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); + return; + } if (!storage_) { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V,A)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } + auto context = opentelemetry::context::Context{}; return storage_->RecordDouble(value, attributes, context); } @@ -38,8 +105,16 @@ void DoubleCounter::Add(double value, const opentelemetry::common::KeyValueIterable &attributes, const opentelemetry::context::Context &context) noexcept { + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V,A,C)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); + return; + } if (!storage_) { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V,A,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordDouble(value, attributes, context); @@ -47,18 +122,34 @@ void DoubleCounter::Add(double value, void DoubleCounter::Add(double value) noexcept { - auto context = opentelemetry::context::Context{}; + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); + return; + } if (!storage_) { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } + auto context = opentelemetry::context::Context{}; return storage_->RecordDouble(value, context); } void DoubleCounter::Add(double value, const opentelemetry::context::Context &context) noexcept { + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); + return; + } if (!storage_) { + OTEL_INTERNAL_LOG_WARN("[DoubleCounter::Add(V,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordDouble(value, context); @@ -71,9 +162,8 @@ LongUpDownCounter::LongUpDownCounter(InstrumentDescriptor instrument_descriptor, if (!storage_) { OTEL_INTERNAL_LOG_ERROR( - "[LongUpDownCounter::LongUpDownCounter] - Error during constructing LongUpDownCounter." - << "The metric storage is invalid" - << "No value will be added"); + "[LongUpDownCounter::LongUpDownCounter] - Error constructing LongUpDownCounter." + << "The metric storage is invalid for " << instrument_descriptor.name_); } } @@ -83,6 +173,9 @@ void LongUpDownCounter::Add(int64_t value, auto context = opentelemetry::context::Context{}; if (!storage_) { + OTEL_INTERNAL_LOG_WARN( + "[LongUpDownCounter::Add(V,A)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordLong(value, attributes, context); @@ -94,6 +187,9 @@ void LongUpDownCounter::Add(int64_t value, { if (!storage_) { + OTEL_INTERNAL_LOG_WARN( + "[LongUpDownCounter::Add(V,A,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordLong(value, attributes, context); @@ -104,6 +200,8 @@ void LongUpDownCounter::Add(int64_t value) noexcept auto context = opentelemetry::context::Context{}; if (!storage_) { + OTEL_INTERNAL_LOG_WARN("[LongUpDownCounter::Add(V)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordLong(value, context); @@ -113,6 +211,9 @@ void LongUpDownCounter::Add(int64_t value, const opentelemetry::context::Context { if (!storage_) { + OTEL_INTERNAL_LOG_WARN( + "[LongUpDownCounter::Add(V,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordLong(value, context); @@ -125,16 +226,20 @@ DoubleUpDownCounter::DoubleUpDownCounter(InstrumentDescriptor instrument_descrip if (!storage_) { OTEL_INTERNAL_LOG_ERROR( - "[DoubleUpDownCounter::DoubleUpDownCounter] - Error during constructing " - "DoubleUpDownCounter." - << "The metric storage is invalid" - << "No value will be added"); + "[DoubleUpDownCounter::DoubleUpDownCounter] - Error constructing DoubleUpDownCounter." + << "The metric storage is invalid for " << instrument_descriptor.name_); } } void DoubleUpDownCounter::Add(double value, const opentelemetry::common::KeyValueIterable &attributes) noexcept { + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN( + "[DoubleUpDownCounter::Add(V,A)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + } auto context = opentelemetry::context::Context{}; return storage_->RecordDouble(value, attributes, context); } @@ -145,6 +250,9 @@ void DoubleUpDownCounter::Add(double value, { if (!storage_) { + OTEL_INTERNAL_LOG_WARN( + "[DoubleUpDownCounter::Add(V,A,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordDouble(value, attributes, context); @@ -154,6 +262,9 @@ void DoubleUpDownCounter::Add(double value) noexcept { if (!storage_) { + OTEL_INTERNAL_LOG_WARN( + "[DoubleUpDownCounter::Add(V)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } auto context = opentelemetry::context::Context{}; @@ -164,11 +275,77 @@ void DoubleUpDownCounter::Add(double value, const opentelemetry::context::Contex { if (!storage_) { + OTEL_INTERNAL_LOG_WARN( + "[DoubleUpDownCounter::Add(V,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); return; } return storage_->RecordDouble(value, context); } +LongHistogram::LongHistogram(InstrumentDescriptor instrument_descriptor, + std::unique_ptr storage) + : Synchronous(instrument_descriptor, std::move(storage)) +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_ERROR("[LongHistogram::LongHistogram] - Error constructing LongHistogram." + << "The metric storage is invalid for " << instrument_descriptor.name_); + } +} + +void LongHistogram::Record(uint64_t value, + const opentelemetry::common::KeyValueIterable &attributes, + const opentelemetry::context::Context &context) noexcept +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN( + "[LongHistogram::Record(V,A,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordLong(value, attributes, context); +} + +void LongHistogram::Record(uint64_t value, const opentelemetry::context::Context &context) noexcept +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongHistogram::Record(V,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordLong(value, context); +} + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 +void LongHistogram::Record(uint64_t value, + const opentelemetry::common::KeyValueIterable &attributes) noexcept +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongHistogram::Record(V,A)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + auto context = opentelemetry::context::Context{}; + return storage_->RecordLong(value, attributes, context); +} + +void LongHistogram::Record(uint64_t value) noexcept +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongHistogram::Record(V)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + auto context = opentelemetry::context::Context{}; + return storage_->RecordLong(value, context); +} +#endif + DoubleHistogram::DoubleHistogram(InstrumentDescriptor instrument_descriptor, std::unique_ptr storage) : Synchronous(instrument_descriptor, std::move(storage)) @@ -176,9 +353,8 @@ DoubleHistogram::DoubleHistogram(InstrumentDescriptor instrument_descriptor, if (!storage_) { OTEL_INTERNAL_LOG_ERROR( - "[DoubleHistogram::DoubleHistogram] - Error during constructing DoubleHistogram." - << "The metric storage is invalid" - << "No value will be added"); + "[DoubleHistogram::DoubleHistogram] - Error constructing DoubleHistogram." + << "The metric storage is invalid for " << instrument_descriptor.name_); } } @@ -186,15 +362,17 @@ void DoubleHistogram::Record(double value, const opentelemetry::common::KeyValueIterable &attributes, const opentelemetry::context::Context &context) noexcept { - if (!storage_) + if (value < 0) { + OTEL_INTERNAL_LOG_WARN( + "[DoubleHistogram::Record(V,A,C)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); return; } - if (value < 0 || std::isnan(value) || std::isinf(value)) + if (!storage_) { OTEL_INTERNAL_LOG_WARN( - "[DoubleHistogram::Record(value, attributes)] negative/nan/infinite value provided to " - "histogram Name:" + "[DoubleHistogram::Record(V,A,C)] Value not recorded - invalid storage for: " << instrument_descriptor_.name_); return; } @@ -203,19 +381,122 @@ void DoubleHistogram::Record(double value, void DoubleHistogram::Record(double value, const opentelemetry::context::Context &context) noexcept { + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN( + "[DoubleHistogram::Record(V,C)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); + return; + } if (!storage_) { + OTEL_INTERNAL_LOG_WARN( + "[DoubleHistogram::Record(V,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordDouble(value, context); +} + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 +void DoubleHistogram::Record(double value, + const opentelemetry::common::KeyValueIterable &attributes) noexcept +{ + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN( + "[DoubleHistogram::Record(V,A)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); return; } - if (value < 0 || std::isnan(value) || std::isinf(value)) + if (!storage_) { OTEL_INTERNAL_LOG_WARN( - "[DoubleHistogram::Record(value)] negative/nan/infinite value provided to histogram Name:" + "[DoubleHistogram::Record(V,A)] Value not recorded - invalid storage for: " << instrument_descriptor_.name_); return; } + auto context = opentelemetry::context::Context{}; + return storage_->RecordDouble(value, attributes, context); +} + +void DoubleHistogram::Record(double value) noexcept +{ + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN("[DoubleHistogram::Record(V)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); + return; + } + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[DoubleHistogram::Record(V)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + auto context = opentelemetry::context::Context{}; return storage_->RecordDouble(value, context); } +#endif + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + +LongGauge::LongGauge(InstrumentDescriptor instrument_descriptor, + std::unique_ptr storage) + : Synchronous(instrument_descriptor, std::move(storage)) +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_ERROR("[LongGauge::LongGauge] - Error during constructing LongGauge." + << "The metric storage is invalid for " << instrument_descriptor.name_); + } +} + +void LongGauge::Record(uint64_t value, + const opentelemetry::common::KeyValueIterable *attributes, + const opentelemetry::context::Context *context) noexcept +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[LongGauge::Record(V,A,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordLong(value, *attributes, *context); +} + +DoubleGauge::DoubleGauge(InstrumentDescriptor instrument_descriptor, + std::unique_ptr storage) + : Synchronous(instrument_descriptor, std::move(storage)) +{ + if (!storage_) + { + OTEL_INTERNAL_LOG_ERROR( + "[DoubleHistogram::DoubleHistogram] - Error during constructing DoubleHistogram." + << "The metric storage is invalid for " << instrument_descriptor.name_); + } +} + +void DoubleGauge::Record(double value, + const opentelemetry::common::KeyValueIterable *attributes, + const opentelemetry::context::Context *context) noexcept +{ + if (value < 0) + { + OTEL_INTERNAL_LOG_WARN("[DoubleGauge::Record(V,A,C)] Value not recorded - negative value for: " + << instrument_descriptor_.name_); + return; + } + if (!storage_) + { + OTEL_INTERNAL_LOG_WARN("[DoubleGauge::Record(V,A,C)] Value not recorded - invalid storage for: " + << instrument_descriptor_.name_); + return; + } + return storage_->RecordDouble(value, *attributes, *context); +} + +#endif } // namespace metrics } // namespace sdk diff --git a/sdk/test/metrics/BUILD b/sdk/test/metrics/BUILD index 3cf379494d..06e277f4a7 100644 --- a/sdk/test/metrics/BUILD +++ b/sdk/test/metrics/BUILD @@ -161,6 +161,22 @@ cc_test( ], ) +cc_test( + name = "sync_metric_storage_gauge_test", + srcs = [ + "sync_metric_storage_gauge_test.cc", + ], + tags = [ + "metrics", + "test", + ], + deps = [ + "metrics_common_test_utils", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "sync_instruments_test", srcs = [ diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt index b30d71ae22..019900a550 100644 --- a/sdk/test/metrics/CMakeLists.txt +++ b/sdk/test/metrics/CMakeLists.txt @@ -18,6 +18,7 @@ foreach( circular_buffer_counter_test histogram_test sync_metric_storage_counter_test + sync_metric_storage_gauge_test sync_metric_storage_histogram_test sync_metric_storage_up_down_counter_test async_metric_storage_test diff --git a/sdk/test/metrics/sync_instruments_test.cc b/sdk/test/metrics/sync_instruments_test.cc index a1ff2325e2..cf0e661aaf 100644 --- a/sdk/test/metrics/sync_instruments_test.cc +++ b/sdk/test/metrics/sync_instruments_test.cc @@ -24,7 +24,7 @@ TEST(SyncInstruments, LongCounter) InstrumentDescriptor instrument_descriptor = { "long_counter", "description", "1", InstrumentType::kCounter, InstrumentValueType::kLong}; std::unique_ptr metric_storage(new SyncMultiMetricStorage()); - LongCounter counter(instrument_descriptor, std::move(metric_storage)); + LongCounter counter(instrument_descriptor, std::move(metric_storage)); counter.Add(10); counter.Add(10, opentelemetry::context::Context{}); @@ -71,6 +71,17 @@ TEST(SyncInstruments, LongUpDownCounter) counter.Add(10, opentelemetry::common::KeyValueIterableView({})); counter.Add(10, opentelemetry::common::KeyValueIterableView({}), opentelemetry::context::Context{}); + // negative values + counter.Add(-10); + counter.Add(-10, opentelemetry::context::Context{}); + + counter.Add(-10, + opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}})); + counter.Add(-10, opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), + opentelemetry::context::Context{}); + counter.Add(-10, opentelemetry::common::KeyValueIterableView({})); + counter.Add(-10, opentelemetry::common::KeyValueIterableView({}), + opentelemetry::context::Context{}); } TEST(SyncInstruments, DoubleUpDownCounter) @@ -98,9 +109,8 @@ TEST(SyncInstruments, LongHistogram) InstrumentDescriptor instrument_descriptor = { "long_histogram", "description", "1", InstrumentType::kHistogram, InstrumentValueType::kLong}; std::unique_ptr metric_storage(new SyncMultiMetricStorage()); - LongHistogram histogram(instrument_descriptor, std::move(metric_storage)); + LongHistogram histogram(instrument_descriptor, std::move(metric_storage)); histogram.Record(10, opentelemetry::context::Context{}); - histogram.Record(-10, opentelemetry::context::Context{}); // This is ignored histogram.Record(10, opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), @@ -129,3 +139,45 @@ TEST(SyncInstruments, DoubleHistogram) histogram.Record(10.10, opentelemetry::common::KeyValueIterableView({}), opentelemetry::context::Context{}); } + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 +TEST(SyncInstruments, DoubleGauge) +{ + InstrumentDescriptor instrument_descriptor = { + "double_gauge", "description", "1", InstrumentType::kGauge, InstrumentValueType::kDouble}; + std::unique_ptr metric_storage(new SyncMultiMetricStorage()); + auto gauge = std::unique_ptr>( + new DoubleGauge(instrument_descriptor, std::move(metric_storage))); + EXPECT_NO_THROW(gauge->Record(10.10, opentelemetry::context::Context{})); + EXPECT_NO_THROW(gauge->Record(-10.10, opentelemetry::context::Context{})); // This is ignored. + EXPECT_NO_THROW(gauge->Record(std::numeric_limits::quiet_NaN(), + opentelemetry::context::Context{})); // This is ignored too + EXPECT_NO_THROW(gauge->Record(std::numeric_limits::infinity(), + opentelemetry::context::Context{})); // This is ignored too + EXPECT_NO_THROW(gauge->Record( + 10.10, opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), + opentelemetry::context::Context{})); + EXPECT_NO_THROW(gauge->Record(10.10, opentelemetry::common::KeyValueIterableView({}), + opentelemetry::context::Context{})); +} + +TEST(SyncInstruments, LongGauge) +{ + InstrumentDescriptor instrument_descriptor = {"double_gauge", "description", "1", + InstrumentType::kGauge, InstrumentValueType::kLong}; + std::unique_ptr metric_storage(new SyncMultiMetricStorage()); + auto gauge = std::unique_ptr>( + new LongGauge(instrument_descriptor, std::move(metric_storage))); + EXPECT_NO_THROW(gauge->Record(10, opentelemetry::context::Context{})); + EXPECT_NO_THROW(gauge->Record(std::numeric_limits::quiet_NaN(), + opentelemetry::context::Context{})); // This is ignored too + EXPECT_NO_THROW(gauge->Record(std::numeric_limits::infinity(), + opentelemetry::context::Context{})); // This is ignored too + + EXPECT_NO_THROW(gauge->Record( + 10, opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), + opentelemetry::context::Context{})); + EXPECT_NO_THROW(gauge->Record(10, opentelemetry::common::KeyValueIterableView({}), + opentelemetry::context::Context{})); +} +#endif diff --git a/sdk/test/metrics/sync_metric_storage_gauge_test.cc b/sdk/test/metrics/sync_metric_storage_gauge_test.cc new file mode 100644 index 0000000000..ec2223da89 --- /dev/null +++ b/sdk/test/metrics/sync_metric_storage_gauge_test.cc @@ -0,0 +1,111 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "common.h" + +#include "opentelemetry/common/key_value_iterable_view.h" +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/sdk/metrics/exemplar/histogram_exemplar_reservoir.h" +#include "opentelemetry/sdk/metrics/instruments.h" +#include "opentelemetry/sdk/metrics/state/sync_metric_storage.h" +#include "opentelemetry/sdk/metrics/view/attributes_processor.h" + +#include +#include +#include + +using namespace opentelemetry::sdk::metrics; +using namespace opentelemetry::common; +using M = std::map; +namespace nostd = opentelemetry::nostd; + +class WritableMetricStorageGaugeTestFixture + : public ::testing::TestWithParam +{}; + +TEST_P(WritableMetricStorageGaugeTestFixture, LongGaugeLastValueAggregation) +{ +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + AggregationTemporality temporality = GetParam(); + auto sdk_start_ts = std::chrono::system_clock::now(); + InstrumentDescriptor instr_desc = {"name", "desc", "1unit", InstrumentType::kGauge, + InstrumentValueType::kLong}; + std::map attributes_roomA = {{"Room.Id", "Rack A"}}; + std::map attributes_roomB = {{"Room.Id", "Rack B"}}; + + std::unique_ptr default_attributes_processor{ + new DefaultAttributesProcessor{}}; + opentelemetry::sdk::metrics::SyncMetricStorage storage( + instr_desc, AggregationType::kLastValue, default_attributes_processor.get(), + ExemplarReservoir::GetNoExemplarReservoir(), nullptr); + + uint64_t noiselevel_1_roomA = 10, noiselevel_1_roomB = 30; + storage.RecordLong(noiselevel_1_roomA, + KeyValueIterableView>(attributes_roomA), + opentelemetry::context::Context{}); + storage.RecordLong(noiselevel_1_roomB, + KeyValueIterableView>(attributes_roomB), + opentelemetry::context::Context{}); + + uint64_t noiselevel_2_roomA = 12, noiselevel_2_roomB = 29; + storage.RecordLong(noiselevel_2_roomA, + KeyValueIterableView>(attributes_roomA), + opentelemetry::context::Context{}); + storage.RecordLong(noiselevel_2_roomB, + KeyValueIterableView>(attributes_roomB), + opentelemetry::context::Context{}); + + std::shared_ptr collector(new MockCollectorHandle(temporality)); + std::vector> collectors; + collectors.push_back(collector); + + // Some computation here + auto collection_ts = std::chrono::system_clock::now(); + size_t count_attributes = 0; + storage.Collect( + collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData data) { + for (auto data_attr : data.point_data_attr_) + { + auto lastvalue_data = opentelemetry::nostd::get(data_attr.point_data); + if (opentelemetry::nostd::get( + data_attr.attributes.find("Room.Id")->second) == "Rack A") + { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(opentelemetry::nostd::get(lastvalue_data.value_), + noiselevel_2_roomA); + } + else + { + EXPECT_EQ(opentelemetry::nostd::get(lastvalue_data.value_), + noiselevel_2_roomA - noiselevel_1_roomA); + } + count_attributes++; + } + else if (opentelemetry::nostd::get( + data_attr.attributes.find("Room.Id")->second) == "Rack B") + { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(opentelemetry::nostd::get(lastvalue_data.value_), + noiselevel_2_roomB); + } + else + { + EXPECT_EQ(opentelemetry::nostd::get(lastvalue_data.value_), + noiselevel_2_roomB - noiselevel_1_roomB); + } + count_attributes++; + } + } + return true; + }); + EXPECT_EQ(count_attributes, 2); // RackA and RackB +#else + EXPECT_TRUE(true); +#endif +} + +INSTANTIATE_TEST_SUITE_P(WritableMetricStorageTestLong, + WritableMetricStorageGaugeTestFixture, + ::testing::Values(AggregationTemporality::kCumulative));