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
60fn open_telemetry_layer<S>(
61 exporter: impl SpanExporter + 'static,
62) -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
63where
64 S: Subscriber + Sync + Send,
65 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
66{
67 let tracer = opentelemetry_sdk::trace::SdkTracerProvider::builder()
68 .with_batch_exporter(exporter)
69 .build();
70
71 let tracer = tracer.tracer("tracing-otel-subscriber");
72 OpenTelemetryLayer::new(tracer).boxed()
73}
74
75#[cfg(not(feature = "tracing-forest"))]
76fn stdout_layer<S>() -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
77where
78 S: Subscriber,
79 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
80{
81 use tracing_subscriber::fmt::format::FmtSpan;
82
83 tracing_subscriber::fmt::layer()
84 .pretty()
85 .compact()
86 .with_level(true)
87 .with_file(true)
88 .with_line_number(true)
89 .with_target(true)
90 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
91 .boxed()
92}
93
94#[cfg(feature = "tracing-forest")]
95fn stdout_layer<S>() -> Box<dyn tracing_subscriber::Layer<S> + Send + Sync + 'static>
96where
97 S: Subscriber,
98 for<'a> S: tracing_subscriber::registry::LookupSpan<'a>,
99{
100 tracing_forest::ForestLayer::default().boxed()
101}
102
103fn env_or_default_filter<S>() -> Box<dyn Filter<S> + Send + Sync + 'static> {
109 use tracing::level_filters::LevelFilter;
110 use tracing_subscriber::{
111 EnvFilter,
112 filter::{FilterExt, Targets},
113 };
114
115 match std::env::var(EnvFilter::DEFAULT_ENV) {
118 Ok(rust_log) => FilterExt::boxed(
119 EnvFilter::from_str(&rust_log)
120 .expect("RUST_LOG should contain a valid filter configuration"),
121 ),
122 Err(std::env::VarError::NotUnicode(_)) => panic!("RUST_LOG contained non-unicode"),
123 Err(std::env::VarError::NotPresent) => {
124 FilterExt::boxed(
126 Targets::new()
127 .with_default(LevelFilter::INFO)
128 .with_target("axum::rejection", LevelFilter::TRACE),
129 )
130 },
131 }
132}