miden_node_utils/tracing/
span_ext.rs

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