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/// This macro computes the name of the function in which it is called and the line number.
29/// We adapted it from:
30/// <https://stackoverflow.com/questions/38088067/equivalent-of-func-or-function-in-rust>
31#[macro_export]
32macro_rules! code_location {
33    ($color:ident) => {{
34        fn f() {}
35        fn type_name_of<T>(_: T) -> &'static str {
36            std::any::type_name::<T>()
37        }
38        let name = type_name_of(f);
39
40        let path: Vec<_> = name.split("::").collect();
41        // The path looks like `crate::module::function::f`.
42        let mut name = path.iter().rev().skip(1).next().unwrap().to_string();
43
44        let line = line!();
45        let file = file!();
46        let mut location = format!("{file}:{line}");
47
48        use std::io::IsTerminal;
49        if std::io::stderr().is_terminal() {
50            use colored::Colorize;
51            name = name.$color().to_string();
52            location = location.dimmed().to_string();
53        }
54        format!("in {name} at {location}")
55    }};
56}
57
58/// A custom log trace macro. Uses the log crate.
59#[macro_export]
60macro_rules! trace {
61    ($($arg:tt)+) => {{
62        tracing::trace!("{}:\n{}", $crate::code_location!(yellow), format!($($arg)+))
63    }};
64    () => {{
65        tracing::trace!("{}", $crate::code_location!(yellow))
66    }};
67}
68
69/// A custom log error macro. Uses the log crate.
70#[macro_export]
71macro_rules! error {
72    ($($arg:tt)+) => {{
73        tracing::error!("{}:\n{}", $crate::code_location!(red), format!($($arg)+))
74    }};
75}
76
77/// A custom log warn macro. Uses the log crate.
78#[macro_export]
79macro_rules! warn {
80    ($($arg:tt)+) => {{
81        tracing::warn!("{}:\n{}", $crate::code_location!(yellow), format!($($arg)+))
82    }};
83}
84
85/// A custom log info macro. Uses the log crate.
86#[macro_export]
87macro_rules! info {
88    ($($arg:tt)+) => {{
89        // As for info we generally output simple messages, we don't insert a newline.
90        tracing::info!("{}: {}", $crate::code_location!(yellow), format!($($arg)+))
91    }};
92    () => {{
93        tracing::info!("{}", $crate::code_location!(yellow))
94    }};
95}