From ff8a59eb131ffd1c97cbe6abb33affc2d1c7d7c5 Mon Sep 17 00:00:00 2001 From: Mindaugas Vinkelis Date: Fri, 6 Dec 2024 09:45:17 +0200 Subject: [PATCH] Gauge start-time is optional --- opentelemetry-proto/src/transform/metrics.rs | 2 +- opentelemetry-sdk/src/metrics/data/mod.rs | 76 +++++++--- .../src/metrics/internal/aggregate.rs | 16 +- .../metrics/internal/exponential_histogram.rs | 34 ++++- .../src/metrics/internal/last_value.rs | 14 +- .../src/metrics/internal/precomputed_sum.rs | 6 +- opentelemetry-sdk/src/metrics/internal/sum.rs | 6 +- opentelemetry-sdk/src/metrics/mod.rs | 138 +++++++++++------- opentelemetry-stdout/src/metrics/exporter.rs | 29 +++- 9 files changed, 217 insertions(+), 104 deletions(-) diff --git a/opentelemetry-proto/src/transform/metrics.rs b/opentelemetry-proto/src/transform/metrics.rs index 333922bb7b..15d97a2dbe 100644 --- a/opentelemetry-proto/src/transform/metrics.rs +++ b/opentelemetry-proto/src/transform/metrics.rs @@ -319,7 +319,7 @@ pub mod tonic { .iter() .map(|dp| TonicNumberDataPoint { attributes: dp.attributes.iter().map(Into::into).collect(), - start_time_unix_nano: to_nanos(dp.start_time), + start_time_unix_nano: dp.start_time.map(to_nanos).unwrap_or_default(), time_unix_nano: to_nanos(dp.time), exemplars: dp.exemplars.iter().map(Into::into).collect(), flags: TonicDataPointFlags::default() as u32, diff --git a/opentelemetry-sdk/src/metrics/data/mod.rs b/opentelemetry-sdk/src/metrics/data/mod.rs index bc1fe4d4af..7590493931 100644 --- a/opentelemetry-sdk/src/metrics/data/mod.rs +++ b/opentelemetry-sdk/src/metrics/data/mod.rs @@ -53,35 +53,42 @@ pub trait Aggregation: fmt::Debug + any::Any + Send + Sync { fn as_mut(&mut self) -> &mut dyn any::Any; } -/// A measurement of the current value of an instrument. -#[derive(Debug)] -pub struct Gauge { - /// Represents individual aggregated measurements with unique attributes. - pub data_points: Vec>, +/// DataPoint is a single data point in a time series. +#[derive(Debug, PartialEq)] +pub struct GaugeDataPoint { + /// Attributes is the set of key value pairs that uniquely identify the + /// time series. + pub attributes: Vec, + /// The time when the time series was started. + pub start_time: Option, + /// The time when the time series was recorded. + pub time: SystemTime, + /// The value of this data point. + pub value: T, + /// The sampled [Exemplar]s collected during the time series. + pub exemplars: Vec>, } -impl Aggregation for Gauge { - fn as_any(&self) -> &dyn any::Any { - self - } - fn as_mut(&mut self) -> &mut dyn any::Any { - self +impl Clone for GaugeDataPoint { + fn clone(&self) -> Self { + Self { + attributes: self.attributes.clone(), + start_time: self.start_time, + time: self.time, + value: self.value, + exemplars: self.exemplars.clone(), + } } } -/// Represents the sum of all measurements of values from an instrument. +/// A measurement of the current value of an instrument. #[derive(Debug)] -pub struct Sum { +pub struct Gauge { /// Represents individual aggregated measurements with unique attributes. - pub data_points: Vec>, - /// Describes if the aggregation is reported as the change from the last report - /// time, or the cumulative changes since a fixed start time. - pub temporality: Temporality, - /// Whether this aggregation only increases or decreases. - pub is_monotonic: bool, + pub data_points: Vec>, } -impl Aggregation for Sum { +impl Aggregation for Gauge { fn as_any(&self) -> &dyn any::Any { self } @@ -92,7 +99,7 @@ impl Aggregation for Sum { /// DataPoint is a single data point in a time series. #[derive(Debug, PartialEq)] -pub struct DataPoint { +pub struct SumDataPoint { /// Attributes is the set of key value pairs that uniquely identify the /// time series. pub attributes: Vec, @@ -106,7 +113,7 @@ pub struct DataPoint { pub exemplars: Vec>, } -impl Clone for DataPoint { +impl Clone for SumDataPoint { fn clone(&self) -> Self { Self { attributes: self.attributes.clone(), @@ -118,6 +125,27 @@ impl Clone for DataPoint { } } +/// Represents the sum of all measurements of values from an instrument. +#[derive(Debug)] +pub struct Sum { + /// Represents individual aggregated measurements with unique attributes. + pub data_points: Vec>, + /// Describes if the aggregation is reported as the change from the last report + /// time, or the cumulative changes since a fixed start time. + pub temporality: Temporality, + /// Whether this aggregation only increases or decreases. + pub is_monotonic: bool, +} + +impl Aggregation for Sum { + fn as_any(&self) -> &dyn any::Any { + self + } + fn as_mut(&mut self) -> &mut dyn any::Any { + self + } +} + /// Represents the histogram of all measurements of values from an instrument. #[derive(Debug)] pub struct Histogram { @@ -330,13 +358,13 @@ impl Clone for Exemplar { #[cfg(test)] mod tests { - use super::{DataPoint, Exemplar, ExponentialHistogramDataPoint, HistogramDataPoint}; + use super::{Exemplar, ExponentialHistogramDataPoint, HistogramDataPoint, SumDataPoint}; use opentelemetry::KeyValue; #[test] fn validate_cloning_data_points() { - let data_type = DataPoint { + let data_type = SumDataPoint { attributes: vec![KeyValue::new("key", "value")], start_time: std::time::SystemTime::now(), time: std::time::SystemTime::now(), diff --git a/opentelemetry-sdk/src/metrics/internal/aggregate.rs b/opentelemetry-sdk/src/metrics/internal/aggregate.rs index 369f947d99..3c78682dce 100644 --- a/opentelemetry-sdk/src/metrics/internal/aggregate.rs +++ b/opentelemetry-sdk/src/metrics/internal/aggregate.rs @@ -211,8 +211,8 @@ impl AggregateBuilder { #[cfg(test)] mod tests { use crate::metrics::data::{ - DataPoint, ExponentialBucket, ExponentialHistogram, ExponentialHistogramDataPoint, - Histogram, HistogramDataPoint, Sum, + ExponentialBucket, ExponentialHistogram, ExponentialHistogramDataPoint, GaugeDataPoint, + Histogram, HistogramDataPoint, Sum, SumDataPoint, }; use std::{time::SystemTime, vec}; @@ -222,9 +222,9 @@ mod tests { fn last_value_aggregation() { let (measure, agg) = AggregateBuilder::::new(None, None).last_value(); let mut a = Gauge { - data_points: vec![DataPoint { + data_points: vec![GaugeDataPoint { attributes: vec![KeyValue::new("a", 1)], - start_time: SystemTime::now(), + start_time: Some(SystemTime::now()), time: SystemTime::now(), value: 1u64, exemplars: vec![], @@ -249,14 +249,14 @@ mod tests { AggregateBuilder::::new(Some(temporality), None).precomputed_sum(true); let mut a = Sum { data_points: vec![ - DataPoint { + SumDataPoint { attributes: vec![KeyValue::new("a1", 1)], start_time: SystemTime::now(), time: SystemTime::now(), value: 1u64, exemplars: vec![], }, - DataPoint { + SumDataPoint { attributes: vec![KeyValue::new("a2", 1)], start_time: SystemTime::now(), time: SystemTime::now(), @@ -292,14 +292,14 @@ mod tests { let (measure, agg) = AggregateBuilder::::new(Some(temporality), None).sum(true); let mut a = Sum { data_points: vec![ - DataPoint { + SumDataPoint { attributes: vec![KeyValue::new("a1", 1)], start_time: SystemTime::now(), time: SystemTime::now(), value: 1u64, exemplars: vec![], }, - DataPoint { + SumDataPoint { attributes: vec![KeyValue::new("a2", 1)], start_time: SystemTime::now(), time: SystemTime::now(), diff --git a/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs b/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs index 7975c1419e..4760a8a55c 100644 --- a/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs +++ b/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs @@ -1467,7 +1467,7 @@ mod tests { test_name ); for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { - assert_data_points_eq( + assert_gauge_data_points_eq( a, b, ignore_timestamp, @@ -1494,7 +1494,7 @@ mod tests { test_name ); for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { - assert_data_points_eq( + assert_sum_data_points_eq( a, b, ignore_timestamp, @@ -1554,9 +1554,33 @@ mod tests { } } - fn assert_data_points_eq( - a: &data::DataPoint, - b: &data::DataPoint, + fn assert_sum_data_points_eq( + a: &data::SumDataPoint, + b: &data::SumDataPoint, + ignore_timestamp: bool, + message: &'static str, + test_name: &'static str, + ) { + assert_eq!( + a.attributes, b.attributes, + "{}: {} attributes", + test_name, message + ); + assert_eq!(a.value, b.value, "{}: {} value", test_name, message); + + if !ignore_timestamp { + assert_eq!( + a.start_time, b.start_time, + "{}: {} start time", + test_name, message + ); + assert_eq!(a.time, b.time, "{}: {} time", test_name, message); + } + } + + fn assert_gauge_data_points_eq( + a: &data::GaugeDataPoint, + b: &data::GaugeDataPoint, ignore_timestamp: bool, message: &'static str, test_name: &'static str, diff --git a/opentelemetry-sdk/src/metrics/internal/last_value.rs b/opentelemetry-sdk/src/metrics/internal/last_value.rs index 60e4b68840..b611be71fa 100644 --- a/opentelemetry-sdk/src/metrics/internal/last_value.rs +++ b/opentelemetry-sdk/src/metrics/internal/last_value.rs @@ -1,6 +1,6 @@ use std::{mem::replace, ops::DerefMut, sync::Mutex, time::SystemTime}; -use crate::metrics::data::DataPoint; +use crate::metrics::data::GaugeDataPoint; use opentelemetry::KeyValue; use super::{Aggregator, AtomicTracker, AtomicallyUpdate, Number, ValueMap}; @@ -56,7 +56,7 @@ impl LastValue { self.value_map.measure(measurement, attrs); } - pub(crate) fn compute_aggregation_delta(&self, dest: &mut Vec>) { + pub(crate) fn compute_aggregation_delta(&self, dest: &mut Vec>) { let t = SystemTime::now(); let prev_start = self .start @@ -64,22 +64,22 @@ impl LastValue { .map(|mut start| replace(start.deref_mut(), t)) .unwrap_or(t); self.value_map - .collect_and_reset(dest, |attributes, aggr| DataPoint { + .collect_and_reset(dest, |attributes, aggr| GaugeDataPoint { attributes, - start_time: prev_start, + start_time: Some(prev_start), time: t, value: aggr.value.get_value(), exemplars: vec![], }); } - pub(crate) fn compute_aggregation_cumulative(&self, dest: &mut Vec>) { + pub(crate) fn compute_aggregation_cumulative(&self, dest: &mut Vec>) { let t = SystemTime::now(); let prev_start = self.start.lock().map(|start| *start).unwrap_or(t); self.value_map - .collect_readonly(dest, |attributes, aggr| DataPoint { + .collect_readonly(dest, |attributes, aggr| GaugeDataPoint { attributes, - start_time: prev_start, + start_time: Some(prev_start), time: t, value: aggr.value.get_value(), exemplars: vec![], diff --git a/opentelemetry-sdk/src/metrics/internal/precomputed_sum.rs b/opentelemetry-sdk/src/metrics/internal/precomputed_sum.rs index e5124a8683..a8b04b85cd 100644 --- a/opentelemetry-sdk/src/metrics/internal/precomputed_sum.rs +++ b/opentelemetry-sdk/src/metrics/internal/precomputed_sum.rs @@ -1,6 +1,6 @@ use opentelemetry::KeyValue; -use crate::metrics::data::{self, Aggregation, DataPoint}; +use crate::metrics::data::{self, Aggregation, SumDataPoint}; use crate::metrics::Temporality; use super::{last_value::Assign, AtomicTracker, Number, ValueMap}; @@ -66,7 +66,7 @@ impl PrecomputedSum { let value = aggr.value.get_value(); new_reported.insert(attributes.clone(), value); let delta = value - *reported.get(&attributes).unwrap_or(&T::default()); - DataPoint { + SumDataPoint { attributes, start_time: prev_start, time: t, @@ -107,7 +107,7 @@ impl PrecomputedSum { let prev_start = self.start.lock().map(|start| *start).unwrap_or(t); self.value_map - .collect_readonly(&mut s_data.data_points, |attributes, aggr| DataPoint { + .collect_readonly(&mut s_data.data_points, |attributes, aggr| SumDataPoint { attributes, start_time: prev_start, time: t, diff --git a/opentelemetry-sdk/src/metrics/internal/sum.rs b/opentelemetry-sdk/src/metrics/internal/sum.rs index 5c59845569..eec8f746bc 100644 --- a/opentelemetry-sdk/src/metrics/internal/sum.rs +++ b/opentelemetry-sdk/src/metrics/internal/sum.rs @@ -3,7 +3,7 @@ use std::ops::DerefMut; use std::vec; use std::{sync::Mutex, time::SystemTime}; -use crate::metrics::data::{self, Aggregation, DataPoint}; +use crate::metrics::data::{self, Aggregation, SumDataPoint}; use crate::metrics::Temporality; use opentelemetry::KeyValue; @@ -93,7 +93,7 @@ impl Sum { .map(|mut start| replace(start.deref_mut(), t)) .unwrap_or(t); self.value_map - .collect_and_reset(&mut s_data.data_points, |attributes, aggr| DataPoint { + .collect_and_reset(&mut s_data.data_points, |attributes, aggr| SumDataPoint { attributes, start_time: prev_start, time: t, @@ -130,7 +130,7 @@ impl Sum { let prev_start = self.start.lock().map(|start| *start).unwrap_or(t); self.value_map - .collect_readonly(&mut s_data.data_points, |attributes, aggr| DataPoint { + .collect_readonly(&mut s_data.data_points, |attributes, aggr| SumDataPoint { attributes, start_time: prev_start, time: t, diff --git a/opentelemetry-sdk/src/metrics/mod.rs b/opentelemetry-sdk/src/metrics/mod.rs index 3d2d8af74e..a83cd92fcb 100644 --- a/opentelemetry-sdk/src/metrics/mod.rs +++ b/opentelemetry-sdk/src/metrics/mod.rs @@ -104,11 +104,12 @@ pub enum Temporality { #[cfg(all(test, feature = "testing"))] mod tests { - use self::data::{DataPoint, HistogramDataPoint, ScopeMetrics}; + use self::data::{HistogramDataPoint, ScopeMetrics, SumDataPoint}; use super::*; use crate::metrics::data::ResourceMetrics; use crate::testing::metrics::InMemoryMetricExporterBuilder; use crate::{runtime, testing::metrics::InMemoryMetricExporter}; + use data::GaugeDataPoint; use opentelemetry::metrics::{Counter, Meter, UpDownCounter}; use opentelemetry::InstrumentationScope; use opentelemetry::{metrics::MeterProvider as _, KeyValue}; @@ -465,7 +466,7 @@ mod tests { let data_point = if is_empty_attributes { &sum.data_points[0] } else { - find_datapoint_with_key_value(&sum.data_points, "key1", "value1") + find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected") }; @@ -1096,12 +1097,12 @@ mod tests { assert_eq!(sum.data_points.len(), 2); // find and validate key1=value1 datapoint - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value1") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 5); // find and validate key1=value2 datapoint - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value2") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value2") .expect("datapoint with key1=value2 expected"); assert_eq!(data_point1.value, 3); @@ -1218,12 +1219,15 @@ mod tests { test_context.get_aggregation::>("test_counter", None); assert_eq!(counter_data.data_points.len(), 2); let zero_attribute_datapoint = - find_datapoint_with_no_attributes(&counter_data.data_points) + find_sum_datapoint_with_no_attributes(&counter_data.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 5); - let data_point1 = - find_datapoint_with_key_value(&counter_data.data_points, "key1", "value1") - .expect("datapoint with key1=value1 expected"); + let data_point1 = find_sum_datapoint_with_key_value( + &counter_data.data_points, + "key1", + "value1", + ) + .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 10); } "updown_counter" => { @@ -1231,10 +1235,10 @@ mod tests { test_context.get_aggregation::>("test_updowncounter", None); assert_eq!(updown_counter_data.data_points.len(), 2); let zero_attribute_datapoint = - find_datapoint_with_no_attributes(&updown_counter_data.data_points) + find_sum_datapoint_with_no_attributes(&updown_counter_data.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 15); - let data_point1 = find_datapoint_with_key_value( + let data_point1 = find_sum_datapoint_with_key_value( &updown_counter_data.data_points, "key1", "value1", @@ -1269,12 +1273,15 @@ mod tests { test_context.get_aggregation::>("test_gauge", None); assert_eq!(gauge_data.data_points.len(), 2); let zero_attribute_datapoint = - find_datapoint_with_no_attributes(&gauge_data.data_points) + find_gauge_datapoint_with_no_attributes(&gauge_data.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 35); - let data_point1 = - find_datapoint_with_key_value(&gauge_data.data_points, "key1", "value1") - .expect("datapoint with key1=value1 expected"); + let data_point1 = find_gauge_datapoint_with_key_value( + &gauge_data.data_points, + "key1", + "value1", + ) + .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 40); } _ => panic!("Incorrect instrument kind provided"), @@ -1366,12 +1373,15 @@ mod tests { assert_eq!(counter_data.data_points.len(), 2); assert!(counter_data.is_monotonic); let zero_attribute_datapoint = - find_datapoint_with_no_attributes(&counter_data.data_points) + find_sum_datapoint_with_no_attributes(&counter_data.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 5); - let data_point1 = - find_datapoint_with_key_value(&counter_data.data_points, "key1", "value1") - .expect("datapoint with key1=value1 expected"); + let data_point1 = find_sum_datapoint_with_key_value( + &counter_data.data_points, + "key1", + "value1", + ) + .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 10); } "updown_counter" => { @@ -1380,10 +1390,10 @@ mod tests { assert_eq!(updown_counter_data.data_points.len(), 2); assert!(!updown_counter_data.is_monotonic); let zero_attribute_datapoint = - find_datapoint_with_no_attributes(&updown_counter_data.data_points) + find_sum_datapoint_with_no_attributes(&updown_counter_data.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 15); - let data_point1 = find_datapoint_with_key_value( + let data_point1 = find_sum_datapoint_with_key_value( &updown_counter_data.data_points, "key1", "value1", @@ -1396,12 +1406,15 @@ mod tests { test_context.get_aggregation::>("test_gauge", None); assert_eq!(gauge_data.data_points.len(), 2); let zero_attribute_datapoint = - find_datapoint_with_no_attributes(&gauge_data.data_points) + find_gauge_datapoint_with_no_attributes(&gauge_data.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 25); - let data_point1 = - find_datapoint_with_key_value(&gauge_data.data_points, "key1", "value1") - .expect("datapoint with key1=value1 expected"); + let data_point1 = find_gauge_datapoint_with_key_value( + &gauge_data.data_points, + "key1", + "value1", + ) + .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 30); } _ => panic!("Incorrect instrument kind provided"), @@ -1970,12 +1983,12 @@ mod tests { // find and validate key1=value2 datapoint let data_point1 = - find_datapoint_with_key_value(&gauge_data_point.data_points, "key1", "value1") + find_gauge_datapoint_with_key_value(&gauge_data_point.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 4); let data_point1 = - find_datapoint_with_key_value(&gauge_data_point.data_points, "key1", "value2") + find_gauge_datapoint_with_key_value(&gauge_data_point.data_points, "key1", "value2") .expect("datapoint with key1=value2 expected"); assert_eq!(data_point1.value, 6); @@ -1995,11 +2008,11 @@ mod tests { let gauge = test_context.get_aggregation::>("my_gauge", None); assert_eq!(gauge.data_points.len(), 2); - let data_point1 = find_datapoint_with_key_value(&gauge.data_points, "key1", "value1") + let data_point1 = find_gauge_datapoint_with_key_value(&gauge.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 41); - let data_point1 = find_datapoint_with_key_value(&gauge.data_points, "key1", "value2") + let data_point1 = find_gauge_datapoint_with_key_value(&gauge.data_points, "key1", "value2") .expect("datapoint with key1=value2 expected"); assert_eq!(data_point1.value, 54); } @@ -2029,18 +2042,19 @@ mod tests { if use_empty_attributes { // find and validate zero attribute datapoint - let zero_attribute_datapoint = find_datapoint_with_no_attributes(&gauge.data_points) - .expect("datapoint with no attributes expected"); + let zero_attribute_datapoint = + find_gauge_datapoint_with_no_attributes(&gauge.data_points) + .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 1); } // find and validate key1=value1 datapoint - let data_point1 = find_datapoint_with_key_value(&gauge.data_points, "key1", "value1") + let data_point1 = find_gauge_datapoint_with_key_value(&gauge.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 4); // find and validate key2=value2 datapoint - let data_point2 = find_datapoint_with_key_value(&gauge.data_points, "key2", "value2") + let data_point2 = find_gauge_datapoint_with_key_value(&gauge.data_points, "key2", "value2") .expect("datapoint with key2=value2 expected"); assert_eq!(data_point2.value, 5); @@ -2053,16 +2067,17 @@ mod tests { assert_eq!(gauge.data_points.len(), expected_time_series_count); if use_empty_attributes { - let zero_attribute_datapoint = find_datapoint_with_no_attributes(&gauge.data_points) - .expect("datapoint with no attributes expected"); + let zero_attribute_datapoint = + find_gauge_datapoint_with_no_attributes(&gauge.data_points) + .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 1); } - let data_point1 = find_datapoint_with_key_value(&gauge.data_points, "key1", "value1") + let data_point1 = find_gauge_datapoint_with_key_value(&gauge.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 4); - let data_point2 = find_datapoint_with_key_value(&gauge.data_points, "key2", "value2") + let data_point2 = find_gauge_datapoint_with_key_value(&gauge.data_points, "key2", "value2") .expect("datapoint with key2=value2 expected"); assert_eq!(data_point2.value, 5); } @@ -2101,11 +2116,11 @@ mod tests { } // find and validate key1=value2 datapoint - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value1") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 5); - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value2") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value2") .expect("datapoint with key1=value2 expected"); assert_eq!(data_point1.value, 3); @@ -2125,7 +2140,7 @@ mod tests { let sum = test_context.get_aggregation::>("my_counter", None); assert_eq!(sum.data_points.len(), 2); - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value1") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); if temporality == Temporality::Cumulative { assert_eq!(data_point1.value, 10); @@ -2133,7 +2148,7 @@ mod tests { assert_eq!(data_point1.value, 5); } - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value2") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value2") .expect("datapoint with key1=value2 expected"); if temporality == Temporality::Cumulative { assert_eq!(data_point1.value, 6); @@ -2169,12 +2184,12 @@ mod tests { assert_eq!(sum.data_points.len(), 2002); let data_point = - find_datapoint_with_key_value(&sum.data_points, "otel.metric.overflow", "true") + find_sum_datapoint_with_key_value(&sum.data_points, "otel.metric.overflow", "true") .expect("overflow point expected"); assert_eq!(data_point.value, 300); // let empty_attrs_data_point = &sum.data_points[0]; - let empty_attrs_data_point = find_datapoint_with_no_attributes(&sum.data_points) + let empty_attrs_data_point = find_sum_datapoint_with_no_attributes(&sum.data_points) .expect("Empty attributes point expected"); assert!( empty_attrs_data_point.attributes.is_empty(), @@ -2300,11 +2315,11 @@ mod tests { ); // find and validate key1=value2 datapoint - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value1") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 5); - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value2") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value2") .expect("datapoint with key1=value2 expected"); assert_eq!(data_point1.value, 7); @@ -2324,20 +2339,20 @@ mod tests { let sum = test_context.get_aggregation::>("my_updown_counter", None); assert_eq!(sum.data_points.len(), 2); - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value1") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 10); - let data_point1 = find_datapoint_with_key_value(&sum.data_points, "key1", "value2") + let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value2") .expect("datapoint with key1=value2 expected"); assert_eq!(data_point1.value, 14); } - fn find_datapoint_with_key_value<'a, T>( - data_points: &'a [DataPoint], + fn find_sum_datapoint_with_key_value<'a, T>( + data_points: &'a [SumDataPoint], key: &str, value: &str, - ) -> Option<&'a DataPoint> { + ) -> Option<&'a SumDataPoint> { data_points.iter().find(|&datapoint| { datapoint .attributes @@ -2346,7 +2361,30 @@ mod tests { }) } - fn find_datapoint_with_no_attributes(data_points: &[DataPoint]) -> Option<&DataPoint> { + fn find_gauge_datapoint_with_key_value<'a, T>( + data_points: &'a [GaugeDataPoint], + key: &str, + value: &str, + ) -> Option<&'a GaugeDataPoint> { + data_points.iter().find(|&datapoint| { + datapoint + .attributes + .iter() + .any(|kv| kv.key.as_str() == key && kv.value.as_str() == value) + }) + } + + fn find_sum_datapoint_with_no_attributes( + data_points: &[SumDataPoint], + ) -> Option<&SumDataPoint> { + data_points + .iter() + .find(|&datapoint| datapoint.attributes.is_empty()) + } + + fn find_gauge_datapoint_with_no_attributes( + data_points: &[GaugeDataPoint], + ) -> Option<&GaugeDataPoint> { data_points .iter() .find(|&datapoint| datapoint.attributes.is_empty()) diff --git a/opentelemetry-stdout/src/metrics/exporter.rs b/opentelemetry-stdout/src/metrics/exporter.rs index 27a80d73e8..67dbbf4e94 100644 --- a/opentelemetry-stdout/src/metrics/exporter.rs +++ b/opentelemetry-stdout/src/metrics/exporter.rs @@ -142,12 +142,12 @@ fn print_sum(sum: &data::Sum) { } else { println!("\t\tTemporality : Delta"); } - print_data_points(&sum.data_points); + print_sum_data_points(&sum.data_points); } fn print_gauge(gauge: &data::Gauge) { println!("\t\tGauge DataPoints"); - print_data_points(&gauge.data_points); + print_gauge_data_points(&gauge.data_points); } fn print_histogram(histogram: &data::Histogram) { @@ -160,7 +160,7 @@ fn print_histogram(histogram: &data::Histogram) { print_hist_data_points(&histogram.data_points); } -fn print_data_points(data_points: &[data::DataPoint]) { +fn print_sum_data_points(data_points: &[data::SumDataPoint]) { for (i, data_point) in data_points.iter().enumerate() { println!("\t\tDataPoint #{}", i); let datetime: DateTime = data_point.start_time.into(); @@ -181,6 +181,29 @@ fn print_data_points(data_points: &[data::DataPoint]) { } } +fn print_gauge_data_points(data_points: &[data::GaugeDataPoint]) { + for (i, data_point) in data_points.iter().enumerate() { + println!("\t\tDataPoint #{}", i); + if let Some(start_time) = data_point.start_time { + let datetime: DateTime = start_time.into(); + println!( + "\t\t\tStartTime : {}", + datetime.format("%Y-%m-%d %H:%M:%S%.6f") + ); + } + let datetime: DateTime = data_point.time.into(); + println!( + "\t\t\tEndTime : {}", + datetime.format("%Y-%m-%d %H:%M:%S%.6f") + ); + println!("\t\t\tValue : {:#?}", data_point.value); + println!("\t\t\tAttributes :"); + for kv in data_point.attributes.iter() { + println!("\t\t\t\t -> {}: {}", kv.key, kv.value.as_str()); + } + } +} + fn print_hist_data_points(data_points: &[data::HistogramDataPoint]) { for (i, data_point) in data_points.iter().enumerate() { println!("\t\tDataPoint #{}", i);