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::parser::ParseResult;
10use crate::Directive;
11use crate::FilterOp;
12use crate::ParseError;
13
14pub struct Builder {
35 directives: Vec<Directive>,
36 filter: Option<FilterOp>,
37 built: bool,
38}
39
40impl Builder {
41 pub fn new() -> Builder {
43 Builder {
44 directives: Vec::new(),
45 filter: None,
46 built: false,
47 }
48 }
49
50 pub fn from_env(env: &str) -> Builder {
52 let mut builder = Builder::new();
53
54 if let Ok(s) = env::var(env) {
55 builder.parse(&s);
56 }
57
58 builder
59 }
60
61 fn insert_directive(&mut self, mut directive: Directive) {
63 if let Some(pos) = self
64 .directives
65 .iter()
66 .position(|d| d.name == directive.name)
67 {
68 mem::swap(&mut self.directives[pos], &mut directive);
69 } else {
70 self.directives.push(directive);
71 }
72 }
73
74 pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self {
76 self.filter(Some(module), level)
77 }
78
79 pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self {
81 self.filter(None, level)
82 }
83
84 pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self {
89 self.insert_directive(Directive {
90 name: module.map(|s| s.to_owned()),
91 level,
92 });
93 self
94 }
95
96 pub fn parse(&mut self, filters: &str) -> &mut Self {
102 #![allow(clippy::print_stderr)] let ParseResult {
105 directives,
106 filter,
107 errors,
108 } = parse_spec(filters);
109
110 for error in errors {
111 eprintln!("warning: {error}, ignoring it");
112 }
113
114 self.filter = filter;
115
116 for directive in directives {
117 self.insert_directive(directive);
118 }
119 self
120 }
121
122 pub fn try_parse(&mut self, filters: &str) -> Result<&mut Self, ParseError> {
128 let (directives, filter) = parse_spec(filters).ok()?;
129
130 self.filter = filter;
131
132 for directive in directives {
133 self.insert_directive(directive);
134 }
135 Ok(self)
136 }
137
138 pub fn build(&mut self) -> Filter {
140 assert!(!self.built, "attempt to re-use consumed builder");
141 self.built = true;
142
143 let mut directives = Vec::new();
144 if self.directives.is_empty() {
145 directives.push(Directive {
147 name: None,
148 level: LevelFilter::Error,
149 });
150 } else {
151 directives = mem::take(&mut self.directives);
153 directives.sort_by(|a, b| {
156 let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0);
157 let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0);
158 alen.cmp(&blen)
159 });
160 }
161
162 Filter {
163 directives: mem::take(&mut directives),
164 filter: mem::take(&mut self.filter),
165 }
166 }
167}
168
169impl Default for Builder {
170 fn default() -> Self {
171 Builder::new()
172 }
173}
174
175impl fmt::Debug for Builder {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 if self.built {
178 f.debug_struct("Filter").field("built", &true).finish()
179 } else {
180 f.debug_struct("Filter")
181 .field("filter", &self.filter)
182 .field("directives", &self.directives)
183 .finish()
184 }
185 }
186}
187
188#[derive(Clone)]
196pub struct Filter {
197 directives: Vec<Directive>,
198 filter: Option<FilterOp>,
199}
200
201impl Filter {
202 pub fn filter(&self) -> LevelFilter {
219 self.directives
220 .iter()
221 .map(|d| d.level)
222 .max()
223 .unwrap_or(LevelFilter::Off)
224 }
225
226 pub fn matches(&self, record: &Record<'_>) -> bool {
228 if !self.enabled(record.metadata()) {
229 return false;
230 }
231
232 if let Some(filter) = self.filter.as_ref() {
233 if !filter.is_match(&record.args().to_string()) {
234 return false;
235 }
236 }
237
238 true
239 }
240
241 pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
243 let level = metadata.level();
244 let target = metadata.target();
245
246 enabled(&self.directives, level, target)
247 }
248}
249
250impl fmt::Debug for Filter {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 f.debug_struct("Filter")
253 .field("filter", &self.filter)
254 .field("directives", &self.directives)
255 .finish()
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use log::{Level, LevelFilter};
262 use snapbox::{assert_data_eq, str};
263
264 use super::{enabled, Builder, Directive, Filter};
265
266 fn make_logger_filter(dirs: Vec<Directive>) -> Filter {
267 let mut logger = Builder::new().build();
268 logger.directives = dirs;
269 logger
270 }
271
272 #[test]
273 fn filter_info() {
274 let logger = Builder::new().filter(None, LevelFilter::Info).build();
275 assert!(enabled(&logger.directives, Level::Info, "crate1"));
276 assert!(!enabled(&logger.directives, Level::Debug, "crate1"));
277 }
278
279 #[test]
280 fn filter_beginning_longest_match() {
281 let logger = Builder::new()
282 .filter(Some("crate2"), LevelFilter::Info)
283 .filter(Some("crate2::mod"), LevelFilter::Debug)
284 .filter(Some("crate1::mod1"), LevelFilter::Warn)
285 .build();
286 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
287 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
288 }
289
290 #[test]
303 fn ensure_tests_cover_level_universe() {
304 let level_universe: Level = Level::Trace; match level_universe {
306 Level::Error | Level::Warn | Level::Info | Level::Debug | Level::Trace => (),
307 }
308 }
309
310 #[test]
311 fn parse_default() {
312 let logger = Builder::new().parse("info,crate1::mod1=warn").build();
313 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
314 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
315 }
316
317 #[test]
318 fn parse_default_bare_level_off_lc() {
319 let logger = Builder::new().parse("off").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_off_uc() {
329 let logger = Builder::new().parse("OFF").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_error_lc() {
339 let logger = Builder::new().parse("error").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_error_uc() {
349 let logger = Builder::new().parse("ERROR").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_warn_lc() {
359 let logger = Builder::new().parse("warn").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_warn_uc() {
369 let logger = Builder::new().parse("WARN").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_info_lc() {
379 let logger = Builder::new().parse("info").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_info_uc() {
389 let logger = Builder::new().parse("INFO").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_debug_lc() {
399 let logger = Builder::new().parse("debug").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]
408 fn parse_default_bare_level_debug_uc() {
409 let logger = Builder::new().parse("DEBUG").build();
410 assert!(enabled(&logger.directives, Level::Error, ""));
411 assert!(enabled(&logger.directives, Level::Warn, ""));
412 assert!(enabled(&logger.directives, Level::Info, ""));
413 assert!(enabled(&logger.directives, Level::Debug, ""));
414 assert!(!enabled(&logger.directives, Level::Trace, ""));
415 }
416
417 #[test]
418 fn parse_default_bare_level_trace_lc() {
419 let logger = Builder::new().parse("trace").build();
420 assert!(enabled(&logger.directives, Level::Error, ""));
421 assert!(enabled(&logger.directives, Level::Warn, ""));
422 assert!(enabled(&logger.directives, Level::Info, ""));
423 assert!(enabled(&logger.directives, Level::Debug, ""));
424 assert!(enabled(&logger.directives, Level::Trace, ""));
425 }
426
427 #[test]
428 fn parse_default_bare_level_trace_uc() {
429 let logger = Builder::new().parse("TRACE").build();
430 assert!(enabled(&logger.directives, Level::Error, ""));
431 assert!(enabled(&logger.directives, Level::Warn, ""));
432 assert!(enabled(&logger.directives, Level::Info, ""));
433 assert!(enabled(&logger.directives, Level::Debug, ""));
434 assert!(enabled(&logger.directives, Level::Trace, ""));
435 }
436
437 #[test]
442 fn parse_default_bare_level_debug_mixed() {
443 {
444 let logger = Builder::new().parse("Debug").build();
445 assert!(enabled(&logger.directives, Level::Error, ""));
446 assert!(enabled(&logger.directives, Level::Warn, ""));
447 assert!(enabled(&logger.directives, Level::Info, ""));
448 assert!(enabled(&logger.directives, Level::Debug, ""));
449 assert!(!enabled(&logger.directives, Level::Trace, ""));
450 }
451 {
452 let logger = Builder::new().parse("debuG").build();
453 assert!(enabled(&logger.directives, Level::Error, ""));
454 assert!(enabled(&logger.directives, Level::Warn, ""));
455 assert!(enabled(&logger.directives, Level::Info, ""));
456 assert!(enabled(&logger.directives, Level::Debug, ""));
457 assert!(!enabled(&logger.directives, Level::Trace, ""));
458 }
459 {
460 let logger = Builder::new().parse("deBug").build();
461 assert!(enabled(&logger.directives, Level::Error, ""));
462 assert!(enabled(&logger.directives, Level::Warn, ""));
463 assert!(enabled(&logger.directives, Level::Info, ""));
464 assert!(enabled(&logger.directives, Level::Debug, ""));
465 assert!(!enabled(&logger.directives, Level::Trace, ""));
466 }
467 {
468 let logger = Builder::new().parse("DeBuG").build(); assert!(enabled(&logger.directives, Level::Error, ""));
470 assert!(enabled(&logger.directives, Level::Warn, ""));
471 assert!(enabled(&logger.directives, Level::Info, ""));
472 assert!(enabled(&logger.directives, Level::Debug, ""));
473 assert!(!enabled(&logger.directives, Level::Trace, ""));
474 }
475 }
476
477 #[test]
478 fn try_parse_valid_filter() {
479 let logger = Builder::new()
480 .try_parse("info,crate1::mod1=warn")
481 .expect("valid filter returned error")
482 .build();
483 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
484 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
485 }
486
487 #[test]
488 fn try_parse_invalid_filter() {
489 let error = Builder::new().try_parse("info,crate1=invalid").unwrap_err();
490 assert_data_eq!(
491 error,
492 str!["error parsing logger filter: invalid logging spec 'invalid'"]
493 );
494 }
495
496 #[test]
497 fn match_full_path() {
498 let logger = make_logger_filter(vec![
499 Directive {
500 name: Some("crate2".to_owned()),
501 level: LevelFilter::Info,
502 },
503 Directive {
504 name: Some("crate1::mod1".to_owned()),
505 level: LevelFilter::Warn,
506 },
507 ]);
508 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
509 assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1"));
510 assert!(enabled(&logger.directives, Level::Info, "crate2"));
511 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
512 }
513
514 #[test]
515 fn no_match() {
516 let logger = make_logger_filter(vec![
517 Directive {
518 name: Some("crate2".to_owned()),
519 level: LevelFilter::Info,
520 },
521 Directive {
522 name: Some("crate1::mod1".to_owned()),
523 level: LevelFilter::Warn,
524 },
525 ]);
526 assert!(!enabled(&logger.directives, Level::Warn, "crate3"));
527 }
528
529 #[test]
530 fn match_beginning() {
531 let logger = make_logger_filter(vec![
532 Directive {
533 name: Some("crate2".to_owned()),
534 level: LevelFilter::Info,
535 },
536 Directive {
537 name: Some("crate1::mod1".to_owned()),
538 level: LevelFilter::Warn,
539 },
540 ]);
541 assert!(enabled(&logger.directives, Level::Info, "crate2::mod1"));
542 }
543
544 #[test]
545 fn match_beginning_longest_match() {
546 let logger = make_logger_filter(vec![
547 Directive {
548 name: Some("crate2".to_owned()),
549 level: LevelFilter::Info,
550 },
551 Directive {
552 name: Some("crate2::mod".to_owned()),
553 level: LevelFilter::Debug,
554 },
555 Directive {
556 name: Some("crate1::mod1".to_owned()),
557 level: LevelFilter::Warn,
558 },
559 ]);
560 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
561 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
562 }
563
564 #[test]
565 fn match_default() {
566 let logger = make_logger_filter(vec![
567 Directive {
568 name: None,
569 level: LevelFilter::Info,
570 },
571 Directive {
572 name: Some("crate1::mod1".to_owned()),
573 level: LevelFilter::Warn,
574 },
575 ]);
576 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
577 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
578 }
579
580 #[test]
581 fn zero_level() {
582 let logger = make_logger_filter(vec![
583 Directive {
584 name: None,
585 level: LevelFilter::Info,
586 },
587 Directive {
588 name: Some("crate1::mod1".to_owned()),
589 level: LevelFilter::Off,
590 },
591 ]);
592 assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1"));
593 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
594 }
595}