queen_log/
lib.rs

1use std::io::{Write, Stdout, stdout};
2
3use log::{self, Log, Metadata, Record, SetLoggerError, Level, LevelFilter};
4use filter::Filter;
5
6use chrono::{Local, DateTime};
7
8use termcolor::{Buffer, Color, ColorSpec, WriteColor};
9use once_cell::sync::Lazy;
10
11pub mod filter;
12
13pub struct Logger<Writer> {
14    filter: Filter,
15    writer: Writer,
16}
17
18static IS_STDOUT: Lazy<bool> = Lazy::new(|| atty::is(atty::Stream::Stdout));
19pub trait Writer {
20    fn writer(&self, record: &Record);
21}
22
23impl Writer for Stdout {
24    fn writer(&self, record: &Record) {
25        let time_now: DateTime<Local> = Local::now();
26
27        let s = format!("[{}] {} | {} | {} | {}:{}",
28                    time_now.format("%Y/%m/%d %H:%M:%S %z").to_string(),
29                    record.level(),
30                    record.target(),
31                    record.args(),
32                    record.file().unwrap_or("unknow"),
33                    record.line().unwrap_or_default()
34                );
35
36        if *IS_STDOUT {
37            let mut buffer = Buffer::ansi();
38            let mut color_spec = ColorSpec::new();
39
40            match record.level() {
41                Level::Trace => {
42                    color_spec.set_fg(Some(Color::Magenta));
43                },
44                Level::Debug => {
45                    color_spec.set_fg(Some(Color::Blue));
46                },
47                Level::Info => {
48                    color_spec.set_fg(Some(Color::Green));
49                },
50                Level::Warn => {
51                    color_spec.set_fg(Some(Color::Yellow));
52                },
53                Level::Error => {
54                    color_spec.set_fg(Some(Color::Red));
55                }
56            }
57
58            color_spec.set_bold(true);
59            let _ = buffer.set_color(&color_spec);
60            let _ = buffer.write_all(s.as_bytes());
61
62            let mut handle = self.lock();
63            let _ = handle.write_all(buffer.as_slice());
64            let _ = handle.write_all(b"\n");
65            let _ = handle.flush();
66        } else {
67            let mut handle = self.lock();
68            let _ = handle.write_all(s.as_bytes());
69            let _ = handle.write_all(b"\n");
70            let _ = handle.flush();
71        }
72    }
73}
74
75impl<W: Writer> Logger<W> {
76    pub fn new(filter: Filter, writer: W) -> Self {
77        Self {
78            filter,
79            writer
80        }
81    }
82}
83
84impl Default for Logger<Stdout> {
85    fn default() -> Self {
86        let mut builder = filter::Builder::new();
87
88        if let Ok(ref filter) = std::env::var("LOG_LEVEL") {
89            builder.parse(filter);
90        }
91
92        Logger::new( builder.build(), stdout())
93    }
94}
95
96impl<P: Writer + Sync + Send> Log for Logger<P> {
97    fn enabled(&self, metadata: &Metadata) -> bool {
98        self.filter.enabled(metadata)
99    }
100
101    fn log(&self, record: &Record) {
102        if self.filter.matches(record) {
103            self.writer.writer(record);
104        }
105    }
106
107    fn flush(&self) {}
108}
109
110pub fn init(level: LevelFilter) -> Result<(), SetLoggerError> {
111    log::set_boxed_logger(Box::new(Logger::default()))
112        .map(|()| log::set_max_level(level))
113}
114
115pub fn init_with_logger<P: Writer + Sync + Send + 'static>(
116    level: LevelFilter,
117    logger: Logger<P>
118) -> Result<(), SetLoggerError> {
119    log::set_boxed_logger(Box::new(logger))
120        .map(|()| log::set_max_level(level))
121}