Skip to main content

fb2_clean/cli/
logger.rs

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