use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
static MULTI_LOGGER: MultiLogger = MultiLogger::new();
static HAS_MULTI_LOGGER: AtomicBool = AtomicBool::new(false);
#[derive(Clone, Copy, Debug)]
pub struct MultiLoggerNotSetupError {}
pub fn init() -> Result<(), log::SetLoggerError> {
HAS_MULTI_LOGGER.store(true, SeqCst);
log::set_logger(&MULTI_LOGGER)
}
pub fn add_boxed_logger(logger: Box<dyn log::Log>) -> Result<(), MultiLoggerNotSetupError> {
add_logger(Box::leak(logger))
}
pub fn add_logger(logger: &'static dyn log::Log) -> Result<(), MultiLoggerNotSetupError> {
if HAS_MULTI_LOGGER.load(SeqCst) {
MULTI_LOGGER.loggers.write().push(logger);
Ok(())
} else {
Err(MultiLoggerNotSetupError {})
}
}
struct MultiLogger {
loggers: parking_lot::RwLock<Vec<&'static dyn log::Log>>,
}
impl MultiLogger {
pub const fn new() -> Self {
Self {
loggers: parking_lot::RwLock::new(vec![]),
}
}
}
impl log::Log for MultiLogger {
fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
self.loggers
.read()
.iter()
.any(|logger| logger.enabled(metadata))
}
fn log(&self, record: &log::Record<'_>) {
for logger in self.loggers.read().iter() {
logger.log(record);
}
}
fn flush(&self) {
for logger in self.loggers.read().iter() {
logger.flush();
}
}
}