use env_logger::{
fmt::{Color, Formatter},
Builder as LogBuilder,
};
use log::LevelFilter;
use std::io::{IsTerminal, Write};
#[derive(Debug, PartialEq, Clone)]
pub struct Config {
pub mode: Option<String>,
pub color: bool,
pub file: Option<String>,
}
impl Default for Config {
fn default() -> Self {
Config { mode: None, color: !cfg!(windows), file: None }
}
}
pub static LOG_ENABLED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
pub fn setup_log(config: &Config) {
let mut levels = String::new();
let mut builder = LogBuilder::new();
builder.filter(None, LevelFilter::Info);
if let Ok(lvl) = std::env::var("RUST_LOG") {
levels.push_str(&lvl);
levels.push(',');
builder.parse_filters(&lvl);
}
if let Some(ref s) = config.mode {
levels.push_str(s);
builder.parse_filters(s);
}
let isatty = std::io::stderr().is_terminal();
let enable_color = config.color && isatty;
let format = move |buf: &mut Formatter, record: &log::Record| {
let mut bold = buf.style();
bold.set_bold(true);
let mut blue_bold = buf.style();
blue_bold.set_color(Color::Blue).set_bold(true);
let dt = chrono::Local::now();
let timestamp = dt.format("%Y-%m-%d %H:%M:%S");
let with_color = if enable_color && log::max_level() <= LevelFilter::Info {
format!("{} {}", bold.value(timestamp), record.args(),)
} else {
let name = std::thread::current()
.name()
.map_or_else(Default::default, |x| format!("{}", blue_bold.value(x)));
format!(
"{} {} {} {} {}",
bold.value(timestamp),
name,
record.level(),
record.target(),
record.args()
)
};
if !isatty && record.level() <= log::Level::Info && std::io::stdout().is_terminal() {
println!("{with_color}");
}
if LOG_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
writeln!(buf, "{with_color}")?;
}
Ok(())
};
builder.format(format);
let _ = builder.try_init();
}