miden_node_utils/
logging.rs1use std::str::FromStr;
2
3use anyhow::Result;
4use opentelemetry::trace::TracerProvider as _;
5use opentelemetry_otlp::WithTonicConfig;
6use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::SpanExporter};
7use tracing::subscriber::Subscriber;
8use tracing_opentelemetry::OpenTelemetryLayer;
9use tracing_subscriber::{
10 Layer, Registry,
11 layer::{Filter, SubscriberExt},
12};
13
14#[derive(Clone, Copy)]
16pub enum OpenTelemetry {
17 Enabled,
18 Disabled,
19}
20
21impl OpenTelemetry {
22 fn is_enabled(self) -> bool {
23 matches!(self, OpenTelemetry::Enabled)
24 }
25}
26
27pub fn setup_tracing(otel: OpenTelemetry) -> 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::into)
58}
59
60#[cfg(feature = "testing")]
69pub fn setup_test_tracing() -> Result<(
70 tokio::sync::mpsc::UnboundedReceiver<opentelemetry_sdk::trace::SpanData>,
71 tokio::sync::mpsc::UnboundedReceiver<()>,
72)> {
73 let (exporter, rx_export, rx_shutdown) =
74 opentelemetry_sdk::testing::trace::new_tokio_test_exporter();
75
76 let otel_layer = open_telemetry_layer(exporter);
77 let subscriber = Registry::default()
78 .with(stdout_layer().with_filter(env_or_default_filter()))
79 .with(otel_layer.with_filter(env_or_default_filter()));
80 tracing::subscriber::set_global_default(subscriber)?;
81 Ok((rx_export, rx_shutdown))
82}
83
84fn open_telemetry_layer<S>(
85 exporter: impl SpanExporter + 'static,
86) -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
87where
88 S: Subscriber + Sync + Send,
89 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
90{
91 let tracer = opentelemetry_sdk::trace::SdkTracerProvider::builder()
92 .with_batch_exporter(exporter)
93 .build();
94
95 let tracer = tracer.tracer("tracing-otel-subscriber");
96 OpenTelemetryLayer::new(tracer).boxed()
97}
98
99#[cfg(not(feature = "tracing-forest"))]
100fn stdout_layer<S>() -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
101where
102 S: Subscriber,
103 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
104{
105 use tracing_subscriber::fmt::format::FmtSpan;
106
107 tracing_subscriber::fmt::layer()
108 .pretty()
109 .compact()
110 .with_level(true)
111 .with_file(true)
112 .with_line_number(true)
113 .with_target(true)
114 .with_span_events(FmtSpan::CLOSE)
115 .boxed()
116}
117
118#[cfg(feature = "tracing-forest")]
119fn stdout_layer<S>() -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
120where
121 S: Subscriber,
122 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
123{
124 tracing_forest::ForestLayer::default().boxed()
125}
126
127fn env_or_default_filter<S>() -> Box<dyn Filter<S> + Send + Sync + 'static> {
133 use tracing::level_filters::LevelFilter;
134 use tracing_subscriber::{
135 EnvFilter,
136 filter::{FilterExt, Targets},
137 };
138
139 match std::env::var(EnvFilter::DEFAULT_ENV) {
142 Ok(rust_log) => FilterExt::boxed(
143 EnvFilter::from_str(&rust_log)
144 .expect("RUST_LOG should contain a valid filter configuration"),
145 ),
146 Err(std::env::VarError::NotUnicode(_)) => panic!("RUST_LOG contained non-unicode"),
147 Err(std::env::VarError::NotPresent) => {
148 FilterExt::boxed(
150 Targets::new()
151 .with_default(LevelFilter::INFO)
152 .with_target("axum::rejection", LevelFilter::TRACE),
153 )
154 },
155 }
156}