Skip to main content

charon_lib/
logger.rs

1extern crate env_logger;
2
3/// Initialize the logger.
4pub fn initialize_logger() {
5    {
6        // Initialize the logger only once (useful when running the driver in tests).
7        use std::sync::atomic::{AtomicBool, Ordering};
8        static LOGGER_INITIALIZED: AtomicBool = AtomicBool::new(false);
9        if LOGGER_INITIALIZED.swap(true, Ordering::SeqCst) {
10            return;
11        }
12    }
13
14    use std::io::IsTerminal;
15    use tracing_subscriber::prelude::*;
16    tracing_subscriber::registry()
17        .with(tracing_subscriber::EnvFilter::from_default_env())
18        .with(
19            tracing_tree::HierarchicalLayer::new(1)
20                .with_ansi(std::io::stderr().is_terminal())
21                .with_indent_lines(true)
22                .with_bracketed_fields(true)
23                .with_timer(tracing_tree::time::Uptime::default()),
24        )
25        .init();
26}
27
28#[macro_export]
29macro_rules! ansi_color {
30    (red) => {
31        "\x1b[31m"
32    };
33    (yellow) => {
34        "\x1b[33m"
35    };
36}
37
38/// This macro computes the name of the function in which it is called and the line number.
39/// We adapted it from:
40/// <https://stackoverflow.com/questions/38088067/equivalent-of-func-or-function-in-rust>
41#[macro_export]
42macro_rules! code_location {
43    ($color:ident) => {{
44        fn f() {}
45        fn type_name_of<T>(_: T) -> &'static str {
46            std::any::type_name::<T>()
47        }
48        let name = type_name_of(f);
49
50        let path: Vec<_> = name.split("::").collect();
51        // The path looks like `crate::module::function::f`.
52        let mut name = path.iter().rev().skip(1).next().unwrap().to_string();
53
54        let line = line!();
55        let file = file!();
56        let mut location = format!("{file}:{line}");
57
58        use std::io::IsTerminal;
59        if std::io::stderr().is_terminal() {
60            name = format!("{}{name}\x1b[39m", $crate::ansi_color!($color));
61            location = format!("\x1b[2m{location}\x1b[22m");
62        }
63        format!("in {name} at {location}")
64    }};
65}
66
67/// A custom log trace macro. Uses the log crate.
68#[macro_export]
69macro_rules! trace {
70    ($($arg:tt)+) => {{
71        tracing::trace!("{}:\n{}", $crate::code_location!(yellow), format!($($arg)+))
72    }};
73    () => {{
74        tracing::trace!("{}", $crate::code_location!(yellow))
75    }};
76}
77
78/// A custom log error macro. Uses the log crate.
79#[macro_export]
80macro_rules! error {
81    ($($arg:tt)+) => {{
82        tracing::error!("{}:\n{}", $crate::code_location!(red), format!($($arg)+))
83    }};
84}
85
86/// A custom log warn macro. Uses the log crate.
87#[macro_export]
88macro_rules! warn {
89    ($($arg:tt)+) => {{
90        tracing::warn!("{}:\n{}", $crate::code_location!(yellow), format!($($arg)+))
91    }};
92}
93
94/// A custom log info macro. Uses the log crate.
95#[macro_export]
96macro_rules! info {
97    ($($arg:tt)+) => {{
98        // As for info we generally output simple messages, we don't insert a newline.
99        tracing::info!("{}: {}", $crate::code_location!(yellow), format!($($arg)+))
100    }};
101    () => {{
102        tracing::info!("{}", $crate::code_location!(yellow))
103    }};
104}