#![deny(missing_docs, rust_2018_idioms)]
mod config;
mod loggers;
pub use self::config::{
format_description, Config, ConfigBuilder, FormatItem, LevelPadding, TargetPadding,
ThreadLogMode, ThreadPadding,
};
#[cfg(feature = "test")]
pub use self::loggers::TestLogger;
pub use self::loggers::{CombinedLogger, SimpleLogger, WriteLogger};
#[cfg(feature = "termcolor")]
pub use self::loggers::{TermLogger, TerminalMode};
#[cfg(feature = "termcolor")]
pub use termcolor::{Color, ColorChoice};
pub use log::{Level, LevelFilter};
use log::Log;
#[cfg(all(test, not(feature = "paris")))]
use log::*;
#[cfg(feature = "paris")]
pub(crate) mod paris_macros;
#[cfg(feature = "paris")]
#[doc(hidden)]
pub mod __private {
pub use log;
pub use paris;
}
pub trait SharedLogger: Log {
fn level(&self) -> LevelFilter;
fn config(&self) -> Option<&Config>;
fn as_log(self: Box<Self>) -> Box<dyn Log>;
}
#[cfg(test)]
mod tests {
use std::fs::File;
use std::io::Read;
use super::*;
#[test]
fn test() {
let mut i = 0;
CombinedLogger::init({
let mut vec = Vec::new();
let mut conf_builder = ConfigBuilder::new();
let conf_thread_name = ConfigBuilder::new()
.set_time_level(LevelFilter::Off)
.set_thread_level(LevelFilter::Error)
.set_thread_mode(ThreadLogMode::Names)
.build();
vec.push(WriteLogger::new(
LevelFilter::Error,
conf_thread_name,
File::create("thread_naming.log").unwrap(),
) as Box<dyn SharedLogger>);
for elem in vec![
LevelFilter::Off,
LevelFilter::Trace,
LevelFilter::Debug,
LevelFilter::Info,
LevelFilter::Warn,
LevelFilter::Error,
] {
let conf = conf_builder
.set_location_level(elem)
.set_target_level(elem)
.set_max_level(elem)
.set_time_level(elem)
.build();
i += 1;
vec.push(
SimpleLogger::new(LevelFilter::Error, conf.clone()) as Box<dyn SharedLogger>
);
#[cfg(feature = "termcolor")]
vec.push(TermLogger::new(
LevelFilter::Error,
conf.clone(),
TerminalMode::Mixed,
ColorChoice::Auto,
) as Box<dyn SharedLogger>);
vec.push(WriteLogger::new(
LevelFilter::Error,
conf.clone(),
File::create(&format!("error_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);
#[cfg(feature = "test")]
vec.push(TestLogger::new(LevelFilter::Error, conf.clone()));
vec.push(
SimpleLogger::new(LevelFilter::Warn, conf.clone()) as Box<dyn SharedLogger>
);
#[cfg(feature = "termcolor")]
vec.push(TermLogger::new(
LevelFilter::Warn,
conf.clone(),
TerminalMode::Mixed,
ColorChoice::Auto,
) as Box<dyn SharedLogger>);
vec.push(WriteLogger::new(
LevelFilter::Warn,
conf.clone(),
File::create(&format!("warn_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);
#[cfg(feature = "test")]
vec.push(TestLogger::new(LevelFilter::Warn, conf.clone()));
vec.push(
SimpleLogger::new(LevelFilter::Info, conf.clone()) as Box<dyn SharedLogger>
);
#[cfg(feature = "termcolor")]
vec.push(TermLogger::new(
LevelFilter::Info,
conf.clone(),
TerminalMode::Mixed,
ColorChoice::Auto,
) as Box<dyn SharedLogger>);
vec.push(WriteLogger::new(
LevelFilter::Info,
conf.clone(),
File::create(&format!("info_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);
#[cfg(feature = "test")]
vec.push(TestLogger::new(LevelFilter::Info, conf.clone()));
vec.push(
SimpleLogger::new(LevelFilter::Debug, conf.clone()) as Box<dyn SharedLogger>
);
#[cfg(feature = "termcolor")]
vec.push(TermLogger::new(
LevelFilter::Debug,
conf.clone(),
TerminalMode::Mixed,
ColorChoice::Auto,
) as Box<dyn SharedLogger>);
vec.push(WriteLogger::new(
LevelFilter::Debug,
conf.clone(),
File::create(&format!("debug_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);
#[cfg(feature = "test")]
vec.push(TestLogger::new(LevelFilter::Debug, conf.clone()));
vec.push(
SimpleLogger::new(LevelFilter::Trace, conf.clone()) as Box<dyn SharedLogger>
);
#[cfg(feature = "termcolor")]
vec.push(TermLogger::new(
LevelFilter::Trace,
conf.clone(),
TerminalMode::Mixed,
ColorChoice::Auto,
) as Box<dyn SharedLogger>);
vec.push(WriteLogger::new(
LevelFilter::Trace,
conf.clone(),
File::create(&format!("trace_{}.log", i)).unwrap(),
) as Box<dyn SharedLogger>);
#[cfg(feature = "test")]
vec.push(TestLogger::new(LevelFilter::Trace, conf.clone()));
}
vec
})
.unwrap();
error!("Test Error");
warn!("Test Warning");
info!("Test Information");
debug!("Test Debug");
trace!("Test Trace");
let mut thread_naming = String::new();
File::open("thread_naming.log")
.unwrap()
.read_to_string(&mut thread_naming)
.unwrap();
if let Some(name) = std::thread::current().name() {
assert!(thread_naming.contains(&format!("({})", name)));
}
for j in 1..i {
let mut error = String::new();
File::open(&format!("error_{}.log", j))
.unwrap()
.read_to_string(&mut error)
.unwrap();
let mut warn = String::new();
File::open(&format!("warn_{}.log", j))
.unwrap()
.read_to_string(&mut warn)
.unwrap();
let mut info = String::new();
File::open(&format!("info_{}.log", j))
.unwrap()
.read_to_string(&mut info)
.unwrap();
let mut debug = String::new();
File::open(&format!("debug_{}.log", j))
.unwrap()
.read_to_string(&mut debug)
.unwrap();
let mut trace = String::new();
File::open(&format!("trace_{}.log", j))
.unwrap()
.read_to_string(&mut trace)
.unwrap();
assert!(error.contains("Test Error"));
assert!(!error.contains("Test Warning"));
assert!(!error.contains("Test Information"));
assert!(!error.contains("Test Debug"));
assert!(!error.contains("Test Trace"));
assert!(warn.contains("Test Error"));
assert!(warn.contains("Test Warning"));
assert!(!warn.contains("Test Information"));
assert!(!warn.contains("Test Debug"));
assert!(!warn.contains("Test Trace"));
assert!(info.contains("Test Error"));
assert!(info.contains("Test Warning"));
assert!(info.contains("Test Information"));
assert!(!info.contains("Test Debug"));
assert!(!info.contains("Test Trace"));
assert!(debug.contains("Test Error"));
assert!(debug.contains("Test Warning"));
assert!(debug.contains("Test Information"));
assert!(debug.contains("Test Debug"));
assert!(!debug.contains("Test Trace"));
assert!(trace.contains("Test Error"));
assert!(trace.contains("Test Warning"));
assert!(trace.contains("Test Information"));
assert!(trace.contains("Test Debug"));
assert!(trace.contains("Test Trace"));
}
}
}