1#![deny(missing_docs, rust_2018_idioms)]
23
24mod config;
25mod loggers;
26
27pub use self::config::{Config, ConfigBuilder, LevelPadding, ThreadLogMode, ThreadPadding};
28#[cfg(feature = "test")]
29pub use self::loggers::TestLogger;
30pub use self::loggers::{CombinedLogger, SimpleLogger, WriteLogger};
31#[cfg(feature = "termcolor")]
32pub use self::loggers::{TermLogger, TerminalMode};
33#[cfg(feature = "termcolor")]
34pub use termcolor::{Color, ColorChoice};
35
36pub use log::{Level, LevelFilter};
37
38use log::Log;
39#[cfg(test)]
40use log::*;
41
42pub trait SharedLogger: Log {
48 fn level(&self) -> LevelFilter;
61
62 fn config(&self) -> Option<&Config>;
77
78 fn as_log(self: Box<Self>) -> Box<dyn Log>;
80}
81
82#[cfg(test)]
83mod tests {
84 use std::fs::File;
85 use std::io::Read;
86
87 use super::*;
88
89 #[test]
90 fn test() {
91 let mut i = 0;
92
93 CombinedLogger::init({
94 let mut vec = Vec::new();
95 let mut conf_builder = ConfigBuilder::new();
96
97 let conf_thread_name = ConfigBuilder::new()
98 .set_time_level(LevelFilter::Off)
99 .set_thread_level(LevelFilter::Error)
100 .set_thread_mode(ThreadLogMode::Names)
101 .build();
102
103 vec.push(WriteLogger::new(
104 LevelFilter::Error,
105 conf_thread_name,
106 File::create("thread_naming.log").unwrap(),
107 ) as Box<dyn SharedLogger>);
108
109 for elem in vec![
110 LevelFilter::Off,
111 LevelFilter::Trace,
112 LevelFilter::Debug,
113 LevelFilter::Info,
114 LevelFilter::Warn,
115 LevelFilter::Error,
116 ] {
117 let conf = conf_builder
118 .set_location_level(elem)
119 .set_target_level(elem)
120 .set_max_level(elem)
121 .set_time_level(elem)
122 .build();
123 i += 1;
124
125 vec.push(
127 SimpleLogger::new(LevelFilter::Error, conf.clone()) as Box<dyn SharedLogger>
128 );
129 #[cfg(feature = "termcolor")]
130 vec.push(TermLogger::new(
131 LevelFilter::Error,
132 conf.clone(),
133 TerminalMode::Mixed,
134 ColorChoice::Auto,
135 ) as Box<dyn SharedLogger>);
136 vec.push(WriteLogger::new(
137 LevelFilter::Error,
138 conf.clone(),
139 File::create(&format!("error_{}.log", i)).unwrap(),
140 ) as Box<dyn SharedLogger>);
141 #[cfg(feature = "test")]
142 vec.push(TestLogger::new(LevelFilter::Error, conf.clone()));
143
144 vec.push(
146 SimpleLogger::new(LevelFilter::Warn, conf.clone()) as Box<dyn SharedLogger>
147 );
148 #[cfg(feature = "termcolor")]
149 vec.push(TermLogger::new(
150 LevelFilter::Warn,
151 conf.clone(),
152 TerminalMode::Mixed,
153 ColorChoice::Auto,
154 ) as Box<dyn SharedLogger>);
155 vec.push(WriteLogger::new(
156 LevelFilter::Warn,
157 conf.clone(),
158 File::create(&format!("warn_{}.log", i)).unwrap(),
159 ) as Box<dyn SharedLogger>);
160 #[cfg(feature = "test")]
161 vec.push(TestLogger::new(LevelFilter::Warn, conf.clone()));
162
163 vec.push(
165 SimpleLogger::new(LevelFilter::Info, conf.clone()) as Box<dyn SharedLogger>
166 );
167 #[cfg(feature = "termcolor")]
168 vec.push(TermLogger::new(
169 LevelFilter::Info,
170 conf.clone(),
171 TerminalMode::Mixed,
172 ColorChoice::Auto,
173 ) as Box<dyn SharedLogger>);
174 vec.push(WriteLogger::new(
175 LevelFilter::Info,
176 conf.clone(),
177 File::create(&format!("info_{}.log", i)).unwrap(),
178 ) as Box<dyn SharedLogger>);
179 #[cfg(feature = "test")]
180 vec.push(TestLogger::new(LevelFilter::Info, conf.clone()));
181
182 vec.push(
184 SimpleLogger::new(LevelFilter::Debug, conf.clone()) as Box<dyn SharedLogger>
185 );
186 #[cfg(feature = "termcolor")]
187 vec.push(TermLogger::new(
188 LevelFilter::Debug,
189 conf.clone(),
190 TerminalMode::Mixed,
191 ColorChoice::Auto,
192 ) as Box<dyn SharedLogger>);
193 vec.push(WriteLogger::new(
194 LevelFilter::Debug,
195 conf.clone(),
196 File::create(&format!("debug_{}.log", i)).unwrap(),
197 ) as Box<dyn SharedLogger>);
198 #[cfg(feature = "test")]
199 vec.push(TestLogger::new(LevelFilter::Debug, conf.clone()));
200
201 vec.push(
203 SimpleLogger::new(LevelFilter::Trace, conf.clone()) as Box<dyn SharedLogger>
204 );
205 #[cfg(feature = "termcolor")]
206 vec.push(TermLogger::new(
207 LevelFilter::Trace,
208 conf.clone(),
209 TerminalMode::Mixed,
210 ColorChoice::Auto,
211 ) as Box<dyn SharedLogger>);
212 vec.push(WriteLogger::new(
213 LevelFilter::Trace,
214 conf.clone(),
215 File::create(&format!("trace_{}.log", i)).unwrap(),
216 ) as Box<dyn SharedLogger>);
217 #[cfg(feature = "test")]
218 vec.push(TestLogger::new(LevelFilter::Trace, conf.clone()));
219 }
220
221 vec
222 })
223 .unwrap();
224
225 error!("Test Error");
226 warn!("Test Warning");
227 info!("Test Information");
228 debug!("Test Debug");
229 trace!("Test Trace");
230
231 let mut thread_naming = String::new();
232 File::open("thread_naming.log")
233 .unwrap()
234 .read_to_string(&mut thread_naming)
235 .unwrap();
236
237 if let Some(name) = std::thread::current().name() {
238 assert!(thread_naming.contains(&format!("({})", name)));
239 }
240
241 for j in 1..i {
242 let mut error = String::new();
243 File::open(&format!("error_{}.log", j))
244 .unwrap()
245 .read_to_string(&mut error)
246 .unwrap();
247 let mut warn = String::new();
248 File::open(&format!("warn_{}.log", j))
249 .unwrap()
250 .read_to_string(&mut warn)
251 .unwrap();
252 let mut info = String::new();
253 File::open(&format!("info_{}.log", j))
254 .unwrap()
255 .read_to_string(&mut info)
256 .unwrap();
257 let mut debug = String::new();
258 File::open(&format!("debug_{}.log", j))
259 .unwrap()
260 .read_to_string(&mut debug)
261 .unwrap();
262 let mut trace = String::new();
263 File::open(&format!("trace_{}.log", j))
264 .unwrap()
265 .read_to_string(&mut trace)
266 .unwrap();
267
268 assert!(error.contains("Test Error"));
269 assert!(!error.contains("Test Warning"));
270 assert!(!error.contains("Test Information"));
271 assert!(!error.contains("Test Debug"));
272 assert!(!error.contains("Test Trace"));
273
274 assert!(warn.contains("Test Error"));
275 assert!(warn.contains("Test Warning"));
276 assert!(!warn.contains("Test Information"));
277 assert!(!warn.contains("Test Debug"));
278 assert!(!warn.contains("Test Trace"));
279
280 assert!(info.contains("Test Error"));
281 assert!(info.contains("Test Warning"));
282 assert!(info.contains("Test Information"));
283 assert!(!info.contains("Test Debug"));
284 assert!(!info.contains("Test Trace"));
285
286 assert!(debug.contains("Test Error"));
287 assert!(debug.contains("Test Warning"));
288 assert!(debug.contains("Test Information"));
289 assert!(debug.contains("Test Debug"));
290 assert!(!debug.contains("Test Trace"));
291
292 assert!(trace.contains("Test Error"));
293 assert!(trace.contains("Test Warning"));
294 assert!(trace.contains("Test Information"));
295 assert!(trace.contains("Test Debug"));
296 assert!(trace.contains("Test Trace"));
297 }
298 }
299}