use std::{env, error::Error, fs::File, io, sync::{Mutex, OnceLock}};
use env_logger::Target;
use log::LevelFilter;
use serde::{Serialize, Deserialize};
struct MultiWriter {
file: Mutex<File>,
stdout: io::Stdout,
}
impl io::Write for MultiWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut file = self.file.lock().unwrap();
file.write_all(buf)?;
self.stdout.write_all(buf)?;
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
let mut file = self.file.lock().unwrap();
file.flush()?;
self.stdout.flush()?;
Ok(())
}
}
static LOGGER_INIT: OnceLock<()> = OnceLock::new();
pub fn init_global_logger_once(output_file: &'static str) {
LOGGER_INIT.get_or_init(|| {
let log_file = File::create(output_file)
.expect("Failed to create log file");
let multi_writer = MultiWriter {
file: Mutex::new(log_file),
stdout: io::stdout(),
};
let level = if let Ok(level) = env::var("RUST_LOG") {
match level.to_lowercase().as_str() {
"error" => LevelFilter::Error,
"warn" | "warning" => LevelFilter::Warn,
"info" => LevelFilter::Info,
"debug" => LevelFilter::Debug,
"trace" => LevelFilter::Trace,
_ => LevelFilter::Info, }
} else {
LevelFilter::Info
};
env_logger::Builder::new()
.target(Target::Pipe(Box::new(multi_writer)))
.filter_level(level)
.init();
log::info!("Logger initialized successfully");
});
}
pub trait TraceLog: Serialize + for<'de> Deserialize<'de> {
fn store_trace_file(self, filename: &'static str) -> Result<(), Box<dyn Error>>;
fn get_trace(filename: &'static str) -> Result<Self, Box<dyn Error>>;
}