use super::logging::should_skip;
use crate::{Config, LevelPadding, SharedLogger};
use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};
use std::thread;
pub struct TestLogger {
level: LevelFilter,
config: Config,
}
impl TestLogger {
pub fn init(log_level: LevelFilter, config: Config) -> Result<(), SetLoggerError> {
set_max_level(log_level);
set_boxed_logger(TestLogger::new(log_level, config))
}
pub fn new(log_level: LevelFilter, config: Config) -> Box<TestLogger> {
Box::new(TestLogger {
level: log_level,
config,
})
}
}
impl Log for TestLogger {
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
metadata.level() <= self.level
}
fn log(&self, record: &Record<'_>) {
if self.enabled(record.metadata()) {
let _ = log(&self.config, record);
}
}
fn flush(&self) {}
}
impl SharedLogger for TestLogger {
fn level(&self) -> LevelFilter {
self.level
}
fn config(&self) -> Option<&Config> {
Some(&self.config)
}
fn as_log(self: Box<Self>) -> Box<dyn Log> {
Box::new(*self)
}
}
#[inline(always)]
pub fn log(config: &Config, record: &Record<'_>) {
if should_skip(&config, &record) {
return;
}
if config.time <= record.level() && config.time != LevelFilter::Off {
write_time(config);
}
if config.level <= record.level() && config.level != LevelFilter::Off {
write_level(record, config);
}
if config.thread < record.level() && config.thread != LevelFilter::Off {
write_thread_id();
}
if config.target <= record.level() && config.target != LevelFilter::Off {
write_target(record);
}
if config.location <= record.level() && config.location != LevelFilter::Off {
write_location(record);
}
write_args(record);
}
#[inline(always)]
pub fn write_time(config: &Config) {
let cur_time = if config.time_local {
chrono::Local::now().naive_local() + config.time_offset
} else {
chrono::Utc::now().naive_utc() + config.time_offset
};
print!("{} ", cur_time.format(&*config.time_format));
}
#[inline(always)]
pub fn write_level(record: &Record<'_>, config: &Config) {
match config.level_padding {
LevelPadding::Left => print!("[{: >5}] ", record.level()),
LevelPadding::Right => print!("[{: <5}] ", record.level()),
LevelPadding::Off => print!("[{}] ", record.level()),
};
}
#[inline(always)]
pub fn write_thread_id() {
let id = format!("{:?}", thread::current().id());
let id = id.replace("ThreadId(", "");
let id = id.replace(")", "");
print!("({}) ", id);
}
#[inline(always)]
pub fn write_target(record: &Record<'_>) {
print!("{}: ", record.target());
}
#[inline(always)]
pub fn write_location(record: &Record<'_>) {
let file = record.file().unwrap_or("<unknown>");
if let Some(line) = record.line() {
print!("[{}:{}] ", file, line);
} else {
print!("[{}:<unknown>] ", file);
}
}
#[inline(always)]
pub fn write_args(record: &Record<'_>) {
println!("{}", record.args());
}