use env_logger::fmt::{Color, Style, StyledValue};
use env_logger::{Builder, WriteStyle};
use log::{Level, LevelFilter};
use std::fmt;
use std::io::Write;
use std::sync::atomic::{AtomicUsize, Ordering};
struct Padded<T> {
value: T,
width: usize,
}
pub fn try_init() {
let mut builder = Builder::from_default_env();
let _ = builder
.format(|f, record| {
let target = record.target();
let max_width = max_target_width(target);
let mut style = f.style();
let level = colored_level(&mut style, record.level());
let mut style = f.style();
let target = style.set_bold(true).value(Padded {
value: target,
width: max_width,
});
writeln!(
f,
"{} {}{} - {}",
level,
target,
if let Some(line) = record.line() {
format!(" [{:0>4}]", line)
} else {
String::new()
},
record.args(),
)
})
.filter(None, LevelFilter::Trace)
.format_timestamp_millis()
.write_style(WriteStyle::Always)
.try_init();
}
impl<T: fmt::Display> fmt::Display for Padded<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{: <width$}", self.value, width = self.width)
}
}
static MAX_MODULE_WIDTH: AtomicUsize = AtomicUsize::new(0);
fn max_target_width(target: &str) -> usize {
let max_width = MAX_MODULE_WIDTH.load(Ordering::Relaxed);
if max_width < target.len() {
MAX_MODULE_WIDTH.store(target.len(), Ordering::Relaxed);
target.len()
} else {
max_width
}
}
fn colored_level<'a>(style: &'a mut Style, level: Level) -> StyledValue<'a, &'static str> {
match level {
Level::Trace => style.set_color(Color::Magenta).value("TRACE"),
Level::Debug => style.set_color(Color::Blue).value("DEBUG"),
Level::Info => style.set_color(Color::Green).value("INFO "),
Level::Warn => style.set_color(Color::Yellow).value("WARN "),
Level::Error => style.set_color(Color::Red).value("ERROR"),
}
}