Skip to main content

spin_world/wasi_otel/
metric_conversions.rs

1use crate::wasi;
2use std::borrow::Cow;
3
4impl From<wasi::otel::metrics::ResourceMetrics>
5    for opentelemetry_sdk::metrics::data::ResourceMetrics
6{
7    fn from(value: wasi::otel::metrics::ResourceMetrics) -> Self {
8        Self {
9            resource: value.resource.into(),
10            scope_metrics: value.scope_metrics.into_iter().map(Into::into).collect(),
11        }
12    }
13}
14
15impl From<wasi::otel::metrics::Resource> for opentelemetry_sdk::Resource {
16    fn from(value: wasi::otel::metrics::Resource) -> Self {
17        let attributes: Vec<opentelemetry::KeyValue> =
18            value.attributes.into_iter().map(Into::into).collect();
19        let schema_url: Option<String> = value.schema_url;
20        match schema_url {
21            Some(url) => opentelemetry_sdk::resource::Resource::builder()
22                .with_schema_url(attributes, url)
23                .build(),
24            None => opentelemetry_sdk::resource::Resource::builder()
25                .with_attributes(attributes)
26                .build(),
27        }
28    }
29}
30
31impl From<wasi::otel::metrics::ScopeMetrics> for opentelemetry_sdk::metrics::data::ScopeMetrics {
32    fn from(value: wasi::otel::metrics::ScopeMetrics) -> Self {
33        Self {
34            scope: value.scope.into(),
35            metrics: value.metrics.into_iter().map(Into::into).collect(),
36        }
37    }
38}
39
40impl From<wasi::otel::metrics::Metric> for opentelemetry_sdk::metrics::data::Metric {
41    fn from(value: wasi::otel::metrics::Metric) -> Self {
42        Self {
43            name: Cow::Owned(value.name),
44            description: Cow::Owned(value.description),
45            unit: Cow::Owned(value.unit),
46            data: value.data.into(),
47        }
48    }
49}
50
51/// Converts a Wasi exemplar to an OTel exemplar
52macro_rules! exemplars_to_otel {
53    (
54            $wasi_exemplar_list:expr,
55            $exemplar_type:ty
56        ) => {
57        $wasi_exemplar_list
58            .iter()
59            .map(|e| {
60                let span_id: [u8; 8] = e
61                    .span_id
62                    .as_bytes()
63                    .try_into()
64                    .expect("failed to parse span ID");
65                let trace_id: [u8; 16] = e
66                    .trace_id
67                    .as_bytes()
68                    .try_into()
69                    .expect("failed to parse trace ID");
70                opentelemetry_sdk::metrics::data::Exemplar::<$exemplar_type> {
71                    filtered_attributes: e
72                        .filtered_attributes
73                        .to_owned()
74                        .into_iter()
75                        .map(Into::into)
76                        .collect(),
77                    time: e.time.into(),
78                    value: e.value.into(),
79                    span_id,
80                    trace_id,
81                }
82            })
83            .collect()
84    };
85}
86
87/// Converts a WASI Gauge to an OTel Gauge
88macro_rules! wasi_gauge_to_otel {
89    ($gauge:expr, $number_type:ty) => {
90        Box::new(opentelemetry_sdk::metrics::data::Gauge {
91            data_points: $gauge
92                .data_points
93                .iter()
94                .map(|dp| opentelemetry_sdk::metrics::data::GaugeDataPoint {
95                    attributes: dp.attributes.iter().map(Into::into).collect(),
96                    value: dp.value.into(),
97                    exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
98                })
99                .collect(),
100            start_time: match $gauge.start_time {
101                Some(t) => Some(t.into()),
102                None => None,
103            },
104            time: $gauge.time.into(),
105        })
106    };
107}
108
109/// Converts a WASI Sum to an OTel Sum
110macro_rules! wasi_sum_to_otel {
111    ($sum:expr, $number_type:ty) => {
112        Box::new(opentelemetry_sdk::metrics::data::Sum {
113            data_points: $sum
114                .data_points
115                .iter()
116                .map(|dp| opentelemetry_sdk::metrics::data::SumDataPoint {
117                    attributes: dp.attributes.iter().map(Into::into).collect(),
118                    exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
119                    value: dp.value.into(),
120                })
121                .collect(),
122            start_time: $sum.start_time.into(),
123            time: $sum.time.into(),
124            temporality: $sum.temporality.into(),
125            is_monotonic: $sum.is_monotonic,
126        })
127    };
128}
129
130/// Converts a WASI Histogram to an OTel Histogram
131macro_rules! wasi_histogram_to_otel {
132    ($histogram:expr, $number_type:ty) => {
133        Box::new(opentelemetry_sdk::metrics::data::Histogram {
134            data_points: $histogram
135                .data_points
136                .iter()
137                .map(|dp| opentelemetry_sdk::metrics::data::HistogramDataPoint {
138                    attributes: dp.attributes.iter().map(Into::into).collect(),
139                    bounds: dp.bounds.to_owned(),
140                    bucket_counts: dp.bucket_counts.to_owned(),
141                    exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
142                    count: dp.count,
143                    max: match dp.max {
144                        Some(m) => Some(m.into()),
145                        None => None,
146                    },
147                    min: match dp.min {
148                        Some(m) => Some(m.into()),
149                        None => None,
150                    },
151                    sum: dp.sum.into(),
152                })
153                .collect(),
154            start_time: $histogram.start_time.into(),
155            time: $histogram.time.into(),
156            temporality: $histogram.temporality.into(),
157        })
158    };
159}
160
161/// Converts a WASI ExponentialHistogram to an OTel ExponentialHistogram
162macro_rules! wasi_exponential_histogram_to_otel {
163    ($histogram:expr, $number_type:ty) => {
164        Box::new(opentelemetry_sdk::metrics::data::ExponentialHistogram {
165            data_points: $histogram
166                .data_points
167                .iter()
168                .map(
169                    |dp| opentelemetry_sdk::metrics::data::ExponentialHistogramDataPoint {
170                        attributes: dp.attributes.iter().map(Into::into).collect(),
171                        exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
172                        count: dp.count as usize,
173                        max: match dp.max {
174                            Some(m) => Some(m.into()),
175                            None => None,
176                        },
177                        min: match dp.min {
178                            Some(m) => Some(m.into()),
179                            None => None,
180                        },
181                        sum: dp.sum.into(),
182                        scale: dp.scale,
183                        zero_count: dp.zero_count,
184                        positive_bucket: dp.positive_bucket.to_owned().into(),
185                        negative_bucket: dp.negative_bucket.to_owned().into(),
186                        zero_threshold: dp.zero_threshold,
187                    },
188                )
189                .collect(),
190            start_time: $histogram.start_time.into(),
191            time: $histogram.time.into(),
192            temporality: $histogram.temporality.into(),
193        })
194    };
195}
196
197impl From<wasi::otel::metrics::MetricData>
198    for Box<dyn opentelemetry_sdk::metrics::data::Aggregation>
199{
200    fn from(value: wasi::otel::metrics::MetricData) -> Self {
201        match value {
202            wasi::otel::metrics::MetricData::F64Sum(s) => wasi_sum_to_otel!(s, f64),
203            wasi::otel::metrics::MetricData::S64Sum(s) => wasi_sum_to_otel!(s, i64),
204            wasi::otel::metrics::MetricData::U64Sum(s) => wasi_sum_to_otel!(s, u64),
205            wasi::otel::metrics::MetricData::F64Gauge(g) => wasi_gauge_to_otel!(g, f64),
206            wasi::otel::metrics::MetricData::S64Gauge(g) => wasi_gauge_to_otel!(g, i64),
207            wasi::otel::metrics::MetricData::U64Gauge(g) => wasi_gauge_to_otel!(g, u64),
208            wasi::otel::metrics::MetricData::F64Histogram(h) => wasi_histogram_to_otel!(h, f64),
209            wasi::otel::metrics::MetricData::S64Histogram(h) => wasi_histogram_to_otel!(h, i64),
210            wasi::otel::metrics::MetricData::U64Histogram(h) => wasi_histogram_to_otel!(h, u64),
211            wasi::otel::metrics::MetricData::F64ExponentialHistogram(h) => {
212                wasi_exponential_histogram_to_otel!(h, f64)
213            }
214            wasi::otel::metrics::MetricData::S64ExponentialHistogram(h) => {
215                wasi_exponential_histogram_to_otel!(h, i64)
216            }
217            wasi::otel::metrics::MetricData::U64ExponentialHistogram(h) => {
218                wasi_exponential_histogram_to_otel!(h, u64)
219            }
220        }
221    }
222}
223
224impl From<wasi::otel::metrics::MetricNumber> for f64 {
225    fn from(value: wasi::otel::metrics::MetricNumber) -> Self {
226        match value {
227            wasi::otel::metrics::MetricNumber::F64(n) => n,
228            _ => panic!("error converting WASI MetricNumber to f64"),
229        }
230    }
231}
232
233impl From<wasi::otel::metrics::MetricNumber> for u64 {
234    fn from(value: wasi::otel::metrics::MetricNumber) -> Self {
235        match value {
236            wasi::otel::metrics::MetricNumber::U64(n) => n,
237            _ => panic!("error converting WASI MetricNumber to u64"),
238        }
239    }
240}
241
242impl From<wasi::otel::metrics::MetricNumber> for i64 {
243    fn from(value: wasi::otel::metrics::MetricNumber) -> Self {
244        match value {
245            wasi::otel::metrics::MetricNumber::S64(n) => n,
246            _ => panic!("error converting WASI MetricNumber to i64"),
247        }
248    }
249}
250
251impl From<wasi::otel::metrics::ExponentialBucket>
252    for opentelemetry_sdk::metrics::data::ExponentialBucket
253{
254    fn from(value: wasi::otel::metrics::ExponentialBucket) -> Self {
255        Self {
256            offset: value.offset,
257            counts: value.counts,
258        }
259    }
260}
261
262impl From<wasi::otel::metrics::Temporality> for opentelemetry_sdk::metrics::Temporality {
263    fn from(value: wasi::otel::metrics::Temporality) -> Self {
264        use opentelemetry_sdk::metrics::Temporality;
265        match value {
266            wasi::otel::metrics::Temporality::Cumulative => Temporality::Cumulative,
267            wasi::otel::metrics::Temporality::Delta => Temporality::Delta,
268            wasi::otel::metrics::Temporality::LowMemory => Temporality::LowMemory,
269        }
270    }
271}