micromegas_telemetry_sink/
log_interop.rs

1use micromegas_tracing::{
2    dispatch::{flush_log_buffer, log_enabled, log_interop},
3    error,
4    levels::{Level, LevelFilter},
5    logs::{FILTER_LEVEL_UNSET_VALUE, LogMetadata},
6};
7use std::sync::atomic::AtomicU32;
8
9struct LogDispatch;
10
11impl log::Log for LogDispatch {
12    fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
13        let level = log_level_to_mm_tracing_level(metadata.level());
14        let log_metadata = LogMetadata {
15            level,
16            level_filter: AtomicU32::new(0),
17            fmt_str: "",
18            target: "unknown",
19            module_path: "unknown",
20            file: "unknown",
21            line: 0,
22        };
23        log_enabled(&log_metadata)
24    }
25
26    fn log(&self, record: &log::Record<'_>) {
27        let level = log_level_to_mm_tracing_level(record.level());
28        let log_desc = LogMetadata {
29            level,
30            level_filter: AtomicU32::new(FILTER_LEVEL_UNSET_VALUE),
31            fmt_str: record.args().as_str().unwrap_or(""),
32            target: record.target(),
33            module_path: record.module_path_static().unwrap_or("unknown"),
34            file: record.file_static().unwrap_or("unknown"),
35            line: record.line().unwrap_or(0),
36        };
37        log_interop(&log_desc, *record.args());
38    }
39    fn flush(&self) {
40        flush_log_buffer();
41    }
42}
43
44pub fn install_log_interop(interop_max_level_override: Option<LevelFilter>) {
45    /// Installs a `log` crate dispatcher that forwards log records to the Micromegas tracing system.
46    ///
47    /// This allows applications using the `log` crate to integrate with Micromegas telemetry.
48    ///
49    /// # Arguments
50    ///
51    /// * `interop_max_level_override` - An optional `LevelFilter` to override the maximum log level
52    ///   for the `log` crate dispatcher. If `None`, the global Micromegas max level is used.
53    static LOG_DISPATCHER: LogDispatch = LogDispatch;
54    let interop_max_level = mm_tracing_level_filter_to_log_level_filter(
55        interop_max_level_override.unwrap_or(micromegas_tracing::levels::max_level()),
56    );
57    log::set_max_level(interop_max_level);
58
59    if let Err(e) = log::set_logger(&LOG_DISPATCHER) {
60        error!("Could not set log crate dispatcher {e:?}");
61        log::set_max_level(log::LevelFilter::Off);
62    }
63}
64
65fn log_level_to_mm_tracing_level(level: log::Level) -> Level {
66    match level {
67        log::Level::Error => Level::Error,
68        log::Level::Warn => Level::Warn,
69        log::Level::Info => Level::Info,
70        log::Level::Debug => Level::Debug,
71        log::Level::Trace => Level::Trace,
72    }
73}
74
75pub(crate) fn mm_tracing_level_filter_to_log_level_filter(level: LevelFilter) -> log::LevelFilter {
76    match level {
77        LevelFilter::Off => log::LevelFilter::Off,
78        LevelFilter::Fatal => log::LevelFilter::Off, //there is no fatal level in the log crate
79        LevelFilter::Error => log::LevelFilter::Error,
80        LevelFilter::Warn => log::LevelFilter::Warn,
81        LevelFilter::Info => log::LevelFilter::Info,
82        LevelFilter::Debug => log::LevelFilter::Debug,
83        LevelFilter::Trace => log::LevelFilter::Trace,
84    }
85}