1use std::env;
2use std::fmt;
3use std::mem;
4
5use log::{LevelFilter, Metadata, Record};
6
7use crate::enabled;
8use crate::parse_spec;
9use crate::Directive;
10use crate::FilterOp;
11
12pub struct Builder {
33 directives: Vec<Directive>,
34 filter: Option<FilterOp>,
35 built: bool,
36}
37
38impl Builder {
39 pub fn new() -> Builder {
41 Builder {
42 directives: Vec::new(),
43 filter: None,
44 built: false,
45 }
46 }
47
48 pub fn from_env(env: &str) -> Builder {
50 let mut builder = Builder::new();
51
52 if let Ok(s) = env::var(env) {
53 builder.parse(&s);
54 }
55
56 builder
57 }
58
59 fn insert_directive(&mut self, mut directive: Directive) {
61 if let Some(pos) = self
62 .directives
63 .iter()
64 .position(|d| d.name == directive.name)
65 {
66 mem::swap(&mut self.directives[pos], &mut directive);
67 } else {
68 self.directives.push(directive);
69 }
70 }
71
72 pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self {
74 self.filter(Some(module), level)
75 }
76
77 pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self {
79 self.filter(None, level)
80 }
81
82 pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self {
87 self.insert_directive(Directive {
88 name: module.map(|s| s.to_string()),
89 level,
90 });
91 self
92 }
93
94 pub fn parse(&mut self, filters: &str) -> &mut Self {
100 let (directives, filter) = parse_spec(filters);
101
102 self.filter = filter;
103
104 for directive in directives {
105 self.insert_directive(directive);
106 }
107 self
108 }
109
110 pub fn build(&mut self) -> Filter {
112 assert!(!self.built, "attempt to re-use consumed builder");
113 self.built = true;
114
115 let mut directives = Vec::new();
116 if self.directives.is_empty() {
117 directives.push(Directive {
119 name: None,
120 level: LevelFilter::Error,
121 });
122 } else {
123 directives = mem::take(&mut self.directives);
125 directives.sort_by(|a, b| {
128 let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0);
129 let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0);
130 alen.cmp(&blen)
131 });
132 }
133
134 Filter {
135 directives: mem::take(&mut directives),
136 filter: mem::take(&mut self.filter),
137 }
138 }
139}
140
141impl Default for Builder {
142 fn default() -> Self {
143 Builder::new()
144 }
145}
146
147impl fmt::Debug for Builder {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 if self.built {
150 f.debug_struct("Filter").field("built", &true).finish()
151 } else {
152 f.debug_struct("Filter")
153 .field("filter", &self.filter)
154 .field("directives", &self.directives)
155 .finish()
156 }
157 }
158}
159
160pub struct Filter {
168 directives: Vec<Directive>,
169 filter: Option<FilterOp>,
170}
171
172impl Filter {
173 pub fn filter(&self) -> LevelFilter {
190 self.directives
191 .iter()
192 .map(|d| d.level)
193 .max()
194 .unwrap_or(LevelFilter::Off)
195 }
196
197 pub fn matches(&self, record: &Record) -> bool {
199 if !self.enabled(record.metadata()) {
200 return false;
201 }
202
203 if let Some(filter) = self.filter.as_ref() {
204 if !filter.is_match(&record.args().to_string()) {
205 return false;
206 }
207 }
208
209 true
210 }
211
212 pub fn enabled(&self, metadata: &Metadata) -> bool {
214 let level = metadata.level();
215 let target = metadata.target();
216
217 enabled(&self.directives, level, target)
218 }
219}
220
221impl fmt::Debug for Filter {
222 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223 f.debug_struct("Filter")
224 .field("filter", &self.filter)
225 .field("directives", &self.directives)
226 .finish()
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use log::{Level, LevelFilter};
233
234 use super::{enabled, Builder, Directive, Filter};
235
236 fn make_logger_filter(dirs: Vec<Directive>) -> Filter {
237 let mut logger = Builder::new().build();
238 logger.directives = dirs;
239 logger
240 }
241
242 #[test]
243 fn filter_info() {
244 let logger = Builder::new().filter(None, LevelFilter::Info).build();
245 assert!(enabled(&logger.directives, Level::Info, "crate1"));
246 assert!(!enabled(&logger.directives, Level::Debug, "crate1"));
247 }
248
249 #[test]
250 fn filter_beginning_longest_match() {
251 let logger = Builder::new()
252 .filter(Some("crate2"), LevelFilter::Info)
253 .filter(Some("crate2::mod"), LevelFilter::Debug)
254 .filter(Some("crate1::mod1"), LevelFilter::Warn)
255 .build();
256 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
257 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
258 }
259
260 #[test]
273 fn ensure_tests_cover_level_universe() {
274 let level_universe: Level = Level::Trace; match level_universe {
276 Level::Error | Level::Warn | Level::Info | Level::Debug | Level::Trace => (),
277 }
278 }
279
280 #[test]
281 fn parse_default() {
282 let logger = Builder::new().parse("info,crate1::mod1=warn").build();
283 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
284 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
285 }
286
287 #[test]
288 fn parse_default_bare_level_off_lc() {
289 let logger = Builder::new().parse("off").build();
290 assert!(!enabled(&logger.directives, Level::Error, ""));
291 assert!(!enabled(&logger.directives, Level::Warn, ""));
292 assert!(!enabled(&logger.directives, Level::Info, ""));
293 assert!(!enabled(&logger.directives, Level::Debug, ""));
294 assert!(!enabled(&logger.directives, Level::Trace, ""));
295 }
296
297 #[test]
298 fn parse_default_bare_level_off_uc() {
299 let logger = Builder::new().parse("OFF").build();
300 assert!(!enabled(&logger.directives, Level::Error, ""));
301 assert!(!enabled(&logger.directives, Level::Warn, ""));
302 assert!(!enabled(&logger.directives, Level::Info, ""));
303 assert!(!enabled(&logger.directives, Level::Debug, ""));
304 assert!(!enabled(&logger.directives, Level::Trace, ""));
305 }
306
307 #[test]
308 fn parse_default_bare_level_error_lc() {
309 let logger = Builder::new().parse("error").build();
310 assert!(enabled(&logger.directives, Level::Error, ""));
311 assert!(!enabled(&logger.directives, Level::Warn, ""));
312 assert!(!enabled(&logger.directives, Level::Info, ""));
313 assert!(!enabled(&logger.directives, Level::Debug, ""));
314 assert!(!enabled(&logger.directives, Level::Trace, ""));
315 }
316
317 #[test]
318 fn parse_default_bare_level_error_uc() {
319 let logger = Builder::new().parse("ERROR").build();
320 assert!(enabled(&logger.directives, Level::Error, ""));
321 assert!(!enabled(&logger.directives, Level::Warn, ""));
322 assert!(!enabled(&logger.directives, Level::Info, ""));
323 assert!(!enabled(&logger.directives, Level::Debug, ""));
324 assert!(!enabled(&logger.directives, Level::Trace, ""));
325 }
326
327 #[test]
328 fn parse_default_bare_level_warn_lc() {
329 let logger = Builder::new().parse("warn").build();
330 assert!(enabled(&logger.directives, Level::Error, ""));
331 assert!(enabled(&logger.directives, Level::Warn, ""));
332 assert!(!enabled(&logger.directives, Level::Info, ""));
333 assert!(!enabled(&logger.directives, Level::Debug, ""));
334 assert!(!enabled(&logger.directives, Level::Trace, ""));
335 }
336
337 #[test]
338 fn parse_default_bare_level_warn_uc() {
339 let logger = Builder::new().parse("WARN").build();
340 assert!(enabled(&logger.directives, Level::Error, ""));
341 assert!(enabled(&logger.directives, Level::Warn, ""));
342 assert!(!enabled(&logger.directives, Level::Info, ""));
343 assert!(!enabled(&logger.directives, Level::Debug, ""));
344 assert!(!enabled(&logger.directives, Level::Trace, ""));
345 }
346
347 #[test]
348 fn parse_default_bare_level_info_lc() {
349 let logger = Builder::new().parse("info").build();
350 assert!(enabled(&logger.directives, Level::Error, ""));
351 assert!(enabled(&logger.directives, Level::Warn, ""));
352 assert!(enabled(&logger.directives, Level::Info, ""));
353 assert!(!enabled(&logger.directives, Level::Debug, ""));
354 assert!(!enabled(&logger.directives, Level::Trace, ""));
355 }
356
357 #[test]
358 fn parse_default_bare_level_info_uc() {
359 let logger = Builder::new().parse("INFO").build();
360 assert!(enabled(&logger.directives, Level::Error, ""));
361 assert!(enabled(&logger.directives, Level::Warn, ""));
362 assert!(enabled(&logger.directives, Level::Info, ""));
363 assert!(!enabled(&logger.directives, Level::Debug, ""));
364 assert!(!enabled(&logger.directives, Level::Trace, ""));
365 }
366
367 #[test]
368 fn parse_default_bare_level_debug_lc() {
369 let logger = Builder::new().parse("debug").build();
370 assert!(enabled(&logger.directives, Level::Error, ""));
371 assert!(enabled(&logger.directives, Level::Warn, ""));
372 assert!(enabled(&logger.directives, Level::Info, ""));
373 assert!(enabled(&logger.directives, Level::Debug, ""));
374 assert!(!enabled(&logger.directives, Level::Trace, ""));
375 }
376
377 #[test]
378 fn parse_default_bare_level_debug_uc() {
379 let logger = Builder::new().parse("DEBUG").build();
380 assert!(enabled(&logger.directives, Level::Error, ""));
381 assert!(enabled(&logger.directives, Level::Warn, ""));
382 assert!(enabled(&logger.directives, Level::Info, ""));
383 assert!(enabled(&logger.directives, Level::Debug, ""));
384 assert!(!enabled(&logger.directives, Level::Trace, ""));
385 }
386
387 #[test]
388 fn parse_default_bare_level_trace_lc() {
389 let logger = Builder::new().parse("trace").build();
390 assert!(enabled(&logger.directives, Level::Error, ""));
391 assert!(enabled(&logger.directives, Level::Warn, ""));
392 assert!(enabled(&logger.directives, Level::Info, ""));
393 assert!(enabled(&logger.directives, Level::Debug, ""));
394 assert!(enabled(&logger.directives, Level::Trace, ""));
395 }
396
397 #[test]
398 fn parse_default_bare_level_trace_uc() {
399 let logger = Builder::new().parse("TRACE").build();
400 assert!(enabled(&logger.directives, Level::Error, ""));
401 assert!(enabled(&logger.directives, Level::Warn, ""));
402 assert!(enabled(&logger.directives, Level::Info, ""));
403 assert!(enabled(&logger.directives, Level::Debug, ""));
404 assert!(enabled(&logger.directives, Level::Trace, ""));
405 }
406
407 #[test]
412 fn parse_default_bare_level_debug_mixed() {
413 {
414 let logger = Builder::new().parse("Debug").build();
415 assert!(enabled(&logger.directives, Level::Error, ""));
416 assert!(enabled(&logger.directives, Level::Warn, ""));
417 assert!(enabled(&logger.directives, Level::Info, ""));
418 assert!(enabled(&logger.directives, Level::Debug, ""));
419 assert!(!enabled(&logger.directives, Level::Trace, ""));
420 }
421 {
422 let logger = Builder::new().parse("debuG").build();
423 assert!(enabled(&logger.directives, Level::Error, ""));
424 assert!(enabled(&logger.directives, Level::Warn, ""));
425 assert!(enabled(&logger.directives, Level::Info, ""));
426 assert!(enabled(&logger.directives, Level::Debug, ""));
427 assert!(!enabled(&logger.directives, Level::Trace, ""));
428 }
429 {
430 let logger = Builder::new().parse("deBug").build();
431 assert!(enabled(&logger.directives, Level::Error, ""));
432 assert!(enabled(&logger.directives, Level::Warn, ""));
433 assert!(enabled(&logger.directives, Level::Info, ""));
434 assert!(enabled(&logger.directives, Level::Debug, ""));
435 assert!(!enabled(&logger.directives, Level::Trace, ""));
436 }
437 {
438 let logger = Builder::new().parse("DeBuG").build(); assert!(enabled(&logger.directives, Level::Error, ""));
440 assert!(enabled(&logger.directives, Level::Warn, ""));
441 assert!(enabled(&logger.directives, Level::Info, ""));
442 assert!(enabled(&logger.directives, Level::Debug, ""));
443 assert!(!enabled(&logger.directives, Level::Trace, ""));
444 }
445 }
446
447 #[test]
448 fn match_full_path() {
449 let logger = make_logger_filter(vec![
450 Directive {
451 name: Some("crate2".to_string()),
452 level: LevelFilter::Info,
453 },
454 Directive {
455 name: Some("crate1::mod1".to_string()),
456 level: LevelFilter::Warn,
457 },
458 ]);
459 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
460 assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1"));
461 assert!(enabled(&logger.directives, Level::Info, "crate2"));
462 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
463 }
464
465 #[test]
466 fn no_match() {
467 let logger = make_logger_filter(vec![
468 Directive {
469 name: Some("crate2".to_string()),
470 level: LevelFilter::Info,
471 },
472 Directive {
473 name: Some("crate1::mod1".to_string()),
474 level: LevelFilter::Warn,
475 },
476 ]);
477 assert!(!enabled(&logger.directives, Level::Warn, "crate3"));
478 }
479
480 #[test]
481 fn match_beginning() {
482 let logger = make_logger_filter(vec![
483 Directive {
484 name: Some("crate2".to_string()),
485 level: LevelFilter::Info,
486 },
487 Directive {
488 name: Some("crate1::mod1".to_string()),
489 level: LevelFilter::Warn,
490 },
491 ]);
492 assert!(enabled(&logger.directives, Level::Info, "crate2::mod1"));
493 }
494
495 #[test]
496 fn match_beginning_longest_match() {
497 let logger = make_logger_filter(vec![
498 Directive {
499 name: Some("crate2".to_string()),
500 level: LevelFilter::Info,
501 },
502 Directive {
503 name: Some("crate2::mod".to_string()),
504 level: LevelFilter::Debug,
505 },
506 Directive {
507 name: Some("crate1::mod1".to_string()),
508 level: LevelFilter::Warn,
509 },
510 ]);
511 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
512 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
513 }
514
515 #[test]
516 fn match_default() {
517 let logger = make_logger_filter(vec![
518 Directive {
519 name: None,
520 level: LevelFilter::Info,
521 },
522 Directive {
523 name: Some("crate1::mod1".to_string()),
524 level: LevelFilter::Warn,
525 },
526 ]);
527 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
528 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
529 }
530
531 #[test]
532 fn zero_level() {
533 let logger = make_logger_filter(vec![
534 Directive {
535 name: None,
536 level: LevelFilter::Info,
537 },
538 Directive {
539 name: Some("crate1::mod1".to_string()),
540 level: LevelFilter::Off,
541 },
542 ]);
543 assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1"));
544 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
545 }
546}