//! Logger for examples, based on Borntyping's Simple Logger use chrono::Local; use colored::*; use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError}; pub struct SimpleLogger { default_level: LevelFilter, module_levels: Vec<(String, LevelFilter)>, } impl SimpleLogger { pub fn new() -> SimpleLogger { SimpleLogger { default_level: LevelFilter::Trace, module_levels: Vec::new(), } } #[allow(dead_code)] pub fn with_level(mut self, level: LevelFilter) -> SimpleLogger { self.default_level = level; self } #[allow(dead_code)] pub fn with_module_level(mut self, target: &str, level: LevelFilter) -> SimpleLogger { self.module_levels.push((target.to_string(), level)); /* Normally this is only called in `init` to avoid redundancy, but we can't initialize the logger in tests */ #[cfg(test)] self.module_levels .sort_by_key(|(name, _level)| name.len().wrapping_neg()); self } pub fn init(mut self) -> Result<(), SetLoggerError> { self.module_levels .sort_by_key(|(name, _level)| name.len().wrapping_neg()); let max_level = self .module_levels .iter() .map(|(_name, level)| level) .copied() .max(); let max_level = max_level .map(|lvl| lvl.max(self.default_level)) .unwrap_or(self.default_level); log::set_max_level(max_level); log::set_boxed_logger(Box::new(self))?; Ok(()) } } impl Default for SimpleLogger { fn default() -> Self { SimpleLogger::new() } } impl Log for SimpleLogger { fn enabled(&self, metadata: &Metadata) -> bool { &metadata.level().to_level_filter() <= self .module_levels .iter() .find(|(name, _level)| metadata.target().starts_with(name)) .map(|(_name, level)| level) .unwrap_or(&self.default_level) } fn log(&self, record: &Record) { if self.enabled(record.metadata()) { let level_string = { match record.level() { Level::Error => record.level().to_string().red(), Level::Warn => record.level().to_string().yellow(), Level::Info => record.level().to_string().cyan(), Level::Debug => record.level().to_string().purple(), Level::Trace => record.level().to_string().normal(), } }; /* let target = if !record.target().is_empty() { record.target() } else { record.module_path().unwrap_or_default() }; println!( "{} {:<5} [{}] {}", Local::now().format("%Y-%m-%d %H:%M:%S,%3f"), level_string, target, record.args() ); */ println!( "{} [{:<5}]: {}", Local::now().format("%Y-%m-%d %H:%M:%S,%3f"), level_string, record.args() ); } } fn flush(&self) {} }