Skip to main content

fb2_clean/cli/
logger.rs

1use log::{Level, LevelFilter, Log, Metadata, Record};
2use std::{
3    io::{self, Write},
4    sync::LazyLock,
5};
6use supports_color::{Stream, on};
7
8static CLI_LOGGER: CliLogger = CliLogger;
9pub struct CliLogger;
10
11static STDERR_ON_COLOR: LazyLock<bool> = LazyLock::new(|| on(Stream::Stderr).is_some());
12static STDOUT_ON_COLOR: LazyLock<bool> = LazyLock::new(|| on(Stream::Stdout).is_some());
13
14impl CliLogger {
15    pub fn init() {
16        log::set_logger(&CLI_LOGGER).unwrap();
17        log::set_max_level(LevelFilter::Info);
18    }
19
20    fn prf_prefix(level: Level) -> &'static str {
21        match level {
22            Level::Error if *STDERR_ON_COLOR => "\x1b[31m",
23            Level::Error => "",
24            Level::Warn if *STDERR_ON_COLOR => "\x1b[33m",
25            Level::Warn => "",
26            Level::Debug if *STDOUT_ON_COLOR => "\x1b[34m",
27            Level::Debug => "",
28            Level::Trace if *STDOUT_ON_COLOR => "\x1b[35m",
29            Level::Trace => "",
30            _ => "",
31        }
32    }
33
34    fn prf_suffix(level: Level) -> &'static str {
35        match level {
36            Level::Error | Level::Warn if *STDERR_ON_COLOR => "\x1b[0m: ",
37            Level::Error | Level::Warn => ": ",
38            Level::Debug | Level::Trace if *STDOUT_ON_COLOR => "\x1b[0m: ",
39            Level::Debug | Level::Trace => ": ",
40            _ => "",
41        }
42    }
43}
44
45impl Log for CliLogger {
46    fn enabled(&self, metadata: &Metadata) -> bool {
47        metadata.level() <= Level::Trace
48    }
49
50    fn log(&self, record: &Record) {
51        if !self.enabled(record.metadata()) {
52            return;
53        }
54
55        let level = record.level();
56
57        let msg = format!(
58            "{}{}{}{}\n",
59            Self::prf_prefix(level),
60            crate::log_prefix_root(level),
61            Self::prf_suffix(level),
62            record.args()
63        );
64        let msg = msg.as_bytes();
65
66        match level {
67            Level::Error | Level::Warn => {
68                let _ = io::stderr()
69                    .write_all(msg)
70                    .or_else(|_| io::stdout().write_all(msg));
71            }
72            _ => {
73                let _ = io::stdout().write_all(msg);
74            }
75        }
76    }
77
78    fn flush(&self) {}
79}