use comat::{cformat_args, cwriteln}; use log::{Level, Metadata, Record}; use std::{ fs::File, io::Write, path::PathBuf, sync::{Mutex, OnceLock, PoisonError}, time::Instant, }; #[derive(Debug)] pub struct Logger { start: Instant, file: Mutex, } impl Logger { pub fn init(level: Level, f: PathBuf) { static LOGGER: OnceLock = OnceLock::new(); LOGGER .set(Self { start: Instant::now(), file: Mutex::new(File::create(f).unwrap()), }) .unwrap(); log::set_logger(LOGGER.get().unwrap()) .map(|()| log::set_max_level(level.to_level_filter())) .unwrap(); } } impl log::Log for Logger { fn enabled(&self, _: &Metadata) -> bool { true } fn log(&self, record: &Record) { cwriteln!( self.file.lock().unwrap_or_else(PoisonError::into_inner), "[{} {:bold_blue}:{:blue}{green}@{:yellow}] {}", match record.level() { Level::Error => cformat_args!("{bold_red}err{reset}"), Level::Warn => cformat_args!("{bold_yellow}wrn{reset}"), Level::Trace => cformat_args!("{magenta}trc{reset}"), Level::Debug => cformat_args!("{green}dbg{reset}"), Level::Info => cformat_args!("{blue}inf{reset}"), }, record.file().unwrap_or(""), record.line().unwrap_or(0), humantime::format_duration(self.start.elapsed()), record.args(), ) .unwrap(); } fn flush(&self) {} }