gloss_utils/
logging.rs

1// mostly copied from here:
2// https://github.com/seanmonstar/pretty-env-logger/blob/master/src/lib.rs
3// and from: https://github.com/LuckyTurtleDev/my-env-logger-style/blob/main/src/lib.rs
4
5use env_logger::fmt::Formatter;
6use log::{Level, Record};
7// #[cfg(feature = "custom-arg-formatter")]
8// use once_cell::sync::OnceCell;
9#[cfg(feature = "log_with_time")]
10use std::sync::atomic::AtomicU8;
11use std::{
12    io,
13    io::Write,
14    sync::atomic::{AtomicBool, AtomicUsize, Ordering},
15};
16
17static MAX_MODULE_LEN: AtomicUsize = AtomicUsize::new(0);
18static SHOW_MODULE: AtomicBool = AtomicBool::new(true);
19static SHOW_EMOJIS: AtomicBool = AtomicBool::new(true);
20#[cfg(feature = "log_with_time")]
21static SHOW_TIME: AtomicU8 = AtomicU8::new(env_logger::TimestampPrecision::Seconds as u8);
22// #[cfg(feature = "custom-arg-formatter")]
23// static ARG_FORMATTER: OnceCell<Box<dyn ArgFormatter + Send + Sync>> =
24// OnceCell::new();
25
26pub use env_logger;
27
28/// return the current module len and set the module length to the maximum of
29/// the current value and the given `len`.
30///
31/// Usefull if you already know the length of module and would like to have an
32/// consistant indentation from the beginnig.
33pub fn get_set_max_module_len(len: usize) -> usize {
34    let module_len = MAX_MODULE_LEN.load(Ordering::Relaxed);
35    if module_len < len {
36        MAX_MODULE_LEN.store(len, Ordering::Relaxed);
37    }
38    module_len
39}
40
41///log formater witch can be used at the
42/// [`format()`](env_logger::Builder::format()) function of the
43/// [`env_logger::Builder`].
44#[allow(clippy::missing_errors_doc)]
45pub fn format(buf: &mut Formatter, record: &Record<'_>) -> io::Result<()> {
46    let mut bold = buf.style();
47    bold.set_bold(true);
48    let mut dimmed = buf.style();
49    dimmed.set_dimmed(true);
50
51    #[cfg(feature = "log_with_time")]
52    {
53        let show_time = SHOW_TIME.load(Ordering::Relaxed);
54        // safety: SHOW_TIME is inilized with TimestampPrecision::Seconds
55        // and can only be written by using set_timestamp_precision()
56        match unsafe { std::mem::transmute::<u8, env_logger::TimestampPrecision>(show_time) } {
57            env_logger::TimestampPrecision::Seconds => {
58                write!(buf, "{} ", dimmed.value(buf.timestamp_seconds()))
59            }
60            env_logger::TimestampPrecision::Millis => {
61                write!(buf, "{} ", dimmed.value(buf.timestamp_millis()))
62            }
63            env_logger::TimestampPrecision::Micros => {
64                write!(buf, "{} ", dimmed.value(buf.timestamp_micros()))
65            }
66            env_logger::TimestampPrecision::Nanos => {
67                write!(buf, "{} ", dimmed.value(buf.timestamp_nanos()))
68            }
69        }?;
70    }
71
72    let level_style = buf.default_level_style(record.level());
73    let level_symbol = if SHOW_EMOJIS.load(Ordering::Relaxed) {
74        match record.level() {
75            //💥 and 🔬 are 2 chars big at the terminal. How does it look with other fonts/terminals?
76            Level::Trace => "🔬",
77            Level::Debug => " ⚙️",
78            Level::Info => " ℹ",
79            Level::Warn => " ⚠",
80            Level::Error => "💥",
81        }
82    } else {
83        ""
84    };
85    write!(buf, "{level_symbol} {:5} ", level_style.value(record.level()))?;
86
87    if SHOW_MODULE.load(Ordering::Relaxed) {
88        let module = record.module_path().unwrap_or_default();
89        let module_with_line_nr = module.to_owned() + "::" + &record.line().unwrap_or(0).to_string();
90        let module_len = get_set_max_module_len(module_with_line_nr.len() + 2); //+1 because we add a "::" between module path and line_nr
91        write!(buf, "{:module_len$} {} ", dimmed.value(module_with_line_nr), bold.value('>'))?;
92    }
93
94    // #[cfg(feature = "custom-arg-formatter")]
95    // if let Some(formatter) = ARG_FORMATTER.get() {
96    // return formatter.arg_format(buf, record);
97    // }
98    writeln!(buf, "{}", record.args())
99}