miden_node_utils/
logging.rs1use std::str::FromStr;
2
3use opentelemetry::trace::TracerProvider as _;
4use opentelemetry_otlp::WithTonicConfig;
5use opentelemetry_sdk::propagation::TraceContextPropagator;
6use opentelemetry_sdk::trace::SpanExporter;
7use tracing::subscriber::Subscriber;
8use tracing_opentelemetry::OpenTelemetryLayer;
9use tracing_subscriber::layer::{Filter, SubscriberExt};
10use tracing_subscriber::{Layer, Registry};
11
12#[derive(Clone, Copy)]
14pub enum OpenTelemetry {
15 Enabled,
16 Disabled,
17}
18
19impl OpenTelemetry {
20 fn is_enabled(self) -> bool {
21 matches!(self, OpenTelemetry::Enabled)
22 }
23}
24
25pub fn setup_tracing(otel: OpenTelemetry) -> anyhow::Result<()> {
35 if otel.is_enabled() {
36 opentelemetry::global::set_text_map_propagator(TraceContextPropagator::new());
37 }
38
39 let otel_layer = {
43 if otel.is_enabled() {
44 let exporter = opentelemetry_otlp::SpanExporter::builder()
45 .with_tonic()
46 .with_tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots())
47 .build()?;
48 Some(open_telemetry_layer(exporter))
49 } else {
50 None
51 }
52 };
53
54 let subscriber = Registry::default()
55 .with(stdout_layer().with_filter(env_or_default_filter()))
56 .with(otel_layer.with_filter(env_or_default_filter()));
57 tracing::subscriber::set_global_default(subscriber).map_err(Into::<anyhow::Error>::into)?;
58
59 std::panic::set_hook(Box::new(|info| {
61 tracing::error!(panic = true, "{info}");
62 }));
63 Ok(())
64}
65
66#[cfg(feature = "testing")]
75pub fn setup_test_tracing() -> anyhow::Result<(
76 tokio::sync::mpsc::UnboundedReceiver<opentelemetry_sdk::trace::SpanData>,
77 tokio::sync::mpsc::UnboundedReceiver<()>,
78)> {
79 let (exporter, rx_export, rx_shutdown) =
80 opentelemetry_sdk::testing::trace::new_tokio_test_exporter();
81
82 let otel_layer = open_telemetry_layer(exporter);
83 let subscriber = Registry::default()
84 .with(stdout_layer().with_filter(env_or_default_filter()))
85 .with(otel_layer.with_filter(env_or_default_filter()));
86 tracing::subscriber::set_global_default(subscriber)?;
87 Ok((rx_export, rx_shutdown))
88}
89
90fn open_telemetry_layer<S>(
91 exporter: impl SpanExporter + 'static,
92) -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
93where
94 S: Subscriber + Sync + Send,
95 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
96{
97 let tracer = opentelemetry_sdk::trace::SdkTracerProvider::builder()
98 .with_batch_exporter(exporter)
99 .build();
100
101 let tracer = tracer.tracer("tracing-otel-subscriber");
102 OpenTelemetryLayer::new(tracer).boxed()
103}
104
105#[cfg(not(feature = "tracing-forest"))]
106fn stdout_layer<S>() -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
107where
108 S: Subscriber,
109 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
110{
111 use tracing_subscriber::fmt::format::FmtSpan;
112
113 tracing_subscriber::fmt::layer()
114 .pretty()
115 .compact()
116 .with_level(true)
117 .with_file(true)
118 .with_line_number(true)
119 .with_target(true)
120 .with_span_events(FmtSpan::CLOSE)
121 .boxed()
122}
123
124#[cfg(feature = "tracing-forest")]
125fn stdout_layer<S>() -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
126where
127 S: Subscriber,
128 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
129{
130 tracing_forest::ForestLayer::default().boxed()
131}
132
133fn env_or_default_filter<S>() -> Box<dyn Filter<S> + Send + Sync + 'static> {
139 use tracing::level_filters::LevelFilter;
140 use tracing_subscriber::EnvFilter;
141 use tracing_subscriber::filter::{FilterExt, Targets};
142
143 match std::env::var(EnvFilter::DEFAULT_ENV) {
146 Ok(rust_log) => FilterExt::boxed(
147 EnvFilter::from_str(&rust_log)
148 .expect("RUST_LOG should contain a valid filter configuration"),
149 ),
150 Err(std::env::VarError::NotUnicode(_)) => panic!("RUST_LOG contained non-unicode"),
151 Err(std::env::VarError::NotPresent) => {
152 FilterExt::boxed(
154 Targets::new()
155 .with_default(LevelFilter::INFO)
156 .with_target("axum::rejection", LevelFilter::TRACE),
157 )
158 },
159 }
160}