use log::{Record, Level, Metadata, LevelFilter};
use std::sync::Mutex;
use std::path::Path;
use std::fs::{ File, OpenOptions };
use std::io::Write;
use chrono::Local;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
struct Logsy(Mutex<LogsyConf>);
struct LogsyConf {
installed: bool,
echo: bool,
file: Option<File>,
level: Option<Level>,
}
impl log::Log for Logsy {
fn enabled(&self, metadata: &Metadata) -> bool {
if let Some(level) = self.0.lock().unwrap().level {
metadata.level() <= level
} else {
false
}
}
fn log(&self, record: &Record) {
if !self.enabled(record.metadata()) {
return;
}
let ts = Local::now().format("%Y-%m-%d %H:%M:%S");
let mut conf = self.0.lock().unwrap();
let color = match record.metadata().level() {
Level::Error | Level::Warn => Some(Color::Red),
Level::Info => Some(Color::Green),
_ => None,
};
if conf.echo {
let mut stdout = StandardStream::stdout(ColorChoice::Always);
print!("[{}][", ts);
let _ = stdout.set_color(ColorSpec::new().set_fg(color));
print!("{}", record.level());
let _ = stdout.reset();
println!("] {}", record.args());
}
if let Some(file) = &mut conf.file {
let _ = writeln!(file, "[{}][{}] {}", ts, record.level(), record.args());
let _ = file.flush();
}
}
fn flush(&self) {}
}
static LOGSY: Logsy = Logsy(Mutex::new(LogsyConf { installed: false, echo: false, file: None, level: None }));
fn check_installed() {
let installed = LOGSY.0.lock().unwrap().installed;
if !installed {
LOGSY.0.lock().unwrap().installed = true;
log::set_logger(&LOGSY).unwrap();
set_level(LevelFilter::Info);
}
}
pub fn set_echo(echo: bool) {
check_installed();
LOGSY.0.lock().unwrap().echo = echo;
}
pub fn set_filename(filename: Option<&str>) -> Option<()> {
check_installed();
if let Some(filename) = filename {
let path = Path::new(filename);
if let Some(parent) = path.parent() {
let parent_path = parent.to_str()?;
if !parent_path.is_empty() {
if let Err(err) = std::fs::create_dir_all(parent_path) {
eprintln!("Couldn't create {}: {}", parent_path, err);
return None;
}
}
}
let file = OpenOptions::new().create(true).append(true).open(filename).unwrap();
LOGSY.0.lock().unwrap().file = Some(file);
} else {
LOGSY.0.lock().unwrap().file = None;
}
Some(())
}
pub fn set_level(filter: LevelFilter) {
log::set_max_level(filter);
LOGSY.0.lock().unwrap().level = filter.to_level();
}