cairo_lang_utils/
logging.rs

1use std::sync::Once;
2
3use tracing_subscriber::EnvFilter;
4use tracing_subscriber::filter::dynamic_filter_fn;
5use tracing_subscriber::prelude::*;
6
7static INIT: Once = Once::new();
8
9pub mod level {
10    pub const TRACE: tracing::Level = tracing::Level::TRACE;
11    pub const DEBUG: tracing::Level = tracing::Level::DEBUG;
12    pub const INFO: tracing::Level = tracing::Level::INFO;
13    pub const WARN: tracing::Level = tracing::Level::WARN;
14    pub const ERROR: tracing::Level = tracing::Level::ERROR;
15}
16
17/// Initializes logging (tracing library).
18/// The format is:
19/// `<level>  /path/to/file:<line_number>  <time>  <log_message>`
20pub fn init_logging(level: tracing::Level) {
21    INIT.call_once(|| {
22        // Bridge log records to tracing so existing log macros still work via tracing-log
23        tracing_log::LogTracer::init().ok();
24
25        let env_filter = EnvFilter::try_from_default_env()
26            .or_else(|_| EnvFilter::try_new(level.to_string()))
27            .unwrap();
28
29        // Custom filter: filter out all events from the "salsa" crate unless CAIRO_UNMUTE_SALSA is
30        // set.
31        let salsa_filter = exclude_salsa();
32
33        let filter = env_filter.and_then(salsa_filter);
34
35        let timer = tracing_subscriber::fmt::time::SystemTime;
36        let fmt_layer = tracing_subscriber::fmt::layer()
37            .with_timer(timer)
38            .with_ansi(false)
39            .with_level(true)
40            .with_target(false)
41            .with_file(true)
42            .with_line_number(true);
43
44        // Avoid panicking if a global subscriber is already set (e.g., tests or another init).
45        let registry = tracing_subscriber::registry().with(filter);
46        if cfg!(test) {
47            let _ = registry.with(fmt_layer.with_test_writer()).try_init();
48        } else {
49            let _ = registry.with(fmt_layer).try_init();
50        }
51    });
52}
53
54/// Returns a filter that mutes all tracing events from the "salsa" crate unless the
55/// `CAIRO_UNMUTE_SALSA` environment variable is set.
56/// This is useful to reduce log noise from salsa internals during normal operation.
57pub fn exclude_salsa() -> tracing_subscriber::filter::DynFilterFn<
58    tracing_subscriber::Registry,
59    impl Fn(
60        &tracing::Metadata<'_>,
61        &tracing_subscriber::layer::Context<'_, tracing_subscriber::Registry>,
62    ) -> bool,
63> {
64    let salsa_unmuted = std::env::var("CAIRO_UNMUTE_SALSA").is_ok();
65    dynamic_filter_fn(move |meta, _ctx| {
66        if salsa_unmuted {
67            // If the env var is set, do not filter out salsa events.
68            true
69        } else {
70            // Filter out events whose target starts with "salsa"
71            !meta.target().starts_with("salsa")
72        }
73    })
74}