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