1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
use std::io::{Write, Stdout, stdout}; use log::{self, Log, Metadata, Record, SetLoggerError, Level, LevelFilter}; use env_logger::filter::Filter; use chrono::{Local, DateTime, SecondsFormat}; use color::{Print, Color}; pub mod color; pub struct QueenLogger<P> { filter: Filter, log_print: P, show_color: bool } pub trait LogPrint { fn println(&self, s: &impl std::fmt::Display); } impl LogPrint for Stdout { fn println(&self, s: &impl std::fmt::Display) { let mut handle = self.lock(); let _ = writeln!(handle, "{}", s); let _ = handle.flush(); } } impl<P: LogPrint> QueenLogger<P> { fn new(log_print: P, show_color: bool) -> Self { use env_logger::filter::Builder; let mut builder = Builder::new(); if let Ok(ref filter) = std::env::var("QUEEN_LOG_LEVEL") { builder.parse(filter); } Self { filter: builder.build(), log_print, show_color } } } impl Default for QueenLogger<Stdout> { fn default() -> Self { QueenLogger::new(stdout(), true) } } impl<W: LogPrint + Sync + Send> Log for QueenLogger<W> { fn enabled(&self, metadata: &Metadata) -> bool { self.filter.enabled(metadata) } fn log(&self, record: &Record) { if self.filter.matches(record) { let (color, level) = match record.level() { Level::Trace => { (Color::Purple, "TRACE") } Level::Debug => { (Color::Blue, "DEBUG") } Level::Info => { (Color::Green, "INFO") } Level::Warn => { (Color::Yellow, "WARN") } Level::Error => { (Color::Red, "ERROR") } }; let time_now: DateTime<Local> = Local::now(); let s = format!("[{} {} {}] {} | {}", time_now.to_rfc3339_opts(SecondsFormat::Millis, true), level, record.target(), record.args(), record.file().unwrap_or("unknow") ); if self.show_color { self.log_print.println(&Print::new(s).foreground(color)); } else { self.log_print.println(&s); } } } fn flush(&self) {} } pub fn init(level: LevelFilter) -> Result<(), SetLoggerError> { log::set_boxed_logger(Box::new(QueenLogger::default())) .map(|()| log::set_max_level(level)) }