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            .into_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                        .into_iter()
74                        .map(Into::into)
75                        .collect(),
76                    time: e.time.into(),
77                    value: e.value.into(),
78                    span_id,
79                    trace_id,
80                }
81            })
82            .collect()
83    };
84}
85
86/// Converts a WASI Gauge to an OTel Gauge
87macro_rules! wasi_gauge_to_otel {
88    ($gauge:expr, $number_type:ty) => {
89        Box::new(opentelemetry_sdk::metrics::data::Gauge {
90            data_points: $gauge
91                .data_points
92                .into_iter()
93                .map(|dp| opentelemetry_sdk::metrics::data::GaugeDataPoint {
94                    attributes: dp.attributes.into_iter().map(Into::into).collect(),
95                    value: dp.value.into(),
96                    exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
97                })
98                .collect(),
99            start_time: match $gauge.start_time {
100                Some(t) => Some(t.into()),
101                None => None,
102            },
103            time: $gauge.time.into(),
104        })
105    };
106}
107
108/// Converts a WASI Sum to an OTel Sum
109macro_rules! wasi_sum_to_otel {
110    ($sum:expr, $number_type:ty) => {
111        Box::new(opentelemetry_sdk::metrics::data::Sum {
112            data_points: $sum
113                .data_points
114                .into_iter()
115                .map(|dp| opentelemetry_sdk::metrics::data::SumDataPoint {
116                    attributes: dp.attributes.into_iter().map(Into::into).collect(),
117                    exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
118                    value: dp.value.into(),
119                })
120                .collect(),
121            start_time: $sum.start_time.into(),
122            time: $sum.time.into(),
123            temporality: $sum.temporality.into(),
124            is_monotonic: $sum.is_monotonic,
125        })
126    };
127}
128
129/// Converts a WASI Histogram to an OTel Histogram
130macro_rules! wasi_histogram_to_otel {
131    ($histogram:expr, $number_type:ty) => {
132        Box::new(opentelemetry_sdk::metrics::data::Histogram {
133            data_points: $histogram
134                .data_points
135                .into_iter()
136                .map(|dp| opentelemetry_sdk::metrics::data::HistogramDataPoint {
137                    attributes: dp.attributes.into_iter().map(Into::into).collect(),
138                    bounds: dp.bounds,
139                    bucket_counts: dp.bucket_counts,
140                    exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
141                    count: dp.count,
142                    max: match dp.max {
143                        Some(m) => Some(m.into()),
144                        None => None,
145                    },
146                    min: match dp.min {
147                        Some(m) => Some(m.into()),
148                        None => None,
149                    },
150                    sum: dp.sum.into(),
151                })
152                .collect(),
153            start_time: $histogram.start_time.into(),
154            time: $histogram.time.into(),
155            temporality: $histogram.temporality.into(),
156        })
157    };
158}
159
160/// Converts a WASI ExponentialHistogram to an OTel ExponentialHistogram
161macro_rules! wasi_exponential_histogram_to_otel {
162    ($histogram:expr, $number_type:ty) => {
163        Box::new(opentelemetry_sdk::metrics::data::ExponentialHistogram {
164            data_points: $histogram
165                .data_points
166                .into_iter()
167                .map(
168                    |dp| opentelemetry_sdk::metrics::data::ExponentialHistogramDataPoint {
169                        attributes: dp.attributes.into_iter().map(Into::into).collect(),
170                        exemplars: exemplars_to_otel!(dp.exemplars, $number_type),
171                        count: dp.count as usize,
172                        max: match dp.max {
173                            Some(m) => Some(m.into()),
174                            None => None,
175                        },
176                        min: match dp.min {
177                            Some(m) => Some(m.into()),
178                            None => None,
179                        },
180                        sum: dp.sum.into(),
181                        scale: dp.scale,
182                        zero_count: dp.zero_count,
183                        positive_bucket: dp.positive_bucket.into(),
184                        negative_bucket: dp.negative_bucket.into(),
185                        zero_threshold: dp.zero_threshold,
186                    },
187                )
188                .collect(),
189            start_time: $histogram.start_time.into(),
190            time: $histogram.time.into(),
191            temporality: $histogram.temporality.into(),
192        })
193    };
194}
195
196impl From<wasi::otel::metrics::MetricData>
197    for Box<dyn opentelemetry_sdk::metrics::data::Aggregation>
198{
199    fn from(value: wasi::otel::metrics::MetricData) -> Self {
200        match value {
201            wasi::otel::metrics::MetricData::F64Sum(s) => wasi_sum_to_otel!(s, f64),
202            wasi::otel::metrics::MetricData::S64Sum(s) => wasi_sum_to_otel!(s, i64),
203            wasi::otel::metrics::MetricData::U64Sum(s) => wasi_sum_to_otel!(s, u64),
204            wasi::otel::metrics::MetricData::F64Gauge(g) => wasi_gauge_to_otel!(g, f64),
205            wasi::otel::metrics::MetricData::S64Gauge(g) => wasi_gauge_to_otel!(g, i64),
206            wasi::otel::metrics::MetricData::U64Gauge(g) => wasi_gauge_to_otel!(g, u64),
207            wasi::otel::metrics::MetricData::F64Histogram(h) => wasi_histogram_to_otel!(h, f64),
208            wasi::otel::metrics::MetricData::S64Histogram(h) => wasi_histogram_to_otel!(h, i64),
209            wasi::otel::metrics::MetricData::U64Histogram(h) => wasi_histogram_to_otel!(h, u64),
210            wasi::otel::metrics::MetricData::F64ExponentialHistogram(h) => {
211                wasi_exponential_histogram_to_otel!(h, f64)
212            }
213            wasi::otel::metrics::MetricData::S64ExponentialHistogram(h) => {
214                wasi_exponential_histogram_to_otel!(h, i64)
215            }
216            wasi::otel::metrics::MetricData::U64ExponentialHistogram(h) => {
217                wasi_exponential_histogram_to_otel!(h, u64)
218            }
219        }
220    }
221}
222
223impl From<wasi::otel::metrics::MetricNumber> for f64 {
224    fn from(value: wasi::otel::metrics::MetricNumber) -> Self {
225        match value {
226            wasi::otel::metrics::MetricNumber::F64(n) => n,
227            _ => panic!("error converting WASI MetricNumber to f64"),
228        }
229    }
230}
231
232impl From<wasi::otel::metrics::MetricNumber> for u64 {
233    fn from(value: wasi::otel::metrics::MetricNumber) -> Self {
234        match value {
235            wasi::otel::metrics::MetricNumber::U64(n) => n,
236            _ => panic!("error converting WASI MetricNumber to u64"),
237        }
238    }
239}
240
241impl From<wasi::otel::metrics::MetricNumber> for i64 {
242    fn from(value: wasi::otel::metrics::MetricNumber) -> Self {
243        match value {
244            wasi::otel::metrics::MetricNumber::S64(n) => n,
245            _ => panic!("error converting WASI MetricNumber to i64"),
246        }
247    }
248}
249
250impl From<wasi::otel::metrics::ExponentialBucket>
251    for opentelemetry_sdk::metrics::data::ExponentialBucket
252{
253    fn from(value: wasi::otel::metrics::ExponentialBucket) -> Self {
254        Self {
255            offset: value.offset,
256            counts: value.counts,
257        }
258    }
259}
260
261impl From<wasi::otel::metrics::Temporality> for opentelemetry_sdk::metrics::Temporality {
262    fn from(value: wasi::otel::metrics::Temporality) -> Self {
263        use opentelemetry_sdk::metrics::Temporality;
264        match value {
265            wasi::otel::metrics::Temporality::Cumulative => Temporality::Cumulative,
266            wasi::otel::metrics::Temporality::Delta => Temporality::Delta,
267            wasi::otel::metrics::Temporality::LowMemory => Temporality::LowMemory,
268        }
269    }
270}