use std::{borrow::Cow, time::SystemTime};
use opentelemetry::{InstrumentationScope, KeyValue};
use crate::Resource;
use super::Temporality;
#[derive(Debug)]
pub struct ResourceMetrics {
pub(crate) resource: Resource,
pub(crate) scope_metrics: Vec<ScopeMetrics>,
}
impl Default for ResourceMetrics {
fn default() -> Self {
Self {
resource: Resource::empty(),
scope_metrics: Vec::new(),
}
}
}
impl ResourceMetrics {
pub fn resource(&self) -> &Resource {
&self.resource
}
pub fn scope_metrics(&self) -> impl Iterator<Item = &ScopeMetrics> {
self.scope_metrics.iter()
}
}
#[derive(Default, Debug)]
pub struct ScopeMetrics {
pub(crate) scope: InstrumentationScope,
pub(crate) metrics: Vec<Metric>,
}
impl ScopeMetrics {
pub fn scope(&self) -> &InstrumentationScope {
&self.scope
}
pub fn metrics(&self) -> impl Iterator<Item = &Metric> {
self.metrics.iter()
}
}
#[derive(Debug)]
pub struct Metric {
pub(crate) name: Cow<'static, str>,
pub(crate) description: Cow<'static, str>,
pub(crate) unit: Cow<'static, str>,
pub(crate) data: AggregatedMetrics,
}
impl Metric {
pub fn name(&self) -> &str {
&self.name
}
pub fn description(&self) -> &str {
&self.description
}
pub fn unit(&self) -> &str {
&self.unit
}
pub fn data(&self) -> &AggregatedMetrics {
&self.data
}
}
#[derive(Debug)]
pub enum AggregatedMetrics {
F64(MetricData<f64>),
U64(MetricData<u64>),
I64(MetricData<i64>),
}
#[derive(Debug)]
pub enum MetricData<T> {
Gauge(Gauge<T>),
Sum(Sum<T>),
Histogram(Histogram<T>),
ExponentialHistogram(ExponentialHistogram<T>),
}
impl From<MetricData<f64>> for AggregatedMetrics {
fn from(value: MetricData<f64>) -> Self {
AggregatedMetrics::F64(value)
}
}
impl From<MetricData<i64>> for AggregatedMetrics {
fn from(value: MetricData<i64>) -> Self {
AggregatedMetrics::I64(value)
}
}
impl From<MetricData<u64>> for AggregatedMetrics {
fn from(value: MetricData<u64>) -> Self {
AggregatedMetrics::U64(value)
}
}
impl<T> From<Gauge<T>> for MetricData<T> {
fn from(value: Gauge<T>) -> Self {
MetricData::Gauge(value)
}
}
impl<T> From<Sum<T>> for MetricData<T> {
fn from(value: Sum<T>) -> Self {
MetricData::Sum(value)
}
}
impl<T> From<Histogram<T>> for MetricData<T> {
fn from(value: Histogram<T>) -> Self {
MetricData::Histogram(value)
}
}
impl<T> From<ExponentialHistogram<T>> for MetricData<T> {
fn from(value: ExponentialHistogram<T>) -> Self {
MetricData::ExponentialHistogram(value)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct GaugeDataPoint<T> {
pub(crate) attributes: Vec<KeyValue>,
pub(crate) value: T,
pub(crate) exemplars: Vec<Exemplar<T>>,
}
impl<T> GaugeDataPoint<T> {
pub fn attributes(&self) -> impl Iterator<Item = &KeyValue> {
self.attributes.iter()
}
pub fn exemplars(&self) -> impl Iterator<Item = &Exemplar<T>> {
self.exemplars.iter()
}
}
impl<T: Copy> GaugeDataPoint<T> {
pub fn value(&self) -> T {
self.value
}
}
#[derive(Debug, Clone)]
pub struct Gauge<T> {
pub(crate) data_points: Vec<GaugeDataPoint<T>>,
pub(crate) start_time: Option<SystemTime>,
pub(crate) time: SystemTime,
}
impl<T> Gauge<T> {
pub fn data_points(&self) -> impl Iterator<Item = &GaugeDataPoint<T>> {
self.data_points.iter()
}
pub fn start_time(&self) -> Option<SystemTime> {
self.start_time
}
pub fn time(&self) -> SystemTime {
self.time
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SumDataPoint<T> {
pub(crate) attributes: Vec<KeyValue>,
pub(crate) value: T,
pub(crate) exemplars: Vec<Exemplar<T>>,
}
impl<T> SumDataPoint<T> {
pub fn attributes(&self) -> impl Iterator<Item = &KeyValue> {
self.attributes.iter()
}
pub fn exemplars(&self) -> impl Iterator<Item = &Exemplar<T>> {
self.exemplars.iter()
}
}
impl<T: Copy> SumDataPoint<T> {
pub fn value(&self) -> T {
self.value
}
}
#[derive(Debug, Clone)]
pub struct Sum<T> {
pub(crate) data_points: Vec<SumDataPoint<T>>,
pub(crate) start_time: SystemTime,
pub(crate) time: SystemTime,
pub(crate) temporality: Temporality,
pub(crate) is_monotonic: bool,
}
impl<T> Sum<T> {
pub fn data_points(&self) -> impl Iterator<Item = &SumDataPoint<T>> {
self.data_points.iter()
}
pub fn start_time(&self) -> SystemTime {
self.start_time
}
pub fn time(&self) -> SystemTime {
self.time
}
pub fn temporality(&self) -> Temporality {
self.temporality
}
pub fn is_monotonic(&self) -> bool {
self.is_monotonic
}
}
#[derive(Debug, Clone)]
pub struct Histogram<T> {
pub(crate) data_points: Vec<HistogramDataPoint<T>>,
pub(crate) start_time: SystemTime,
pub(crate) time: SystemTime,
pub(crate) temporality: Temporality,
}
impl<T> Histogram<T> {
pub fn data_points(&self) -> impl Iterator<Item = &HistogramDataPoint<T>> {
self.data_points.iter()
}
pub fn start_time(&self) -> SystemTime {
self.start_time
}
pub fn time(&self) -> SystemTime {
self.time
}
pub fn temporality(&self) -> Temporality {
self.temporality
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct HistogramDataPoint<T> {
pub(crate) attributes: Vec<KeyValue>,
pub(crate) count: u64,
pub(crate) bounds: Vec<f64>,
pub(crate) bucket_counts: Vec<u64>,
pub(crate) min: Option<T>,
pub(crate) max: Option<T>,
pub(crate) sum: T,
pub(crate) exemplars: Vec<Exemplar<T>>,
}
impl<T> HistogramDataPoint<T> {
pub fn attributes(&self) -> impl Iterator<Item = &KeyValue> {
self.attributes.iter()
}
pub fn exemplars(&self) -> impl Iterator<Item = &Exemplar<T>> {
self.exemplars.iter()
}
pub fn bounds(&self) -> impl Iterator<Item = f64> + '_ {
self.bounds.iter().copied()
}
pub fn bucket_counts(&self) -> impl Iterator<Item = u64> + '_ {
self.bucket_counts.iter().copied()
}
pub fn count(&self) -> u64 {
self.count
}
}
impl<T: Copy> HistogramDataPoint<T> {
pub fn min(&self) -> Option<T> {
self.min
}
pub fn max(&self) -> Option<T> {
self.max
}
pub fn sum(&self) -> T {
self.sum
}
}
#[derive(Debug, Clone)]
pub struct ExponentialHistogram<T> {
pub(crate) data_points: Vec<ExponentialHistogramDataPoint<T>>,
pub(crate) start_time: SystemTime,
pub(crate) time: SystemTime,
pub(crate) temporality: Temporality,
}
impl<T> ExponentialHistogram<T> {
pub fn data_points(&self) -> impl Iterator<Item = &ExponentialHistogramDataPoint<T>> {
self.data_points.iter()
}
pub fn start_time(&self) -> SystemTime {
self.start_time
}
pub fn time(&self) -> SystemTime {
self.time
}
pub fn temporality(&self) -> Temporality {
self.temporality
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ExponentialHistogramDataPoint<T> {
pub(crate) attributes: Vec<KeyValue>,
pub(crate) count: usize,
pub(crate) min: Option<T>,
pub(crate) max: Option<T>,
pub(crate) sum: T,
pub(crate) scale: i8,
pub(crate) zero_count: u64,
pub(crate) positive_bucket: ExponentialBucket,
pub(crate) negative_bucket: ExponentialBucket,
pub(crate) zero_threshold: f64,
pub(crate) exemplars: Vec<Exemplar<T>>,
}
impl<T> ExponentialHistogramDataPoint<T> {
pub fn attributes(&self) -> impl Iterator<Item = &KeyValue> {
self.attributes.iter()
}
pub fn exemplars(&self) -> impl Iterator<Item = &Exemplar<T>> {
self.exemplars.iter()
}
pub fn count(&self) -> usize {
self.count
}
pub fn scale(&self) -> i8 {
self.scale
}
pub fn zero_count(&self) -> u64 {
self.zero_count
}
pub fn positive_bucket(&self) -> &ExponentialBucket {
&self.positive_bucket
}
pub fn negative_bucket(&self) -> &ExponentialBucket {
&self.negative_bucket
}
pub fn zero_threshold(&self) -> f64 {
self.zero_threshold
}
}
impl<T: Copy> ExponentialHistogramDataPoint<T> {
pub fn min(&self) -> Option<T> {
self.min
}
pub fn max(&self) -> Option<T> {
self.max
}
pub fn sum(&self) -> T {
self.sum
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ExponentialBucket {
pub(crate) offset: i32,
pub(crate) counts: Vec<u64>,
}
impl ExponentialBucket {
pub fn offset(&self) -> i32 {
self.offset
}
pub fn counts(&self) -> impl Iterator<Item = u64> + '_ {
self.counts.iter().copied()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Exemplar<T> {
pub(crate) filtered_attributes: Vec<KeyValue>,
pub(crate) time: SystemTime,
pub value: T,
pub(crate) span_id: [u8; 8],
pub(crate) trace_id: [u8; 16],
}
impl<T> Exemplar<T> {
pub fn filtered_attributes(&self) -> impl Iterator<Item = &KeyValue> {
self.filtered_attributes.iter()
}
pub fn time(&self) -> SystemTime {
self.time
}
pub fn span_id(&self) -> &[u8; 8] {
&self.span_id
}
pub fn trace_id(&self) -> &[u8; 16] {
&self.trace_id
}
}
#[cfg(test)]
mod tests {
use super::{Exemplar, ExponentialHistogramDataPoint, HistogramDataPoint, SumDataPoint};
use opentelemetry::time::now;
use opentelemetry::KeyValue;
#[test]
fn validate_cloning_data_points() {
let data_type = SumDataPoint {
attributes: vec![KeyValue::new("key", "value")],
value: 0u32,
exemplars: vec![Exemplar {
filtered_attributes: vec![],
time: now(),
value: 0u32,
span_id: [0; 8],
trace_id: [0; 16],
}],
};
assert_eq!(data_type.clone(), data_type);
let histogram_data_point = HistogramDataPoint {
attributes: vec![KeyValue::new("key", "value")],
count: 0,
bounds: vec![],
bucket_counts: vec![],
min: None,
max: None,
sum: 0u32,
exemplars: vec![Exemplar {
filtered_attributes: vec![],
time: now(),
value: 0u32,
span_id: [0; 8],
trace_id: [0; 16],
}],
};
assert_eq!(histogram_data_point.clone(), histogram_data_point);
let exponential_histogram_data_point = ExponentialHistogramDataPoint {
attributes: vec![KeyValue::new("key", "value")],
count: 0,
min: None,
max: None,
sum: 0u32,
scale: 0,
zero_count: 0,
positive_bucket: super::ExponentialBucket {
offset: 0,
counts: vec![],
},
negative_bucket: super::ExponentialBucket {
offset: 0,
counts: vec![],
},
zero_threshold: 0.0,
exemplars: vec![Exemplar {
filtered_attributes: vec![],
time: now(),
value: 0u32,
span_id: [0; 8],
trace_id: [0; 16],
}],
};
assert_eq!(
exponential_histogram_data_point.clone(),
exponential_histogram_data_point
);
}
}