use log::{debug, error, info, trace, warn, Level, LevelFilter, Log, Metadata, Record}; use std::sync::{Arc, Mutex}; #[cfg(feature = "std")] use log::set_boxed_logger; #[cfg(not(feature = "std"))] fn set_boxed_logger(logger: Box) -> Result<(), log::SetLoggerError> { log::set_logger(Box::leak(logger)) } struct State { last_log: Mutex>, } struct Logger(Arc); impl Log for Logger { fn enabled(&self, _: &Metadata) -> bool { true } fn log(&self, record: &Record) { *self.0.last_log.lock().unwrap() = Some(record.level()); } fn flush(&self) {} } fn main() { let me = Arc::new(State { last_log: Mutex::new(None), }); let a = me.clone(); set_boxed_logger(Box::new(Logger(me))).unwrap(); test(&a, LevelFilter::Off); test(&a, LevelFilter::Error); test(&a, LevelFilter::Warn); test(&a, LevelFilter::Info); test(&a, LevelFilter::Debug); test(&a, LevelFilter::Trace); } fn test(a: &State, filter: LevelFilter) { log::set_max_level(filter); error!(""); last(&a, t(Level::Error, filter)); warn!(""); last(&a, t(Level::Warn, filter)); info!(""); last(&a, t(Level::Info, filter)); debug!(""); if cfg!(debug_assertions) { last(&a, t(Level::Debug, filter)); } else { last(&a, None); } trace!(""); last(&a, None); fn t(lvl: Level, filter: LevelFilter) -> Option { if lvl <= filter { Some(lvl) } else { None } } } fn last(state: &State, expected: Option) { let mut lvl = state.last_log.lock().unwrap(); assert_eq!(*lvl, expected); *lvl = None; }