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