#[cfg_attr(test, macro_use)]
extern crate log;
pub struct MultiLogger {
loggers: Vec<Box<log::Log>>,
}
impl MultiLogger {
pub fn new(loggers: Vec<Box<log::Log>>) -> Self {
MultiLogger { loggers }
}
pub fn init(loggers: Vec<Box<log::Log>>, level: log::Level) -> Result<(), log::SetLoggerError> {
log::set_max_level(level.to_level_filter());
log::set_boxed_logger(Box::new(MultiLogger::new(loggers)))
}
}
impl log::Log for MultiLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
self.loggers.iter().any(|logger| logger.enabled(metadata))
}
fn log(&self, record: &log::Record) {
self.loggers.iter().for_each(|logger| logger.log(record));
}
fn flush(&self) {
self.loggers.iter().for_each(|logger| logger.flush());
}
}
#[cfg(test)]
mod tests {
extern crate log;
use std::sync::{Arc, Mutex};
use std::ops::Deref;
use super::MultiLogger;
struct VecLogger {
messages: Arc<Mutex<Vec<String>>>,
level: log::Level,
}
impl VecLogger {
fn new(messages: Arc<Mutex<Vec<String>>>, level: log::Level) -> Self {
VecLogger { messages, level }
}
}
impl log::Log for VecLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= self.level
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
let mut messages = self.messages.lock().unwrap();
messages.push(format!("{}", record.args()));
}
}
fn flush(&self) {}
}
#[test]
fn multiple_vec_loggers() {
let mutex_a = Arc::new(Mutex::new(Vec::new()));
let mutex_b = Arc::new(Mutex::new(Vec::new()));
let mutex_c = Arc::new(Mutex::new(Vec::new()));
let logger = MultiLogger::new(vec![Box::new(VecLogger::new(mutex_a.clone(), log::Level::Debug)),
Box::new(VecLogger::new(mutex_b.clone(), log::Level::Info)),
Box::new(VecLogger::new(mutex_c.clone(), log::Level::Error))]);
log::set_max_level(log::Level::Trace.to_level_filter());
log::set_boxed_logger(Box::new(logger)).unwrap();
debug!("debug");
info!("info");
warn!("warn");
error!("error");
assert_eq!(get_messages(mutex_a.clone()), vec!["debug", "info", "warn", "error"]);
assert_eq!(get_messages(mutex_b.clone()), vec!["info", "warn", "error"]);
assert_eq!(get_messages(mutex_c.clone()), vec!["error"]);
}
fn get_messages(mutex: Arc<Mutex<Vec<String>>>) -> Vec<String> {
let lock = mutex.lock().unwrap();
lock.deref().clone()
}
}