blob: 87d0303f94bb3d45e46964e62d3e1e527d2ff71f [file] [log] [blame]
// Copyright 2016 Victor Brekenfeld
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Module providing the CombinedLogger Implementation
use crate::{Config, SharedLogger};
use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};
/// The CombinedLogger struct. Provides a Logger implementation that proxies multiple Loggers as one.
///
/// The purpose is to allow multiple Loggers to be set globally
pub struct CombinedLogger {
level: LevelFilter,
logger: Vec<Box<dyn SharedLogger>>,
}
impl CombinedLogger {
/// init function. Globally initializes the CombinedLogger as the one and only used log facility.
///
/// Takes all used Loggers as a Vector argument. None of those Loggers should already be set globally.
///
/// All loggers need to implement `log::Log` and `logger::SharedLogger` and need to provide a way to be
/// initialized without calling `set_logger`. All loggers of this library provide a `new(..)`` method
/// for that purpose.
/// Fails if another logger is already set globally.
///
/// # Examples
/// ```
/// # extern crate simplelog;
/// # use simplelog::*;
/// # use std::fs::File;
/// # fn main() {
/// let _ = CombinedLogger::init(
/// vec![
/// # #[cfg(feature = "termcolor")]
/// TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed),
/// WriteLogger::new(LevelFilter::Info, Config::default(), File::create("my_rust_bin.log").unwrap())
/// ]
/// );
/// # }
/// ```
pub fn init(logger: Vec<Box<dyn SharedLogger>>) -> Result<(), SetLoggerError> {
let comblog = CombinedLogger::new(logger);
set_max_level(comblog.level());
set_boxed_logger(comblog)
}
/// allows to create a new logger, that can be independently used, no matter whats globally set.
///
/// no macros are provided for this case and you probably
/// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
///
/// Takes all used loggers as a Vector argument. The log level is automatically determined by the
/// lowest log level used by the given loggers.
///
/// All loggers need to implement log::Log.
///
/// # Examples
/// ```
/// # extern crate simplelog;
/// # use simplelog::*;
/// # use std::fs::File;
/// # fn main() {
/// let combined_logger = CombinedLogger::new(
/// vec![
/// # #[cfg(feature = "termcolor")]
/// TermLogger::new(LevelFilter::Debug, Config::default(), TerminalMode::Mixed),
/// WriteLogger::new(LevelFilter::Info, Config::default(), File::create("my_rust_bin.log").unwrap())
/// ]
/// );
/// # }
/// ```
pub fn new(logger: Vec<Box<dyn SharedLogger>>) -> Box<CombinedLogger> {
let mut log_level = LevelFilter::Off;
for log in &logger {
if log_level < log.level() {
log_level = log.level();
}
}
Box::new(CombinedLogger {
level: log_level,
logger: logger,
})
}
}
impl Log for CombinedLogger {
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
metadata.level() <= self.level
}
fn log(&self, record: &Record<'_>) {
if self.enabled(record.metadata()) {
for log in &self.logger {
log.log(record);
}
}
}
fn flush(&self) {
for log in &self.logger {
log.flush();
}
}
}
impl SharedLogger for CombinedLogger {
fn level(&self) -> LevelFilter {
self.level
}
fn config(&self) -> Option<&Config> {
None
}
fn as_log(self: Box<Self>) -> Box<dyn Log> {
Box::new(*self)
}
}