use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use std::sync::{Mutex, OnceLock};
static LOG_SINK: OnceLock<Mutex<Box<dyn Write + Send>>> = OnceLock::new();
#[derive(Debug, Clone, Copy)]
pub enum Level {
Error,
Warn,
Info,
Debug,
}
impl Level {
fn as_str(self) -> &'static str {
match self {
Self::Error => "ERROR",
Self::Warn => "WARN",
Self::Info => "INFO",
Self::Debug => "DEBUG",
}
}
}
pub fn init_file(path: impl AsRef<Path>) {
let path = path.as_ref();
if let Some(parent) = path.parent() {
let _ = std::fs::create_dir_all(parent);
}
if let Ok(f) = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(path)
{
let _ = LOG_SINK.set(Mutex::new(Box::new(f)));
}
}
pub fn init_stderr() {
let _ = LOG_SINK.set(Mutex::new(Box::new(std::io::stderr())));
}
pub fn write(level: Level, msg: &str) {
if let Some(mtx) = LOG_SINK.get() {
if let Ok(mut w) = mtx.lock() {
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
let _ = writeln!(w, "[{}] {}: {}", ts, level.as_str(), msg);
}
}
}
#[macro_export]
macro_rules! rlog {
($level:ident, $($arg:tt)+) => {
$crate::log::write($crate::log::Level::$level, &format!($($arg)+))
};
}