diff --git a/opentelemetry-proto/src/transform/metrics.rs b/opentelemetry-proto/src/transform/metrics.rs index 680da03b3f..c040898ec3 100644 --- a/opentelemetry-proto/src/transform/metrics.rs +++ b/opentelemetry-proto/src/transform/metrics.rs @@ -5,13 +5,13 @@ #[allow(deprecated)] #[cfg(feature = "gen-tonic-messages")] pub mod tonic { - use std::any::Any; - use std::fmt; + use std::fmt::Debug; use opentelemetry::{otel_debug, Key, Value}; use opentelemetry_sdk::metrics::data::{ - Exemplar as SdkExemplar, ExponentialHistogram as SdkExponentialHistogram, - Gauge as SdkGauge, Histogram as SdkHistogram, Metric as SdkMetric, ResourceMetrics, + AggregatedMetrics, Exemplar as SdkExemplar, + ExponentialHistogram as SdkExponentialHistogram, Gauge as SdkGauge, + Histogram as SdkHistogram, Metric as SdkMetric, MetricData, ResourceMetrics, ScopeMetrics as SdkScopeMetrics, Sum as SdkSum, }; use opentelemetry_sdk::metrics::Temporality; @@ -152,46 +152,27 @@ pub mod tonic { description: metric.description.to_string(), unit: metric.unit.to_string(), metadata: vec![], // internal and currently unused - data: metric.data.as_any().try_into().ok(), + data: Some(match &metric.data { + AggregatedMetrics::F64(data) => data.into(), + AggregatedMetrics::U64(data) => data.into(), + AggregatedMetrics::I64(data) => data.into(), + }), } } } - impl TryFrom<&dyn Any> for TonicMetricData { - type Error = (); - - fn try_from(data: &dyn Any) -> Result { - if let Some(hist) = data.downcast_ref::>() { - Ok(TonicMetricData::Histogram(hist.into())) - } else if let Some(hist) = data.downcast_ref::>() { - Ok(TonicMetricData::Histogram(hist.into())) - } else if let Some(hist) = data.downcast_ref::>() { - Ok(TonicMetricData::Histogram(hist.into())) - } else if let Some(hist) = data.downcast_ref::>() { - Ok(TonicMetricData::ExponentialHistogram(hist.into())) - } else if let Some(hist) = data.downcast_ref::>() { - Ok(TonicMetricData::ExponentialHistogram(hist.into())) - } else if let Some(hist) = data.downcast_ref::>() { - Ok(TonicMetricData::ExponentialHistogram(hist.into())) - } else if let Some(sum) = data.downcast_ref::>() { - Ok(TonicMetricData::Sum(sum.into())) - } else if let Some(sum) = data.downcast_ref::>() { - Ok(TonicMetricData::Sum(sum.into())) - } else if let Some(sum) = data.downcast_ref::>() { - Ok(TonicMetricData::Sum(sum.into())) - } else if let Some(gauge) = data.downcast_ref::>() { - Ok(TonicMetricData::Gauge(gauge.into())) - } else if let Some(gauge) = data.downcast_ref::>() { - Ok(TonicMetricData::Gauge(gauge.into())) - } else if let Some(gauge) = data.downcast_ref::>() { - Ok(TonicMetricData::Gauge(gauge.into())) - } else { - otel_debug!( - name: "TonicMetricData::UnknownAggregator", - message= "Unknown aggregator type", - unknown_type= format!("{:?}", data), - ); - Err(()) + impl From<&MetricData> for TonicMetricData + where + T: Numeric + Debug, + { + fn from(data: &MetricData) -> Self { + match data { + MetricData::Gauge(gauge) => TonicMetricData::Gauge(gauge.into()), + MetricData::Sum(sum) => TonicMetricData::Sum(sum.into()), + MetricData::Histogram(hist) => TonicMetricData::Histogram(hist.into()), + MetricData::ExponentialHistogram(hist) => { + TonicMetricData::ExponentialHistogram(hist.into()) + } } } } @@ -286,7 +267,7 @@ pub mod tonic { impl From<&SdkSum> for TonicSum where - T: fmt::Debug + Into + Into + Copy, + T: Debug + Into + Into + Copy, { fn from(sum: &SdkSum) -> Self { TonicSum { @@ -310,7 +291,7 @@ pub mod tonic { impl From<&SdkGauge> for TonicGauge where - T: fmt::Debug + Into + Into + Copy, + T: Debug + Into + Into + Copy, { fn from(gauge: &SdkGauge) -> Self { TonicGauge { diff --git a/opentelemetry-sdk/src/metrics/data/mod.rs b/opentelemetry-sdk/src/metrics/data/mod.rs index de9469637d..819d2ef5fe 100644 --- a/opentelemetry-sdk/src/metrics/data/mod.rs +++ b/opentelemetry-sdk/src/metrics/data/mod.rs @@ -1,6 +1,6 @@ //! Types for delivery of pre-aggregated metric time series data. -use std::{any, borrow::Cow, fmt, time::SystemTime}; +use std::{borrow::Cow, time::SystemTime}; use opentelemetry::{InstrumentationScope, KeyValue}; @@ -38,23 +38,77 @@ pub struct Metric { /// The unit in which the instrument reports. pub unit: Cow<'static, str>, /// The aggregated data from an instrument. - pub data: Box, + pub data: AggregatedMetrics, } -/// The store of data reported by an [Instrument]. -/// -/// It will be one of: [Gauge], [Sum], or [Histogram]. -/// -/// [Instrument]: crate::metrics::Instrument -pub trait Aggregation: fmt::Debug + any::Any + Send + Sync { - /// Support downcasting - fn as_any(&self) -> &dyn any::Any; - /// Support downcasting during aggregation - fn as_mut(&mut self) -> &mut dyn any::Any; +/// Aggregated metrics data from an instrument +#[derive(Debug)] +pub enum AggregatedMetrics { + /// All metric data with `f64` value type + F64(MetricData), + /// All metric data with `u64` value type + U64(MetricData), + /// All metric data with `i64` value type + I64(MetricData), +} + +/// Metric data for all types +#[derive(Debug)] +pub enum MetricData { + /// Metric data for Gauge + Gauge(Gauge), + /// Metric data for Sum + Sum(Sum), + /// Metric data for Histogram + Histogram(Histogram), + /// Metric data for ExponentialHistogram + ExponentialHistogram(ExponentialHistogram), +} + +impl From> for AggregatedMetrics { + fn from(value: MetricData) -> Self { + AggregatedMetrics::F64(value) + } +} + +impl From> for AggregatedMetrics { + fn from(value: MetricData) -> Self { + AggregatedMetrics::I64(value) + } +} + +impl From> for AggregatedMetrics { + fn from(value: MetricData) -> Self { + AggregatedMetrics::U64(value) + } +} + +impl From> for MetricData { + fn from(value: Gauge) -> Self { + MetricData::Gauge(value) + } +} + +impl From> for MetricData { + fn from(value: Sum) -> Self { + MetricData::Sum(value) + } +} + +impl From> for MetricData { + fn from(value: Histogram) -> Self { + MetricData::Histogram(value) + } +} + +impl From> for MetricData { + fn from(value: ExponentialHistogram) -> Self { + MetricData::ExponentialHistogram(value) + } } /// DataPoint is a single data point in a time series. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct GaugeDataPoint { /// Attributes is the set of key value pairs that uniquely identify the /// time series. @@ -65,18 +119,8 @@ pub struct GaugeDataPoint { pub exemplars: Vec>, } -impl Clone for GaugeDataPoint { - fn clone(&self) -> Self { - Self { - attributes: self.attributes.clone(), - value: self.value, - exemplars: self.exemplars.clone(), - } - } -} - /// A measurement of the current value of an instrument. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Gauge { /// Represents individual aggregated measurements with unique attributes. pub data_points: Vec>, @@ -86,17 +130,8 @@ pub struct Gauge { pub time: SystemTime, } -impl Aggregation for Gauge { - fn as_any(&self) -> &dyn any::Any { - self - } - fn as_mut(&mut self) -> &mut dyn any::Any { - self - } -} - /// DataPoint is a single data point in a time series. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct SumDataPoint { /// Attributes is the set of key value pairs that uniquely identify the /// time series. @@ -107,18 +142,8 @@ pub struct SumDataPoint { pub exemplars: Vec>, } -impl Clone for SumDataPoint { - fn clone(&self) -> Self { - Self { - attributes: self.attributes.clone(), - value: self.value, - exemplars: self.exemplars.clone(), - } - } -} - /// Represents the sum of all measurements of values from an instrument. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Sum { /// Represents individual aggregated measurements with unique attributes. pub data_points: Vec>, @@ -133,17 +158,8 @@ pub struct Sum { 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)] +#[derive(Debug, Clone)] pub struct Histogram { /// Individual aggregated measurements with unique attributes. pub data_points: Vec>, @@ -156,17 +172,8 @@ pub struct Histogram { pub temporality: Temporality, } -impl Aggregation for Histogram { - fn as_any(&self) -> &dyn any::Any { - self - } - fn as_mut(&mut self) -> &mut dyn any::Any { - self - } -} - /// A single histogram data point in a time series. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct HistogramDataPoint { /// The set of key value pairs that uniquely identify the time series. pub attributes: Vec, @@ -190,23 +197,8 @@ pub struct HistogramDataPoint { pub exemplars: Vec>, } -impl Clone for HistogramDataPoint { - fn clone(&self) -> Self { - Self { - attributes: self.attributes.clone(), - count: self.count, - bounds: self.bounds.clone(), - bucket_counts: self.bucket_counts.clone(), - min: self.min, - max: self.max, - sum: self.sum, - exemplars: self.exemplars.clone(), - } - } -} - /// The histogram of all measurements of values from an instrument. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ExponentialHistogram { /// The individual aggregated measurements with unique attributes. pub data_points: Vec>, @@ -219,17 +211,8 @@ pub struct ExponentialHistogram { pub temporality: Temporality, } -impl Aggregation for ExponentialHistogram { - fn as_any(&self) -> &dyn any::Any { - self - } - fn as_mut(&mut self) -> &mut dyn any::Any { - self - } -} - /// A single exponential histogram data point in a time series. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct ExponentialHistogramDataPoint { /// The set of key value pairs that uniquely identify the time series. pub attributes: Vec, @@ -273,26 +256,8 @@ pub struct ExponentialHistogramDataPoint { pub exemplars: Vec>, } -impl Clone for ExponentialHistogramDataPoint { - fn clone(&self) -> Self { - Self { - attributes: self.attributes.clone(), - count: self.count, - min: self.min, - max: self.max, - sum: self.sum, - scale: self.scale, - zero_count: self.zero_count, - positive_bucket: self.positive_bucket.clone(), - negative_bucket: self.negative_bucket.clone(), - zero_threshold: self.zero_threshold, - exemplars: self.exemplars.clone(), - } - } -} - /// A set of bucket counts, encoded in a contiguous array of counts. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct ExponentialBucket { /// The bucket index of the first entry in the `counts` vec. pub offset: i32, @@ -304,17 +269,8 @@ pub struct ExponentialBucket { pub counts: Vec, } -impl Clone for ExponentialBucket { - fn clone(&self) -> Self { - Self { - offset: self.offset, - counts: self.counts.clone(), - } - } -} - /// A measurement sampled from a time series providing a typical example. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct Exemplar { /// The attributes recorded with the measurement but filtered out of the /// time series' aggregated data. @@ -333,18 +289,6 @@ pub struct Exemplar { pub trace_id: [u8; 16], } -impl Clone for Exemplar { - fn clone(&self) -> Self { - Self { - filtered_attributes: self.filtered_attributes.clone(), - time: self.time, - value: self.value, - span_id: self.span_id, - trace_id: self.trace_id, - } - } -} - #[cfg(test)] mod tests { diff --git a/opentelemetry-sdk/src/metrics/in_memory_exporter.rs b/opentelemetry-sdk/src/metrics/in_memory_exporter.rs index fe06cadbc2..b743541a47 100644 --- a/opentelemetry-sdk/src/metrics/in_memory_exporter.rs +++ b/opentelemetry-sdk/src/metrics/in_memory_exporter.rs @@ -1,6 +1,7 @@ use crate::error::{OTelSdkError, OTelSdkResult}; -use crate::metrics::data::{self, Gauge, Sum}; -use crate::metrics::data::{Histogram, Metric, ResourceMetrics, ScopeMetrics}; +use crate::metrics::data::{ + ExponentialHistogram, Gauge, Histogram, MetricData, ResourceMetrics, Sum, +}; use crate::metrics::exporter::PushMetricExporter; use crate::metrics::Temporality; use crate::InMemoryExporterError; @@ -8,6 +9,8 @@ use std::collections::VecDeque; use std::fmt; use std::sync::{Arc, Mutex}; +use super::data::{AggregatedMetrics, Metric, ScopeMetrics}; + /// An in-memory metrics exporter that stores metrics data in memory. /// /// This exporter is useful for testing and debugging purposes. It stores @@ -183,8 +186,7 @@ impl InMemoryMetricExporter { name: metric.name.clone(), description: metric.description.clone(), unit: metric.unit.clone(), - // we don't expect any unknown data type here - data: Self::clone_data(metric.data.as_ref()).unwrap(), + data: Self::clone_data(&metric.data), }) .collect(), }) @@ -192,73 +194,43 @@ impl InMemoryMetricExporter { } } - fn clone_data(data: &dyn data::Aggregation) -> Option> { - if let Some(hist) = data.as_any().downcast_ref::>() { - Some(Box::new(Histogram { - data_points: hist.data_points.clone(), - start_time: hist.start_time, - time: hist.time, - temporality: hist.temporality, - })) - } else if let Some(hist) = data.as_any().downcast_ref::>() { - Some(Box::new(Histogram { - data_points: hist.data_points.clone(), - start_time: hist.start_time, - time: hist.time, - temporality: hist.temporality, - })) - } else if let Some(hist) = data.as_any().downcast_ref::>() { - Some(Box::new(Histogram { - data_points: hist.data_points.clone(), - start_time: hist.start_time, - time: hist.time, - temporality: hist.temporality, - })) - } else if let Some(sum) = data.as_any().downcast_ref::>() { - Some(Box::new(data::Sum { - data_points: sum.data_points.clone(), - start_time: sum.start_time, - time: sum.time, - temporality: sum.temporality, - is_monotonic: sum.is_monotonic, - })) - } else if let Some(sum) = data.as_any().downcast_ref::>() { - Some(Box::new(data::Sum { - data_points: sum.data_points.clone(), - start_time: sum.start_time, - time: sum.time, - temporality: sum.temporality, - is_monotonic: sum.is_monotonic, - })) - } else if let Some(sum) = data.as_any().downcast_ref::>() { - Some(Box::new(data::Sum { - data_points: sum.data_points.clone(), - start_time: sum.start_time, - time: sum.time, - temporality: sum.temporality, - is_monotonic: sum.is_monotonic, - })) - } else if let Some(gauge) = data.as_any().downcast_ref::>() { - Some(Box::new(data::Gauge { - data_points: gauge.data_points.clone(), - start_time: gauge.start_time, - time: gauge.time, - })) - } else if let Some(gauge) = data.as_any().downcast_ref::>() { - Some(Box::new(data::Gauge { - data_points: gauge.data_points.clone(), - start_time: gauge.start_time, - time: gauge.time, - })) - } else if let Some(gauge) = data.as_any().downcast_ref::>() { - Some(Box::new(data::Gauge { - data_points: gauge.data_points.clone(), - start_time: gauge.start_time, - time: gauge.time, - })) - } else { - // unknown data type - None + fn clone_data(data: &AggregatedMetrics) -> AggregatedMetrics { + fn clone_inner(data: &MetricData) -> MetricData { + match data { + MetricData::Gauge(gauge) => Gauge { + data_points: gauge.data_points.clone(), + start_time: gauge.start_time, + time: gauge.time, + } + .into(), + MetricData::Sum(sum) => Sum { + data_points: sum.data_points.clone(), + start_time: sum.start_time, + time: sum.time, + temporality: sum.temporality, + is_monotonic: sum.is_monotonic, + } + .into(), + MetricData::Histogram(histogram) => Histogram { + data_points: histogram.data_points.clone(), + start_time: histogram.start_time, + time: histogram.time, + temporality: histogram.temporality, + } + .into(), + MetricData::ExponentialHistogram(exponential_histogram) => ExponentialHistogram { + data_points: exponential_histogram.data_points.clone(), + start_time: exponential_histogram.start_time, + time: exponential_histogram.time, + temporality: exponential_histogram.temporality, + } + .into(), + } + } + match data { + AggregatedMetrics::F64(metric_data) => AggregatedMetrics::F64(clone_inner(metric_data)), + AggregatedMetrics::U64(metric_data) => AggregatedMetrics::U64(clone_inner(metric_data)), + AggregatedMetrics::I64(metric_data) => AggregatedMetrics::I64(clone_inner(metric_data)), } } } diff --git a/opentelemetry-sdk/src/metrics/internal/aggregate.rs b/opentelemetry-sdk/src/metrics/internal/aggregate.rs index 4497ac2fd3..c07c56acca 100644 --- a/opentelemetry-sdk/src/metrics/internal/aggregate.rs +++ b/opentelemetry-sdk/src/metrics/internal/aggregate.rs @@ -6,7 +6,7 @@ use std::{ time::SystemTime, }; -use crate::metrics::{data::Aggregation, Temporality}; +use crate::metrics::{data::AggregatedMetrics, Temporality}; use opentelemetry::time::now; use opentelemetry::KeyValue; @@ -38,7 +38,7 @@ pub(crate) trait ComputeAggregation: Send + Sync + 'static { /// If no initial aggregation exists, `dest` will be `None`, in which case the /// returned option is expected to contain a new aggregation with the data from /// the current collection cycle. - fn call(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>); + fn call(&self, dest: Option<&mut AggregatedMetrics>) -> (usize, Option); } /// Separate `measure` and `collect` functions for an aggregate. @@ -205,7 +205,7 @@ impl AggregateBuilder { mod tests { use crate::metrics::data::{ ExponentialBucket, ExponentialHistogram, ExponentialHistogramDataPoint, Gauge, - GaugeDataPoint, Histogram, HistogramDataPoint, Sum, SumDataPoint, + GaugeDataPoint, Histogram, HistogramDataPoint, MetricData, Sum, SumDataPoint, }; use std::vec; @@ -215,7 +215,7 @@ mod tests { fn last_value_aggregation() { let AggregateFns { measure, collect } = AggregateBuilder::::new(Temporality::Cumulative, None).last_value(None); - let mut a = Gauge { + let mut a = MetricData::Gauge(Gauge { data_points: vec![GaugeDataPoint { attributes: vec![KeyValue::new("a", 1)], value: 1u64, @@ -223,11 +223,15 @@ mod tests { }], start_time: Some(now()), time: now(), - }; + }) + .into(); let new_attributes = [KeyValue::new("b", 2)]; measure.call(2, &new_attributes[..]); let (count, new_agg) = collect.call(Some(&mut a)); + let AggregatedMetrics::U64(MetricData::Gauge(a)) = a else { + unreachable!() + }; assert_eq!(count, 1); assert!(new_agg.is_none()); @@ -241,7 +245,7 @@ mod tests { for temporality in [Temporality::Delta, Temporality::Cumulative] { let AggregateFns { measure, collect } = AggregateBuilder::::new(temporality, None).precomputed_sum(true); - let mut a = Sum { + let mut a = MetricData::Sum(Sum { data_points: vec![ SumDataPoint { attributes: vec![KeyValue::new("a1", 1)], @@ -262,11 +266,15 @@ mod tests { Temporality::Delta }, is_monotonic: false, - }; + }) + .into(); let new_attributes = [KeyValue::new("b", 2)]; measure.call(3, &new_attributes[..]); let (count, new_agg) = collect.call(Some(&mut a)); + let AggregatedMetrics::U64(MetricData::Sum(a)) = a else { + unreachable!() + }; assert_eq!(count, 1); assert!(new_agg.is_none()); @@ -283,7 +291,7 @@ mod tests { for temporality in [Temporality::Delta, Temporality::Cumulative] { let AggregateFns { measure, collect } = AggregateBuilder::::new(temporality, None).sum(true); - let mut a = Sum { + let mut a = MetricData::Sum(Sum { data_points: vec![ SumDataPoint { attributes: vec![KeyValue::new("a1", 1)], @@ -304,11 +312,15 @@ mod tests { Temporality::Delta }, is_monotonic: false, - }; + }) + .into(); let new_attributes = [KeyValue::new("b", 2)]; measure.call(3, &new_attributes[..]); let (count, new_agg) = collect.call(Some(&mut a)); + let AggregatedMetrics::U64(MetricData::Sum(a)) = a else { + unreachable!() + }; assert_eq!(count, 1); assert!(new_agg.is_none()); @@ -325,7 +337,7 @@ mod tests { for temporality in [Temporality::Delta, Temporality::Cumulative] { let AggregateFns { measure, collect } = AggregateBuilder::::new(temporality, None) .explicit_bucket_histogram(vec![1.0], true, true); - let mut a = Histogram { + let mut a = MetricData::Histogram(Histogram { data_points: vec![HistogramDataPoint { attributes: vec![KeyValue::new("a1", 1)], count: 2, @@ -343,11 +355,15 @@ mod tests { } else { Temporality::Delta }, - }; + }) + .into(); let new_attributes = [KeyValue::new("b", 2)]; measure.call(3, &new_attributes[..]); let (count, new_agg) = collect.call(Some(&mut a)); + let AggregatedMetrics::U64(MetricData::Histogram(a)) = a else { + unreachable!() + }; assert_eq!(count, 1); assert!(new_agg.is_none()); @@ -368,7 +384,7 @@ mod tests { for temporality in [Temporality::Delta, Temporality::Cumulative] { let AggregateFns { measure, collect } = AggregateBuilder::::new(temporality, None) .exponential_bucket_histogram(4, 20, true, true); - let mut a = ExponentialHistogram { + let mut a = MetricData::ExponentialHistogram(ExponentialHistogram { data_points: vec![ExponentialHistogramDataPoint { attributes: vec![KeyValue::new("a1", 1)], count: 2, @@ -395,11 +411,15 @@ mod tests { } else { Temporality::Delta }, - }; + }) + .into(); let new_attributes = [KeyValue::new("b", 2)]; measure.call(3, &new_attributes[..]); let (count, new_agg) = collect.call(Some(&mut a)); + let AggregatedMetrics::U64(MetricData::ExponentialHistogram(a)) = a else { + unreachable!() + }; assert_eq!(count, 1); assert!(new_agg.is_none()); diff --git a/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs b/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs index 2680e945b1..30a20c0fa9 100644 --- a/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs +++ b/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs @@ -4,7 +4,7 @@ use opentelemetry::{otel_debug, KeyValue}; use std::sync::OnceLock; use crate::metrics::{ - data::{self, Aggregation, ExponentialHistogram}, + data::{self, AggregatedMetrics, MetricData}, Temporality, }; @@ -383,10 +383,16 @@ impl ExpoHistogram { } } - fn delta(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>) { + fn delta(&self, dest: Option<&mut MetricData>) -> (usize, Option>) { let time = self.init_time.delta(); - let h = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let h = dest.and_then(|d| { + if let MetricData::ExponentialHistogram(hist) = d { + Some(hist) + } else { + None + } + }); let mut new_agg = if h.is_none() { Some(data::ExponentialHistogram { data_points: vec![], @@ -434,16 +440,19 @@ impl ExpoHistogram { } }); - (h.data_points.len(), new_agg.map(|a| Box::new(a) as Box<_>)) + (h.data_points.len(), new_agg.map(Into::into)) } - fn cumulative( - &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + fn cumulative(&self, dest: Option<&mut MetricData>) -> (usize, Option>) { let time = self.init_time.cumulative(); - let h = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let h = dest.and_then(|d| { + if let MetricData::ExponentialHistogram(hist) = d { + Some(hist) + } else { + None + } + }); let mut new_agg = if h.is_none() { Some(data::ExponentialHistogram { data_points: vec![], @@ -491,7 +500,7 @@ impl ExpoHistogram { } }); - (h.data_points.len(), new_agg.map(|a| Box::new(a) as Box<_>)) + (h.data_points.len(), new_agg.map(Into::into)) } } @@ -517,18 +526,20 @@ impl ComputeAggregation for ExpoHistogram where T: Number, { - fn call(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>) { - match self.temporality { - Temporality::Delta => self.delta(dest), - _ => self.cumulative(dest), - } + fn call(&self, dest: Option<&mut AggregatedMetrics>) -> (usize, Option) { + let data = dest.and_then(|d| T::extract_metrics_data_mut(d)); + let (len, new) = match self.temporality { + Temporality::Delta => self.delta(data), + _ => self.cumulative(data), + }; + (len, new.map(T::make_aggregated_metrics)) } } + #[cfg(test)] mod tests { - use data::{ExponentialHistogram, Gauge, Histogram, Sum}; use opentelemetry::time::now; - use std::ops::Neg; + use std::{any::Any, ops::Neg}; use tests::internal::AggregateFns; use crate::metrics::internal::{self, AggregateBuilder}; @@ -1438,111 +1449,114 @@ mod tests { for test in test_cases { let AggregateFns { measure, collect } = (test.build)(); - let mut got: Box = Box::new(data::ExponentialHistogram:: { - data_points: vec![], - start_time: now(), - time: now(), - temporality: Temporality::Delta, - }); + let mut got = T::make_aggregated_metrics(MetricData::ExponentialHistogram( + data::ExponentialHistogram:: { + data_points: vec![], + start_time: now(), + time: now(), + temporality: Temporality::Delta, + }, + )); let mut count = 0; for n in test.input { for v in n { measure.call(v, &[]) } - count = collect.call(Some(got.as_mut())).0 + count = collect.call(Some(&mut got)).0 } - assert_aggregation_eq::(Box::new(test.want), got, test.name); + assert_aggregation_eq( + &MetricData::ExponentialHistogram(test.want), + T::extract_metrics_data_ref(&got).unwrap(), + test.name, + ); assert_eq!(test.want_count, count, "{}", test.name); } } fn assert_aggregation_eq( - a: Box, - b: Box, + a: &MetricData, + b: &MetricData, test_name: &'static str, ) { - assert_eq!( - a.as_any().type_id(), - b.as_any().type_id(), - "{} Aggregation types not equal", - test_name - ); - - if let Some(a) = a.as_any().downcast_ref::>() { - let b = b.as_any().downcast_ref::>().unwrap(); - assert_eq!( - a.data_points.len(), - b.data_points.len(), - "{} gauge counts", - test_name - ); - for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { - assert_gauge_data_points_eq(a, b, "mismatching gauge data points", test_name); + match (a, b) { + (MetricData::Gauge(a), MetricData::Gauge(b)) => { + assert_eq!( + a.data_points.len(), + b.data_points.len(), + "{} gauge counts", + test_name + ); + for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { + assert_gauge_data_points_eq(a, b, "mismatching gauge data points", test_name); + } } - } else if let Some(a) = a.as_any().downcast_ref::>() { - let b = b.as_any().downcast_ref::>().unwrap(); - assert_eq!( - a.temporality, b.temporality, - "{} mismatching sum temporality", - test_name - ); - assert_eq!( - a.is_monotonic, b.is_monotonic, - "{} mismatching sum monotonicity", - test_name, - ); - assert_eq!( - a.data_points.len(), - b.data_points.len(), - "{} sum counts", - test_name - ); - for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { - assert_sum_data_points_eq(a, b, "mismatching sum data points", test_name); + (MetricData::Sum(a), MetricData::Sum(b)) => { + assert_eq!( + a.temporality, b.temporality, + "{} mismatching sum temporality", + test_name + ); + assert_eq!( + a.is_monotonic, b.is_monotonic, + "{} mismatching sum monotonicity", + test_name, + ); + assert_eq!( + a.data_points.len(), + b.data_points.len(), + "{} sum counts", + test_name + ); + for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { + assert_sum_data_points_eq(a, b, "mismatching sum data points", test_name); + } } - } else if let Some(a) = a.as_any().downcast_ref::>() { - let b = b.as_any().downcast_ref::>().unwrap(); - assert_eq!( - a.temporality, b.temporality, - "{}: mismatching hist temporality", - test_name - ); - assert_eq!( - a.data_points.len(), - b.data_points.len(), - "{} hist counts", - test_name - ); - for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { - assert_hist_data_points_eq(a, b, "mismatching hist data points", test_name); + (MetricData::Histogram(a), MetricData::Histogram(b)) => { + assert_eq!( + a.temporality, b.temporality, + "{}: mismatching hist temporality", + test_name + ); + assert_eq!( + a.data_points.len(), + b.data_points.len(), + "{} hist counts", + test_name + ); + for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { + assert_hist_data_points_eq(a, b, "mismatching hist data points", test_name); + } } - } else if let Some(a) = a.as_any().downcast_ref::>() { - let b = b - .as_any() - .downcast_ref::>() - .unwrap(); - assert_eq!( - a.temporality, b.temporality, - "{} mismatching hist temporality", - test_name - ); - assert_eq!( - a.data_points.len(), - b.data_points.len(), - "{} hist counts", - test_name - ); - for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { - assert_exponential_hist_data_points_eq( - a, - b, - "mismatching hist data points", - test_name, + (MetricData::ExponentialHistogram(a), MetricData::ExponentialHistogram(b)) => { + assert_eq!( + a.temporality, b.temporality, + "{} mismatching hist temporality", + test_name + ); + assert_eq!( + a.data_points.len(), + b.data_points.len(), + "{} hist counts", + test_name + ); + for (a, b) in a.data_points.iter().zip(b.data_points.iter()) { + assert_exponential_hist_data_points_eq( + a, + b, + "mismatching hist data points", + test_name, + ); + } + } + _ => { + assert_eq!( + a.type_id(), + b.type_id(), + "{} Aggregation types not equal", + test_name ); } - } else { - panic!("Aggregation of unknown types") } } diff --git a/opentelemetry-sdk/src/metrics/internal/histogram.rs b/opentelemetry-sdk/src/metrics/internal/histogram.rs index 988f8cf359..62f2e236e8 100644 --- a/opentelemetry-sdk/src/metrics/internal/histogram.rs +++ b/opentelemetry-sdk/src/metrics/internal/histogram.rs @@ -2,8 +2,8 @@ use std::mem::replace; use std::ops::DerefMut; use std::sync::Mutex; -use crate::metrics::data::HistogramDataPoint; -use crate::metrics::data::{self, Aggregation}; +use crate::metrics::data::{self, MetricData}; +use crate::metrics::data::{AggregatedMetrics, HistogramDataPoint}; use crate::metrics::Temporality; use opentelemetry::KeyValue; @@ -107,10 +107,16 @@ impl Histogram { } } - fn delta(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>) { + fn delta(&self, dest: Option<&mut MetricData>) -> (usize, Option>) { let time = self.init_time.delta(); - let h = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let h = dest.and_then(|d| { + if let MetricData::Histogram(hist) = d { + Some(hist) + } else { + None + } + }); let mut new_agg = if h.is_none() { Some(data::Histogram { data_points: vec![], @@ -153,15 +159,18 @@ impl Histogram { } }); - (h.data_points.len(), new_agg.map(|a| Box::new(a) as Box<_>)) + (h.data_points.len(), new_agg.map(Into::into)) } - fn cumulative( - &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + fn cumulative(&self, dest: Option<&mut MetricData>) -> (usize, Option>) { let time = self.init_time.cumulative(); - let h = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let h = dest.and_then(|d| { + if let MetricData::Histogram(hist) = d { + Some(hist) + } else { + None + } + }); let mut new_agg = if h.is_none() { Some(data::Histogram { data_points: vec![], @@ -204,7 +213,7 @@ impl Histogram { } }); - (h.data_points.len(), new_agg.map(|a| Box::new(a) as Box<_>)) + (h.data_points.len(), new_agg.map(Into::into)) } } @@ -231,11 +240,13 @@ impl ComputeAggregation for Histogram where T: Number, { - fn call(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>) { - match self.temporality { - Temporality::Delta => self.delta(dest), - _ => self.cumulative(dest), - } + fn call(&self, dest: Option<&mut AggregatedMetrics>) -> (usize, Option) { + let data = dest.and_then(|d| T::extract_metrics_data_mut(d)); + let (len, new) = match self.temporality { + Temporality::Delta => self.delta(data), + _ => self.cumulative(data), + }; + (len, new.map(T::make_aggregated_metrics)) } } @@ -257,7 +268,9 @@ mod tests { } let (count, dp) = ComputeAggregation::call(&hist, None); let dp = dp.unwrap(); - let dp = dp.as_any().downcast_ref::>().unwrap(); + let AggregatedMetrics::I64(MetricData::Histogram(dp)) = dp else { + unreachable!() + }; assert_eq!(count, 1); assert_eq!(dp.data_points[0].count, 10); assert_eq!(dp.data_points[0].bucket_counts.len(), 4); diff --git a/opentelemetry-sdk/src/metrics/internal/last_value.rs b/opentelemetry-sdk/src/metrics/internal/last_value.rs index b14c86047e..9d8576f15b 100644 --- a/opentelemetry-sdk/src/metrics/internal/last_value.rs +++ b/opentelemetry-sdk/src/metrics/internal/last_value.rs @@ -1,5 +1,5 @@ use crate::metrics::{ - data::{self, Aggregation, Gauge, GaugeDataPoint}, + data::{self, AggregatedMetrics, GaugeDataPoint, MetricData}, Temporality, }; use opentelemetry::KeyValue; @@ -59,13 +59,16 @@ impl LastValue { } } - pub(crate) fn delta( - &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + pub(crate) fn delta(&self, dest: Option<&mut MetricData>) -> (usize, Option>) { let time = self.init_time.delta(); - let s_data = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let s_data = dest.and_then(|d| { + if let MetricData::Gauge(gauge) = d { + Some(gauge) + } else { + None + } + }); let mut new_agg = if s_data.is_none() { Some(data::Gauge { data_points: vec![], @@ -86,18 +89,21 @@ impl LastValue { exemplars: vec![], }); - ( - s_data.data_points.len(), - new_agg.map(|a| Box::new(a) as Box<_>), - ) + (s_data.data_points.len(), new_agg.map(Into::into)) } pub(crate) fn cumulative( &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + dest: Option<&mut MetricData>, + ) -> (usize, Option>) { let time = self.init_time.cumulative(); - let s_data = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let s_data = dest.and_then(|d| { + if let MetricData::Gauge(gauge) = d { + Some(gauge) + } else { + None + } + }); let mut new_agg = if s_data.is_none() { Some(data::Gauge { data_points: vec![], @@ -119,10 +125,7 @@ impl LastValue { exemplars: vec![], }); - ( - s_data.data_points.len(), - new_agg.map(|a| Box::new(a) as Box<_>), - ) + (s_data.data_points.len(), new_agg.map(Into::into)) } } @@ -141,10 +144,12 @@ impl ComputeAggregation for LastValue where T: Number, { - fn call(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>) { - match self.temporality { - Temporality::Delta => self.delta(dest), - _ => self.cumulative(dest), - } + fn call(&self, dest: Option<&mut AggregatedMetrics>) -> (usize, Option) { + let data = dest.and_then(|d| T::extract_metrics_data_mut(d)); + let (len, new) = match self.temporality { + Temporality::Delta => self.delta(data), + _ => self.cumulative(data), + }; + (len, new.map(T::make_aggregated_metrics)) } } diff --git a/opentelemetry-sdk/src/metrics/internal/mod.rs b/opentelemetry-sdk/src/metrics/internal/mod.rs index 6316c97b23..5df1d65125 100644 --- a/opentelemetry-sdk/src/metrics/internal/mod.rs +++ b/opentelemetry-sdk/src/metrics/internal/mod.rs @@ -17,6 +17,8 @@ pub(crate) use aggregate::{AggregateBuilder, AggregateFns, ComputeAggregation, M pub(crate) use exponential_histogram::{EXPO_MAX_SCALE, EXPO_MIN_SCALE}; use opentelemetry::{otel_warn, KeyValue}; +use super::data::{AggregatedMetrics, MetricData}; + // TODO Replace it with LazyLock once it is stable pub(crate) static STREAM_OVERFLOW_ATTRIBUTES: OnceLock> = OnceLock::new(); @@ -242,6 +244,14 @@ pub(crate) trait AtomicallyUpdate { fn new_atomic_tracker(init: T) -> Self::AtomicTracker; } +pub(crate) trait AggregatedMetricsAccess: Sized { + /// This function is used in tests. + #[allow(unused)] + fn extract_metrics_data_ref(data: &AggregatedMetrics) -> Option<&MetricData>; + fn extract_metrics_data_mut(data: &mut AggregatedMetrics) -> Option<&mut MetricData>; + fn make_aggregated_metrics(data: MetricData) -> AggregatedMetrics; +} + pub(crate) trait Number: Add + AddAssign @@ -256,6 +266,7 @@ pub(crate) trait Number: + Sync + 'static + AtomicallyUpdate + + AggregatedMetricsAccess { fn min() -> Self; fn max() -> Self; @@ -305,6 +316,72 @@ impl Number for f64 { } } +impl AggregatedMetricsAccess for i64 { + fn make_aggregated_metrics(data: MetricData) -> AggregatedMetrics { + AggregatedMetrics::I64(data) + } + + fn extract_metrics_data_ref(data: &AggregatedMetrics) -> Option<&MetricData> { + if let AggregatedMetrics::I64(data) = data { + Some(data) + } else { + None + } + } + + fn extract_metrics_data_mut(data: &mut AggregatedMetrics) -> Option<&mut MetricData> { + if let AggregatedMetrics::I64(data) = data { + Some(data) + } else { + None + } + } +} + +impl AggregatedMetricsAccess for u64 { + fn make_aggregated_metrics(data: MetricData) -> AggregatedMetrics { + AggregatedMetrics::U64(data) + } + + fn extract_metrics_data_ref(data: &AggregatedMetrics) -> Option<&MetricData> { + if let AggregatedMetrics::U64(data) = data { + Some(data) + } else { + None + } + } + + fn extract_metrics_data_mut(data: &mut AggregatedMetrics) -> Option<&mut MetricData> { + if let AggregatedMetrics::U64(data) = data { + Some(data) + } else { + None + } + } +} + +impl AggregatedMetricsAccess for f64 { + fn make_aggregated_metrics(data: MetricData) -> AggregatedMetrics { + AggregatedMetrics::F64(data) + } + + fn extract_metrics_data_ref(data: &AggregatedMetrics) -> Option<&MetricData> { + if let AggregatedMetrics::F64(data) = data { + Some(data) + } else { + None + } + } + + fn extract_metrics_data_mut(data: &mut AggregatedMetrics) -> Option<&mut MetricData> { + if let AggregatedMetrics::F64(data) = data { + Some(data) + } else { + None + } + } +} + impl AtomicTracker for AtomicU64 { fn store(&self, value: u64) { self.store(value, Ordering::Relaxed); diff --git a/opentelemetry-sdk/src/metrics/internal/precomputed_sum.rs b/opentelemetry-sdk/src/metrics/internal/precomputed_sum.rs index c035dbe696..6e3dc7d541 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, Sum, SumDataPoint}; +use crate::metrics::data::{self, AggregatedMetrics, MetricData, SumDataPoint}; use crate::metrics::Temporality; use super::aggregate::{AggregateTimeInitiator, AttributeSetFilter}; @@ -34,13 +34,16 @@ impl PrecomputedSum { } } - pub(crate) fn delta( - &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + pub(crate) fn delta(&self, dest: Option<&mut MetricData>) -> (usize, Option>) { let time = self.init_time.delta(); - let s_data = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let s_data = dest.and_then(|d| { + if let MetricData::Sum(sum) = d { + Some(sum) + } else { + None + } + }); let mut new_agg = if s_data.is_none() { Some(data::Sum { data_points: vec![], @@ -79,19 +82,22 @@ impl PrecomputedSum { *reported = new_reported; drop(reported); // drop before values guard is dropped - ( - s_data.data_points.len(), - new_agg.map(|a| Box::new(a) as Box<_>), - ) + (s_data.data_points.len(), new_agg.map(Into::into)) } pub(crate) fn cumulative( &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + dest: Option<&mut MetricData>, + ) -> (usize, Option>) { let time = self.init_time.cumulative(); - let s_data = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let s_data = dest.and_then(|d| { + if let MetricData::Sum(sum) = d { + Some(sum) + } else { + None + } + }); let mut new_agg = if s_data.is_none() { Some(data::Sum { data_points: vec![], @@ -116,10 +122,7 @@ impl PrecomputedSum { exemplars: vec![], }); - ( - s_data.data_points.len(), - new_agg.map(|a| Box::new(a) as Box<_>), - ) + (s_data.data_points.len(), new_agg.map(Into::into)) } } @@ -138,10 +141,12 @@ impl ComputeAggregation for PrecomputedSum where T: Number, { - fn call(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>) { - match self.temporality { - Temporality::Delta => self.delta(dest), - _ => self.cumulative(dest), - } + fn call(&self, dest: Option<&mut AggregatedMetrics>) -> (usize, Option) { + let data = dest.and_then(|d| T::extract_metrics_data_mut(d)); + let (len, new) = match self.temporality { + Temporality::Delta => self.delta(data), + _ => self.cumulative(data), + }; + (len, new.map(T::make_aggregated_metrics)) } } diff --git a/opentelemetry-sdk/src/metrics/internal/sum.rs b/opentelemetry-sdk/src/metrics/internal/sum.rs index 24b656dc1f..79ae5d711d 100644 --- a/opentelemetry-sdk/src/metrics/internal/sum.rs +++ b/opentelemetry-sdk/src/metrics/internal/sum.rs @@ -1,4 +1,4 @@ -use crate::metrics::data::{self, Aggregation, SumDataPoint}; +use crate::metrics::data::{self, AggregatedMetrics, MetricData, SumDataPoint}; use crate::metrics::Temporality; use opentelemetry::KeyValue; @@ -66,12 +66,15 @@ impl Sum { } } - pub(crate) fn delta( - &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + pub(crate) fn delta(&self, dest: Option<&mut MetricData>) -> (usize, Option>) { let time = self.init_time.delta(); - let s_data = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let s_data = dest.and_then(|d| { + if let MetricData::Sum(sum) = d { + Some(sum) + } else { + None + } + }); let mut new_agg = if s_data.is_none() { Some(data::Sum { data_points: vec![], @@ -96,18 +99,21 @@ impl Sum { exemplars: vec![], }); - ( - s_data.data_points.len(), - new_agg.map(|a| Box::new(a) as Box<_>), - ) + (s_data.data_points.len(), new_agg.map(Into::into)) } pub(crate) fn cumulative( &self, - dest: Option<&mut dyn Aggregation>, - ) -> (usize, Option>) { + dest: Option<&mut MetricData>, + ) -> (usize, Option>) { let time = self.init_time.cumulative(); - let s_data = dest.and_then(|d| d.as_mut().downcast_mut::>()); + let s_data = dest.and_then(|d| { + if let MetricData::Sum(sum) = d { + Some(sum) + } else { + None + } + }); let mut new_agg = if s_data.is_none() { Some(data::Sum { data_points: vec![], @@ -133,10 +139,7 @@ impl Sum { exemplars: vec![], }); - ( - s_data.data_points.len(), - new_agg.map(|a| Box::new(a) as Box<_>), - ) + (s_data.data_points.len(), new_agg.map(Into::into)) } } @@ -155,10 +158,12 @@ impl ComputeAggregation for Sum where T: Number, { - fn call(&self, dest: Option<&mut dyn Aggregation>) -> (usize, Option>) { - match self.temporality { - Temporality::Delta => self.delta(dest), - _ => self.cumulative(dest), - } + fn call(&self, dest: Option<&mut AggregatedMetrics>) -> (usize, Option) { + let data = dest.and_then(|d| T::extract_metrics_data_mut(d)); + let (len, new) = match self.temporality { + Temporality::Delta => self.delta(data), + _ => self.cumulative(data), + }; + (len, new.map(T::make_aggregated_metrics)) } } diff --git a/opentelemetry-sdk/src/metrics/mod.rs b/opentelemetry-sdk/src/metrics/mod.rs index 25a7389d92..608ce62775 100644 --- a/opentelemetry-sdk/src/metrics/mod.rs +++ b/opentelemetry-sdk/src/metrics/mod.rs @@ -112,15 +112,14 @@ pub enum Temporality { #[cfg(all(test, feature = "testing"))] mod tests { use self::data::{HistogramDataPoint, ScopeMetrics, SumDataPoint}; + use super::data::MetricData; + use super::internal::Number; use super::*; - use crate::metrics::data::Aggregation; use crate::metrics::data::ResourceMetrics; + use crate::metrics::internal::AggregatedMetricsAccess; use crate::metrics::InMemoryMetricExporter; use crate::metrics::InMemoryMetricExporterBuilder; - use data::Gauge; use data::GaugeDataPoint; - use data::Histogram; - use data::Sum; use opentelemetry::metrics::{Counter, Meter, UpDownCounter}; use opentelemetry::InstrumentationScope; use opentelemetry::{metrics::MeterProvider as _, KeyValue}; @@ -329,7 +328,9 @@ mod tests { counter.add(50, &[]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 1, "Expected only one data point"); assert!(sum.is_monotonic, "Should produce monotonic."); @@ -352,7 +353,9 @@ mod tests { counter.add(50, &[]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 1, "Expected only one data point"); assert!(sum.is_monotonic, "Should produce monotonic."); @@ -554,7 +557,11 @@ mod tests { for (iter, v) in values_clone.iter().enumerate() { test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_observable_counter", None); + let MetricData::Sum(sum) = + test_context.get_aggregation::("my_observable_counter", None) + else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 1); assert!(sum.is_monotonic, "Counter should produce monotonic."); if let Temporality::Cumulative = temporality { @@ -670,11 +677,11 @@ mod tests { let metric = &resource_metrics[0].scope_metrics[0].metrics[0]; assert_eq!(metric.name, "my_counter"); assert_eq!(metric.unit, "my_unit"); - let sum = metric - .data - .as_any() - .downcast_ref::>() - .expect("Sum aggregation expected for Counter instruments by default"); + let MetricData::Sum(sum) = u64::extract_metrics_data_ref(&metric.data) + .expect("Sum aggregation expected for Counter instruments by default") + else { + unreachable!() + }; // Expecting 1 time-series. assert_eq!(sum.data_points.len(), 1); @@ -737,11 +744,11 @@ mod tests { assert_eq!(metric1.name, "my_counter"); assert_eq!(metric1.unit, "my_unit"); assert_eq!(metric1.description, "my_description"); - let sum1 = metric1 - .data - .as_any() - .downcast_ref::>() - .expect("Sum aggregation expected for Counter instruments by default"); + let MetricData::Sum(sum1) = u64::extract_metrics_data_ref(&metric1.data) + .expect("Sum aggregation expected for Counter instruments by default") + else { + unreachable!() + }; // Expecting 1 time-series. assert_eq!(sum1.data_points.len(), 1); @@ -757,11 +764,12 @@ mod tests { assert_eq!(metric2.name, "my_counter"); assert_eq!(metric2.unit, "my_unit"); assert_eq!(metric2.description, "my_description"); - let sum2 = metric2 - .data - .as_any() - .downcast_ref::>() - .expect("Sum aggregation expected for Counter instruments by default"); + + let MetricData::Sum(sum2) = u64::extract_metrics_data_ref(&metric2.data) + .expect("Sum aggregation expected for Counter instruments by default") + else { + unreachable!() + }; // Expecting 1 time-series. assert_eq!(sum2.data_points.len(), 1); @@ -842,11 +850,12 @@ mod tests { assert_eq!(metric.name, "my_counter"); assert_eq!(metric.unit, "my_unit"); assert_eq!(metric.description, "my_description"); - let sum = metric - .data - .as_any() - .downcast_ref::>() - .expect("Sum aggregation expected for Counter instruments by default"); + + let MetricData::Sum(sum) = u64::extract_metrics_data_ref(&metric.data) + .expect("Sum aggregation expected for Counter instruments by default") + else { + unreachable!() + }; // Expecting 1 time-series. assert_eq!(sum.data_points.len(), 1); @@ -963,11 +972,11 @@ mod tests { let metric = &resource_metrics[0].scope_metrics[0].metrics[0]; assert_eq!(metric.name, "my_observable_counter",); - let sum = metric - .data - .as_any() - .downcast_ref::>() - .expect("Sum aggregation expected for ObservableCounter instruments by default"); + let MetricData::Sum(sum) = u64::extract_metrics_data_ref(&metric.data) + .expect("Sum aggregation expected for ObservableCounter instruments by default") + else { + unreachable!() + }; // Expecting 1 time-series only, as the view drops all attributes resulting // in a single time-series. @@ -1039,11 +1048,11 @@ mod tests { let metric = &resource_metrics[0].scope_metrics[0].metrics[0]; assert_eq!(metric.name, "my_counter",); - let sum = metric - .data - .as_any() - .downcast_ref::>() - .expect("Sum aggregation expected for Counter instruments by default"); + let MetricData::Sum(sum) = u64::extract_metrics_data_ref(&metric.data) + .expect("Sum aggregation expected for Counter instruments by default") + else { + unreachable!() + }; // Expecting 1 time-series only, as the view drops all attributes resulting // in a single time-series. @@ -1062,7 +1071,11 @@ mod tests { counter.add(50, &[]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", Some("my_unit")); + let MetricData::Sum(sum) = + test_context.get_aggregation::("my_counter", Some("my_unit")) + else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 1, "Expected only one data point"); assert!(!sum.is_monotonic, "Should not produce monotonic."); @@ -1085,7 +1098,11 @@ mod tests { counter.add(50, &[]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", Some("my_unit")); + let MetricData::Sum(sum) = + test_context.get_aggregation::("my_counter", Some("my_unit")) + else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 1, "Expected only one data point"); assert!(!sum.is_monotonic, "Should not produce monotonic."); @@ -1107,12 +1124,14 @@ mod tests { counter.add(50, &[]); test_context.flush_metrics(); - let _ = test_context.get_aggregation::>("my_counter", None); + let _ = test_context.get_aggregation::("my_counter", None); test_context.reset_metrics(); counter.add(5, &[]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 1, "Expected only one data point"); assert!(sum.is_monotonic, "Should produce monotonic."); @@ -1134,12 +1153,14 @@ mod tests { counter.add(50, &[]); test_context.flush_metrics(); - let _ = test_context.get_aggregation::>("my_counter", None); + let _ = test_context.get_aggregation::("my_counter", None); test_context.reset_metrics(); counter.add(5, &[]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 1, "Expected only one data point"); assert!(sum.is_monotonic, "Should produce monotonic."); @@ -1161,12 +1182,14 @@ mod tests { counter.add(50, &[]); test_context.flush_metrics(); - let _ = test_context.get_aggregation::>("my_counter", None); + let _ = test_context.get_aggregation::("my_counter", None); test_context.reset_metrics(); counter.add(50, &[KeyValue::new("a", "b")]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; let no_attr_data_point = sum.data_points.iter().find(|x| x.attributes.is_empty()); @@ -1197,7 +1220,9 @@ mod tests { counter.add(1, &[KeyValue::new("key1", "value2")]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; // Expecting 2 time-series. assert_eq!(sum.data_points.len(), 2); @@ -1321,40 +1346,43 @@ mod tests { fn assert_correct_export(test_context: &mut TestContext, instrument_name: &'static str) { match instrument_name { "counter" => { - let counter_data = - test_context.get_aggregation::>("test_counter", None); - assert_eq!(counter_data.data_points.len(), 2); + let MetricData::Sum(sum) = + test_context.get_aggregation::("test_counter", None) + else { + unreachable!() + }; + assert_eq!(sum.data_points.len(), 2); let zero_attribute_datapoint = - find_sum_datapoint_with_no_attributes(&counter_data.data_points) + find_sum_datapoint_with_no_attributes(&sum.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 5); - let data_point1 = find_sum_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(&sum.data_points, "key1", "value1") + .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 10); } "updown_counter" => { - let updown_counter_data = - test_context.get_aggregation::>("test_updowncounter", None); - assert_eq!(updown_counter_data.data_points.len(), 2); + let MetricData::Sum(sum) = + test_context.get_aggregation::("test_updowncounter", None) + else { + unreachable!() + }; + assert_eq!(sum.data_points.len(), 2); let zero_attribute_datapoint = - find_sum_datapoint_with_no_attributes(&updown_counter_data.data_points) + find_sum_datapoint_with_no_attributes(&sum.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 15); - let data_point1 = find_sum_datapoint_with_key_value( - &updown_counter_data.data_points, - "key1", - "value1", - ) - .expect("datapoint with key1=value1 expected"); + 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, 20); } "histogram" => { - let histogram_data = - test_context.get_aggregation::>("test_histogram", None); + let MetricData::Histogram(histogram_data) = + test_context.get_aggregation::("test_histogram", None) + else { + unreachable!() + }; assert_eq!(histogram_data.data_points.len(), 2); let zero_attribute_datapoint = find_histogram_datapoint_with_no_attributes(&histogram_data.data_points) @@ -1375,7 +1403,11 @@ mod tests { assert_eq!(data_point1.max, Some(30)); } "gauge" => { - let gauge_data = test_context.get_aggregation::>("test_gauge", None); + let MetricData::Gauge(gauge_data) = + test_context.get_aggregation::("test_gauge", None) + else { + unreachable!() + }; assert_eq!(gauge_data.data_points.len(), 2); let zero_attribute_datapoint = find_gauge_datapoint_with_no_attributes(&gauge_data.data_points) @@ -1487,41 +1519,45 @@ mod tests { fn assert_correct_export(test_context: &mut TestContext, instrument_name: &'static str) { match instrument_name { "counter" => { - let counter_data = - test_context.get_aggregation::>("test_counter", None); - assert_eq!(counter_data.data_points.len(), 2); - assert!(counter_data.is_monotonic); + let MetricData::Sum(sum) = + test_context.get_aggregation::("test_counter", None) + else { + unreachable!() + }; + assert_eq!(sum.data_points.len(), 2); + assert!(sum.is_monotonic); let zero_attribute_datapoint = - find_sum_datapoint_with_no_attributes(&counter_data.data_points) + find_sum_datapoint_with_no_attributes(&sum.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 5); - let data_point1 = find_sum_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(&sum.data_points, "key1", "value1") + .expect("datapoint with key1=value1 expected"); assert_eq!(data_point1.value, 10); } "updown_counter" => { - let updown_counter_data = - test_context.get_aggregation::>("test_updowncounter", None); - assert_eq!(updown_counter_data.data_points.len(), 2); - assert!(!updown_counter_data.is_monotonic); + let MetricData::Sum(sum) = + test_context.get_aggregation::("test_updowncounter", None) + else { + unreachable!() + }; + assert_eq!(sum.data_points.len(), 2); + assert!(!sum.is_monotonic); let zero_attribute_datapoint = - find_sum_datapoint_with_no_attributes(&updown_counter_data.data_points) + find_sum_datapoint_with_no_attributes(&sum.data_points) .expect("datapoint with no attributes expected"); assert_eq!(zero_attribute_datapoint.value, 15); - let data_point1 = find_sum_datapoint_with_key_value( - &updown_counter_data.data_points, - "key1", - "value1", - ) - .expect("datapoint with key1=value1 expected"); + 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, 20); } "gauge" => { - let gauge_data = test_context.get_aggregation::>("test_gauge", None); + let MetricData::Gauge(gauge_data) = + test_context.get_aggregation::("test_gauge", None) + else { + unreachable!() + }; assert_eq!(gauge_data.data_points.len(), 2); let zero_attribute_datapoint = find_gauge_datapoint_with_no_attributes(&gauge_data.data_points) @@ -1570,7 +1606,17 @@ mod tests { // Assert // We invoke `test_context.flush_metrics()` six times. - let sums = test_context.get_from_multiple_aggregations::>("my_counter", None, 6); + let sums = test_context + .get_from_multiple_aggregations::("my_counter", None, 6) + .into_iter() + .map(|data| { + if let MetricData::Sum(sum) = data { + sum + } else { + unreachable!() + } + }) + .collect::>(); let mut sum_zero_attributes = 0; let mut sum_key1_value1 = 0; @@ -1622,7 +1668,17 @@ mod tests { // Assert // We invoke `test_context.flush_metrics()` six times. - let sums = test_context.get_from_multiple_aggregations::>("test_counter", None, 6); + let sums = test_context + .get_from_multiple_aggregations::("test_counter", None, 6) + .into_iter() + .map(|data| { + if let MetricData::Sum(sum) = data { + sum + } else { + unreachable!() + } + }) + .collect::>(); let mut sum_zero_attributes = 0.0; let mut sum_key1_value1 = 0.0; @@ -1675,11 +1731,17 @@ mod tests { // Assert // We invoke `test_context.flush_metrics()` six times. - let histograms = test_context.get_from_multiple_aggregations::>( - "test_histogram", - None, - 6, - ); + let histograms = test_context + .get_from_multiple_aggregations::("test_histogram", None, 6) + .into_iter() + .map(|data| { + if let MetricData::Histogram(hist) = data { + hist + } else { + unreachable!() + } + }) + .collect::>(); let ( mut sum_zero_attributes, @@ -1812,11 +1874,17 @@ mod tests { // Assert // We invoke `test_context.flush_metrics()` six times. - let histograms = test_context.get_from_multiple_aggregations::>( - "test_histogram", - None, - 6, - ); + let histograms = test_context + .get_from_multiple_aggregations::("test_histogram", None, 6) + .into_iter() + .map(|data| { + if let MetricData::Histogram(hist) = data { + hist + } else { + unreachable!() + } + }) + .collect::>(); let ( mut sum_zero_attributes, @@ -1942,7 +2010,11 @@ mod tests { test_context.flush_metrics(); // Assert - let histogram_data = test_context.get_aggregation::>("my_histogram", None); + let MetricData::Histogram(histogram_data) = + test_context.get_aggregation::("my_histogram", None) + else { + unreachable!() + }; // Expecting 2 time-series. assert_eq!(histogram_data.data_points.len(), 2); if let Temporality::Cumulative = temporality { @@ -1988,7 +2060,11 @@ mod tests { test_context.flush_metrics(); - let histogram_data = test_context.get_aggregation::>("my_histogram", None); + let MetricData::Histogram(histogram_data) = + test_context.get_aggregation::("my_histogram", None) + else { + unreachable!() + }; assert_eq!(histogram_data.data_points.len(), 2); let data_point1 = find_histogram_datapoint_with_key_value(&histogram_data.data_points, "key1", "value1") @@ -2037,7 +2113,11 @@ mod tests { test_context.flush_metrics(); // Assert - let histogram_data = test_context.get_aggregation::>("test_histogram", None); + let MetricData::Histogram(histogram_data) = + test_context.get_aggregation::("test_histogram", None) + else { + unreachable!() + }; // Expecting 2 time-series. assert_eq!(histogram_data.data_points.len(), 1); if let Temporality::Cumulative = temporality { @@ -2090,7 +2170,11 @@ mod tests { test_context.flush_metrics(); // Assert - let gauge_data_point = test_context.get_aggregation::>("my_gauge", None); + let MetricData::Gauge(gauge_data_point) = + test_context.get_aggregation::("my_gauge", None) + else { + unreachable!() + }; // Expecting 2 time-series. assert_eq!(gauge_data_point.data_points.len(), 2); @@ -2119,7 +2203,9 @@ mod tests { test_context.flush_metrics(); - let gauge = test_context.get_aggregation::>("my_gauge", None); + let MetricData::Gauge(gauge) = test_context.get_aggregation::("my_gauge", None) else { + unreachable!() + }; assert_eq!(gauge.data_points.len(), 2); let data_point1 = find_gauge_datapoint_with_key_value(&gauge.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); @@ -2148,7 +2234,11 @@ mod tests { test_context.flush_metrics(); // Assert - let gauge = test_context.get_aggregation::>("test_observable_gauge", None); + let MetricData::Gauge(gauge) = + test_context.get_aggregation::("test_observable_gauge", None) + else { + unreachable!() + }; // Expecting 2 time-series. let expected_time_series_count = if use_empty_attributes { 3 } else { 2 }; assert_eq!(gauge.data_points.len(), expected_time_series_count); @@ -2176,7 +2266,11 @@ mod tests { test_context.flush_metrics(); - let gauge = test_context.get_aggregation::>("test_observable_gauge", None); + let MetricData::Gauge(gauge) = + test_context.get_aggregation::("test_observable_gauge", None) + else { + unreachable!() + }; assert_eq!(gauge.data_points.len(), expected_time_series_count); if use_empty_attributes { @@ -2214,7 +2308,9 @@ mod tests { test_context.flush_metrics(); // Assert - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; // Expecting 2 time-series. assert_eq!(sum.data_points.len(), 2); assert!(sum.is_monotonic, "Counter should produce monotonic."); @@ -2251,7 +2347,9 @@ mod tests { test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 2); let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); @@ -2291,7 +2389,9 @@ mod tests { counter.add(100, &[KeyValue::new("A", "yet_another")]); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; // Expecting 2002 metric points. (2000 + 1 overflow + Empty attributes) assert_eq!(sum.data_points.len(), 2002); @@ -2385,7 +2485,9 @@ mod tests { ); test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_counter", None) else { + unreachable!() + }; // Expecting 1 time-series. assert_eq!(sum.data_points.len(), 1); @@ -2414,7 +2516,10 @@ mod tests { test_context.flush_metrics(); // Assert - let sum = test_context.get_aggregation::>("my_updown_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_updown_counter", None) + else { + unreachable!() + }; // Expecting 2 time-series. assert_eq!(sum.data_points.len(), 2); assert!( @@ -2450,7 +2555,10 @@ mod tests { test_context.flush_metrics(); - let sum = test_context.get_aggregation::>("my_updown_counter", None); + let MetricData::Sum(sum) = test_context.get_aggregation::("my_updown_counter", None) + else { + unreachable!() + }; assert_eq!(sum.data_points.len(), 2); let data_point1 = find_sum_datapoint_with_key_value(&sum.data_points, "key1", "value1") .expect("datapoint with key1=value1 expected"); @@ -2605,11 +2713,11 @@ mod tests { assert!(resource_metrics.is_empty(), "no metrics should be exported"); } - fn get_aggregation( + fn get_aggregation( &mut self, counter_name: &str, unit_name: Option<&str>, - ) -> &T { + ) -> &MetricData { self.resource_metrics = self .exporter .get_finished_metrics() @@ -2641,19 +2749,16 @@ mod tests { assert_eq!(metric.unit, expected_unit); } - metric - .data - .as_any() - .downcast_ref::() + T::extract_metrics_data_ref(&metric.data) .expect("Failed to cast aggregation to expected type") } - fn get_from_multiple_aggregations( + fn get_from_multiple_aggregations( &mut self, counter_name: &str, unit_name: Option<&str>, invocation_count: usize, - ) -> Vec<&T> { + ) -> Vec<&MetricData> { self.resource_metrics = self .exporter .get_finished_metrics() @@ -2689,10 +2794,7 @@ mod tests { assert_eq!(metric.unit, expected_unit); } - let aggregation = metric - .data - .as_any() - .downcast_ref::() + let aggregation = T::extract_metrics_data_ref(&metric.data) .expect("Failed to cast aggregation to expected type"); aggregation }) diff --git a/opentelemetry-sdk/src/metrics/pipeline.rs b/opentelemetry-sdk/src/metrics/pipeline.rs index d8c9429c51..65d587e7cd 100644 --- a/opentelemetry-sdk/src/metrics/pipeline.rs +++ b/opentelemetry-sdk/src/metrics/pipeline.rs @@ -135,7 +135,7 @@ impl SdkProducer for Pipeline { let mut j = 0; for inst in instruments { let mut m = sm.metrics.get_mut(j); - match (inst.comp_agg.call(m.as_mut().map(|m| m.data.as_mut())), m) { + match (inst.comp_agg.call(m.as_mut().map(|m| &mut m.data)), m) { // No metric to re-use, expect agg to create new metric data ((len, Some(initial_agg)), None) if len > 0 => sm.metrics.push(Metric { name: inst.name.clone(), diff --git a/opentelemetry-stdout/src/metrics/exporter.rs b/opentelemetry-stdout/src/metrics/exporter.rs index a30e649baf..2e000a2dbe 100644 --- a/opentelemetry-stdout/src/metrics/exporter.rs +++ b/opentelemetry-stdout/src/metrics/exporter.rs @@ -1,12 +1,13 @@ use chrono::{DateTime, Utc}; use core::{f64, fmt}; +use opentelemetry_sdk::metrics::data::{AggregatedMetrics, MetricData}; use opentelemetry_sdk::metrics::Temporality; use opentelemetry_sdk::{ error::OTelSdkResult, metrics::{ data::{ - ExponentialHistogram, Gauge, GaugeDataPoint, Histogram, HistogramDataPoint, - ResourceMetrics, ScopeMetrics, Sum, SumDataPoint, + Gauge, GaugeDataPoint, Histogram, HistogramDataPoint, ResourceMetrics, ScopeMetrics, + Sum, SumDataPoint, }, exporter::PushMetricExporter, }, @@ -100,39 +101,32 @@ fn print_metrics(metrics: &[ScopeMetrics]) { println!("\t\tDescription : {}", &metric.description); println!("\t\tUnit : {}", &metric.unit); - let data = metric.data.as_any(); - if let Some(hist) = data.downcast_ref::>() { - println!("\t\tType : Histogram"); - print_histogram(hist); - } else if let Some(hist) = data.downcast_ref::>() { - println!("\t\tType : Histogram"); - print_histogram(hist); - } else if let Some(_hist) = data.downcast_ref::>() { - println!("\t\tType : Exponential Histogram"); - // TODO - } else if let Some(_hist) = data.downcast_ref::>() { - println!("\t\tType : Exponential Histogram"); - // TODO - } else if let Some(sum) = data.downcast_ref::>() { - println!("\t\tType : Sum"); - print_sum(sum); - } else if let Some(sum) = data.downcast_ref::>() { - println!("\t\tType : Sum"); - print_sum(sum); - } else if let Some(sum) = data.downcast_ref::>() { - println!("\t\tType : Sum"); - print_sum(sum); - } else if let Some(gauge) = data.downcast_ref::>() { - println!("\t\tType : Gauge"); - print_gauge(gauge); - } else if let Some(gauge) = data.downcast_ref::>() { - println!("\t\tType : Gauge"); - print_gauge(gauge); - } else if let Some(gauge) = data.downcast_ref::>() { - println!("\t\tType : Gauge"); - print_gauge(gauge); - } else { - println!("Unsupported data type"); + fn print_info(data: &MetricData) + where + T: Debug, + { + match data { + MetricData::Gauge(gauge) => { + println!("\t\tType : Gauge"); + print_gauge(gauge); + } + MetricData::Sum(sum) => { + println!("\t\tType : Sum"); + print_sum(sum); + } + MetricData::Histogram(hist) => { + println!("\t\tType : Histogram"); + print_histogram(hist); + } + MetricData::ExponentialHistogram(_) => { + println!("\t\tType : Exponential Histogram"); + } + } + } + match &metric.data { + AggregatedMetrics::F64(data) => print_info(data), + AggregatedMetrics::U64(data) => print_info(data), + AggregatedMetrics::I64(data) => print_info(data), } }); }