ptero/log.rs
1use colored::Colorize;
2use fern::{
3    colors::{Color, ColoredLevelConfig},
4    Dispatch,
5};
6use log::{Level, LevelFilter};
7/// Converts verbosity number to [LevelFilter](log::LevelFilter) enum.
8/// Used for configuring the logging level.
9/// # Arguments
10///
11/// * `verbosity` - verbosity level described by number `u8`
12///
13/// # Examples
14/// ## Converts verbosity number
15/// ```
16/// use ptero::log::verbosity_to_level_filter;
17/// use log::{LevelFilter};
18///
19/// assert_eq!(verbosity_to_level_filter(0), LevelFilter::Off);
20/// assert_eq!(verbosity_to_level_filter(1), LevelFilter::Warn);
21/// assert_eq!(verbosity_to_level_filter(2), LevelFilter::Info);
22/// assert_eq!(verbosity_to_level_filter(3), LevelFilter::Debug);
23/// ```
24/// ## Unrecognized verbosity defaults to trace
25/// ```
26/// use ptero::log::verbosity_to_level_filter;
27/// use log::{LevelFilter};
28///
29/// assert_eq!(verbosity_to_level_filter(4), LevelFilter::Trace);
30/// assert_eq!(verbosity_to_level_filter(100), LevelFilter::Trace);
31/// assert_eq!(verbosity_to_level_filter(255), LevelFilter::Trace);
32/// ```
33pub fn verbosity_to_level_filter(verbosity: u8) -> LevelFilter {
34    match verbosity {
35        0 => LevelFilter::Off,
36        1 => LevelFilter::Warn,
37        2 => LevelFilter::Info,
38        3 => LevelFilter::Debug,
39        _ => LevelFilter::Trace,
40    }
41}
42
43/// Returns pre-configured [ColoredLevelConfig](fern::colors::ColoredLevelConfig) used to color
44/// logging level.
45fn get_logging_colors() -> ColoredLevelConfig {
46    ColoredLevelConfig::new()
47        .error(Color::Red)
48        .warn(Color::BrightYellow)
49        .debug(Color::Magenta)
50        .trace(Color::BrightBlack)
51}
52
53/// Returns text which will be shown before the message. Used only in stdout formatter.
54fn get_level_text(level: &Level) -> &str {
55    match level {
56        Level::Error => "ERROR",
57        Level::Warn => " WARN",
58        Level::Info => " INFO",
59        Level::Debug => "DEBUG",
60        Level::Trace => "TRACE",
61    }
62}
63
64/// Returns pre-configured stdout logger.
65/// It only shows info relevant to user like message and logging level.
66/// Uses coloring unlike file logger.
67///
68/// # Arguments
69/// * `log_level` - level filter which is used to restrict amount of logs to user
70pub fn get_stdout_logger() -> Dispatch {
71    let colors = get_logging_colors();
72
73    fern::Dispatch::new()
74        .format(move |out, message, record| {
75            out.finish(format_args!(
76                "{color_line}{level_txt}\x1B[0m  [{module}]: {message}",
77                level_txt = get_level_text(&record.level()),
78                color_line =
79                    format_args!("\x1B[{}m", colors.get_color(&record.level()).to_fg_str()),
80                message = message,
81                module = &record.target().dimmed(),
82            ));
83        })
84        .chain(std::io::stderr())
85}
86
87/// Returns pre-configured file logger.
88/// This logger does not used coloring and adds additional info like date time or module path.
89/// It doesn't restrict logging - saves everything beginning from `TRACE` level.
90///
91/// # Arguments
92/// * `log_path` - path to the log file which will be used to store logs
93pub fn get_file_logger(log_path: &str) -> Dispatch {
94    fern::Dispatch::new()
95        .format(move |out, message, record| {
96            out.finish(format_args!(
97                "{}[{}][{}] - {}",
98                chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
99                &record.target(),
100                &record.level(),
101                message,
102            ));
103        })
104        .chain(fern::log_file(&log_path).unwrap())
105}