simplelog/loggers/
comblog.rs

1// Copyright 2016 Victor Brekenfeld
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! Module providing the CombinedLogger Implementation
9
10use crate::{Config, SharedLogger};
11use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};
12
13/// The CombinedLogger struct. Provides a Logger implementation that proxies multiple Loggers as one.
14///
15/// The purpose is to allow multiple Loggers to be set globally
16pub struct CombinedLogger {
17    level: LevelFilter,
18    logger: Vec<Box<dyn SharedLogger>>,
19}
20
21impl CombinedLogger {
22    /// init function. Globally initializes the CombinedLogger as the one and only used log facility.
23    ///
24    /// Takes all used Loggers as a Vector argument. None of those Loggers should already be set globally.
25    ///
26    /// All loggers need to implement `log::Log` and `logger::SharedLogger` and need to provide a way to be
27    /// initialized without calling `set_logger`. All loggers of this library provide a `new(..)`` method
28    /// for that purpose.
29    /// Fails if another logger is already set globally.
30    ///
31    /// # Examples
32    /// ```
33    /// # extern crate simplelog;
34    /// # use simplelog::*;
35    /// # use std::fs::File;
36    /// # fn main() {
37    /// let _ = CombinedLogger::init(
38    ///             vec![
39    /// #               #[cfg(feature = "termcolor")]
40    ///                 TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed, ColorChoice::Auto),
41    ///                 WriteLogger::new(LevelFilter::Info, Config::default(), File::create("my_rust_bin.log").unwrap())
42    ///             ]
43    ///         );
44    /// # }
45    /// ```
46    pub fn init(logger: Vec<Box<dyn SharedLogger>>) -> Result<(), SetLoggerError> {
47        let comblog = CombinedLogger::new(logger);
48        set_max_level(comblog.level());
49        set_boxed_logger(comblog)
50    }
51
52    /// allows to create a new logger, that can be independently used, no matter whats globally set.
53    ///
54    /// no macros are provided for this case and you probably
55    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
56    ///
57    /// Takes all used loggers as a Vector argument. The log level is automatically determined by the
58    /// lowest log level used by the given loggers.
59    ///
60    /// All loggers need to implement log::Log.
61    ///
62    /// # Examples
63    /// ```
64    /// # extern crate simplelog;
65    /// # use simplelog::*;
66    /// # use std::fs::File;
67    /// # fn main() {
68    /// let combined_logger = CombinedLogger::new(
69    ///             vec![
70    /// #               #[cfg(feature = "termcolor")]
71    ///                 TermLogger::new(LevelFilter::Debug, Config::default(), TerminalMode::Mixed, ColorChoice::Auto),
72    ///                 WriteLogger::new(LevelFilter::Info, Config::default(), File::create("my_rust_bin.log").unwrap())
73    ///             ]
74    ///         );
75    /// # }
76    /// ```
77    pub fn new(logger: Vec<Box<dyn SharedLogger>>) -> Box<CombinedLogger> {
78        let mut log_level = LevelFilter::Off;
79        for log in &logger {
80            if log_level < log.level() {
81                log_level = log.level();
82            }
83        }
84
85        Box::new(CombinedLogger {
86            level: log_level,
87            logger,
88        })
89    }
90}
91
92impl Log for CombinedLogger {
93    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
94        metadata.level() <= self.level
95    }
96
97    fn log(&self, record: &Record<'_>) {
98        if self.enabled(record.metadata()) {
99            for log in &self.logger {
100                log.log(record);
101            }
102        }
103    }
104
105    fn flush(&self) {
106        for log in &self.logger {
107            log.flush();
108        }
109    }
110}
111
112impl SharedLogger for CombinedLogger {
113    fn level(&self) -> LevelFilter {
114        self.level
115    }
116
117    fn config(&self) -> Option<&Config> {
118        None
119    }
120
121    fn as_log(self: Box<Self>) -> Box<dyn Log> {
122        Box::new(*self)
123    }
124}