miden_node_utils/tracing/
span_ext.rs1use core::time::Duration;
2use std::net::IpAddr;
3
4use miden_objects::{Digest, batch::BatchId, block::BlockNumber};
5use opentelemetry::{Key, Value, trace::Status};
6
7use crate::ErrorReport;
8
9pub trait ToValue {
11 fn to_value(&self) -> Value;
12}
13
14impl ToValue for Duration {
15 fn to_value(&self) -> Value {
16 self.as_secs_f64().into()
17 }
18}
19
20impl ToValue for Digest {
21 fn to_value(&self) -> Value {
22 self.to_hex().into()
23 }
24}
25
26impl ToValue for BlockNumber {
27 fn to_value(&self) -> Value {
28 i64::from(self.as_u32()).into()
29 }
30}
31
32impl ToValue for BatchId {
33 fn to_value(&self) -> Value {
34 self.to_hex().into()
35 }
36}
37
38impl ToValue for usize {
39 fn to_value(&self) -> Value {
40 i64::try_from(*self).unwrap_or(i64::MAX).into()
41 }
42}
43
44macro_rules! impl_to_string_to_value {
46 ($($t:ty),*) => {
47 $(
48 impl ToValue for $t {
49 fn to_value(&self) -> Value {
50 self.to_string().into()
51 }
52 }
53 )*
54 };
55}
56impl_to_string_to_value!(IpAddr, &str);
57
58macro_rules! impl_int_to_value {
60 ($($t:ty),*) => {
61 $(
62 impl ToValue for $t {
63 fn to_value(&self) -> Value {
64 i64::from(*self).into()
65 }
66 }
67 )*
68 };
69}
70impl_int_to_value!(u16, u32);
71
72macro_rules! impl_to_value {
74 ($($t:ty),*) => {
75 $(
76 impl ToValue for $t {
77 fn to_value(&self) -> Value {
78 (*self).into()
79 }
80 }
81 )*
82 };
83}
84impl_to_value!(f64, i64);
85
86pub trait OpenTelemetrySpanExt: private::Sealed {
90 fn set_attribute(&self, key: impl Into<Key>, value: impl ToValue);
91 fn set_error(&self, err: &dyn std::error::Error);
92}
93
94impl<S> OpenTelemetrySpanExt for S
95where
96 S: tracing_opentelemetry::OpenTelemetrySpanExt,
97{
98 fn set_attribute(&self, key: impl Into<Key>, value: impl ToValue) {
102 tracing_opentelemetry::OpenTelemetrySpanExt::set_attribute(self, key, value.to_value());
103 }
104
105 fn set_error(&self, err: &dyn std::error::Error) {
107 use std::fmt::Write as _;
108 let mut report = err.to_string();
110
111 std::iter::successors(err.source(), |child| child.source()).for_each(|source| {
112 let _ = write!(&mut report, "\nCaused by: {source}");
113 });
114
115 tracing_opentelemetry::OpenTelemetrySpanExt::set_status(
116 self,
117 Status::Error { description: err.as_report().into() },
118 );
119 }
120}
121
122mod private {
123 pub trait Sealed {}
124 impl<S> Sealed for S where S: tracing_opentelemetry::OpenTelemetrySpanExt {}
125}