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}