miden_node_utils/tracing/
span_ext.rs

1use core::time::Duration;
2use std::net::IpAddr;
3
4use miden_objects::Word;
5use miden_objects::account::AccountId;
6use miden_objects::batch::BatchId;
7use miden_objects::block::BlockNumber;
8use miden_objects::transaction::TransactionId;
9use opentelemetry::trace::Status;
10use opentelemetry::{Key, StringValue, Value};
11
12use crate::ErrorReport;
13
14/// Utility functions for converting types into [`opentelemetry::Value`].
15pub trait ToValue {
16    fn to_value(&self) -> Value;
17}
18
19impl<T: ToValue> ToValue for Vec<T> {
20    fn to_value(&self) -> Value {
21        let string_values = self.iter().map(|v| v.to_value().into()).collect::<Vec<StringValue>>();
22        Value::Array(string_values.into())
23    }
24}
25
26impl ToValue for Duration {
27    fn to_value(&self) -> Value {
28        self.as_secs_f64().into()
29    }
30}
31
32impl ToValue for Word {
33    fn to_value(&self) -> Value {
34        self.to_hex().into()
35    }
36}
37
38impl ToValue for AccountId {
39    fn to_value(&self) -> Value {
40        self.to_hex().into()
41    }
42}
43
44impl ToValue for BlockNumber {
45    fn to_value(&self) -> Value {
46        i64::from(self.as_u32()).into()
47    }
48}
49
50impl ToValue for BatchId {
51    fn to_value(&self) -> Value {
52        self.to_hex().into()
53    }
54}
55
56impl ToValue for TransactionId {
57    fn to_value(&self) -> Value {
58        self.to_hex().into()
59    }
60}
61
62impl ToValue for usize {
63    fn to_value(&self) -> Value {
64        i64::try_from(*self).unwrap_or(i64::MAX).into()
65    }
66}
67
68/// Generates `impl ToValue` blocks for types that are `ToString`.
69macro_rules! impl_to_string_to_value {
70    ($($t:ty),*) => {
71        $(
72            impl ToValue for $t {
73                fn to_value(&self) -> Value {
74                    self.to_string().into()
75                }
76            }
77        )*
78    };
79}
80impl_to_string_to_value!(IpAddr, &str);
81
82/// Generates `impl ToValue` blocks for integer types.
83macro_rules! impl_int_to_value {
84    ($($t:ty),*) => {
85        $(
86            impl ToValue for $t {
87                fn to_value(&self) -> Value {
88                    i64::from(*self).into()
89                }
90            }
91        )*
92    };
93}
94impl_int_to_value!(u16, u32);
95
96/// Generates `impl ToValue` blocks for types that are `Into<Value>`.
97macro_rules! impl_to_value {
98    ($($t:ty),*) => {
99        $(
100            impl ToValue for $t {
101                fn to_value(&self) -> Value {
102                    (*self).into()
103                }
104            }
105        )*
106    };
107}
108impl_to_value!(f64, i64);
109
110/// Utility functions based on [`tracing_opentelemetry::OpenTelemetrySpanExt`].
111///
112/// This is a sealed trait. It and cannot be implemented outside of this module.
113pub trait OpenTelemetrySpanExt: private::Sealed {
114    fn set_attribute(&self, key: impl Into<Key>, value: impl ToValue);
115    fn set_error(&self, err: &dyn std::error::Error);
116}
117
118impl<S> OpenTelemetrySpanExt for S
119where
120    S: tracing_opentelemetry::OpenTelemetrySpanExt,
121{
122    /// Sets an attribute on `Span`.
123    ///
124    /// Implementations for `ToValue` should be added to this crate (miden-node-utils).
125    fn set_attribute(&self, key: impl Into<Key>, value: impl ToValue) {
126        tracing_opentelemetry::OpenTelemetrySpanExt::set_attribute(self, key, value.to_value());
127    }
128
129    /// Sets a status on `Span` based on an error.
130    fn set_error(&self, err: &dyn std::error::Error) {
131        tracing_opentelemetry::OpenTelemetrySpanExt::set_status(
132            self,
133            Status::Error { description: err.as_report().into() },
134        );
135    }
136}
137
138mod private {
139    pub trait Sealed {}
140    impl<S> Sealed for S where S: tracing_opentelemetry::OpenTelemetrySpanExt {}
141}