use crate::error::Error; pub use log::{debug, info, set_logger, set_max_level, warn, LevelFilter}; use std::{ fs::File, io, path::Path, sync::{Arc, Mutex}, }; use log::{Metadata, Record}; pub struct Log { out: Arc>, } impl Log { pub fn file>(p: P) -> Result { let f = File::options().append(true).create(true).open(p)?; Ok(Self { out: Arc::new(Mutex::new(f)), }) } } impl Log where W: io::Write, { #[allow(dead_code)] pub fn from_writer(w: W) -> Self { Self { out: Arc::new(Mutex::new(w)), } } } impl log::Log for Log where W: io::Write + Send, { fn enabled(&self, _metadata: &Metadata) -> bool { true } fn log(&self, record: &Record) { if self.enabled(record.metadata()) { if let Ok(out) = self.out.lock().as_deref_mut() { match record.level() { log::Level::Error => { _ = write!(out, "\x1b[31m{}\x1b[0m\n", record.args()); } log::Level::Warn => { _ = write!(out, "\x1b[33m{}\x1b[0m\n", record.args()); } log::Level::Info => { _ = write!(out, "\x1b[37m{}\x1b[0m\n", record.args()); } log::Level::Debug => { _ = write!(out, "\x1b[90m{}\x1b[0m\n", record.args()); } log::Level::Trace => { _ = write!(out, "\x1b[36m{}\x1b[0m\n", record.args()); } } } } } fn flush(&self) { if let Ok(out) = self.out.lock().as_deref_mut() { _ = out.flush(); } } }