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
188pub struct Filter {
196 directives: Vec<Directive>,
197 filter: Option<FilterOp>,
198}
199
200impl Filter {
201 pub fn filter(&self) -> LevelFilter {
218 self.directives
219 .iter()
220 .map(|d| d.level)
221 .max()
222 .unwrap_or(LevelFilter::Off)
223 }
224
225 pub fn matches(&self, record: &Record<'_>) -> bool {
227 if !self.enabled(record.metadata()) {
228 return false;
229 }
230
231 if let Some(filter) = self.filter.as_ref() {
232 if !filter.is_match(&record.args().to_string()) {
233 return false;
234 }
235 }
236
237 true
238 }
239
240 pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
242 let level = metadata.level();
243 let target = metadata.target();
244
245 enabled(&self.directives, level, target)
246 }
247}
248
249impl fmt::Debug for Filter {
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 f.debug_struct("Filter")
252 .field("filter", &self.filter)
253 .field("directives", &self.directives)
254 .finish()
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use log::{Level, LevelFilter};
261 use snapbox::{assert_data_eq, str};
262
263 use super::{enabled, Builder, Directive, Filter};
264
265 fn make_logger_filter(dirs: Vec<Directive>) -> Filter {
266 let mut logger = Builder::new().build();
267 logger.directives = dirs;
268 logger
269 }
270
271 #[test]
272 fn filter_info() {
273 let logger = Builder::new().filter(None, LevelFilter::Info).build();
274 assert!(enabled(&logger.directives, Level::Info, "crate1"));
275 assert!(!enabled(&logger.directives, Level::Debug, "crate1"));
276 }
277
278 #[test]
279 fn filter_beginning_longest_match() {
280 let logger = Builder::new()
281 .filter(Some("crate2"), LevelFilter::Info)
282 .filter(Some("crate2::mod"), LevelFilter::Debug)
283 .filter(Some("crate1::mod1"), LevelFilter::Warn)
284 .build();
285 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
286 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
287 }
288
289 #[test]
302 fn ensure_tests_cover_level_universe() {
303 let level_universe: Level = Level::Trace; match level_universe {
305 Level::Error | Level::Warn | Level::Info | Level::Debug | Level::Trace => (),
306 }
307 }
308
309 #[test]
310 fn parse_default() {
311 let logger = Builder::new().parse("info,crate1::mod1=warn").build();
312 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
313 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
314 }
315
316 #[test]
317 fn parse_default_bare_level_off_lc() {
318 let logger = Builder::new().parse("off").build();
319 assert!(!enabled(&logger.directives, Level::Error, ""));
320 assert!(!enabled(&logger.directives, Level::Warn, ""));
321 assert!(!enabled(&logger.directives, Level::Info, ""));
322 assert!(!enabled(&logger.directives, Level::Debug, ""));
323 assert!(!enabled(&logger.directives, Level::Trace, ""));
324 }
325
326 #[test]
327 fn parse_default_bare_level_off_uc() {
328 let logger = Builder::new().parse("OFF").build();
329 assert!(!enabled(&logger.directives, Level::Error, ""));
330 assert!(!enabled(&logger.directives, Level::Warn, ""));
331 assert!(!enabled(&logger.directives, Level::Info, ""));
332 assert!(!enabled(&logger.directives, Level::Debug, ""));
333 assert!(!enabled(&logger.directives, Level::Trace, ""));
334 }
335
336 #[test]
337 fn parse_default_bare_level_error_lc() {
338 let logger = Builder::new().parse("error").build();
339 assert!(enabled(&logger.directives, Level::Error, ""));
340 assert!(!enabled(&logger.directives, Level::Warn, ""));
341 assert!(!enabled(&logger.directives, Level::Info, ""));
342 assert!(!enabled(&logger.directives, Level::Debug, ""));
343 assert!(!enabled(&logger.directives, Level::Trace, ""));
344 }
345
346 #[test]
347 fn parse_default_bare_level_error_uc() {
348 let logger = Builder::new().parse("ERROR").build();
349 assert!(enabled(&logger.directives, Level::Error, ""));
350 assert!(!enabled(&logger.directives, Level::Warn, ""));
351 assert!(!enabled(&logger.directives, Level::Info, ""));
352 assert!(!enabled(&logger.directives, Level::Debug, ""));
353 assert!(!enabled(&logger.directives, Level::Trace, ""));
354 }
355
356 #[test]
357 fn parse_default_bare_level_warn_lc() {
358 let logger = Builder::new().parse("warn").build();
359 assert!(enabled(&logger.directives, Level::Error, ""));
360 assert!(enabled(&logger.directives, Level::Warn, ""));
361 assert!(!enabled(&logger.directives, Level::Info, ""));
362 assert!(!enabled(&logger.directives, Level::Debug, ""));
363 assert!(!enabled(&logger.directives, Level::Trace, ""));
364 }
365
366 #[test]
367 fn parse_default_bare_level_warn_uc() {
368 let logger = Builder::new().parse("WARN").build();
369 assert!(enabled(&logger.directives, Level::Error, ""));
370 assert!(enabled(&logger.directives, Level::Warn, ""));
371 assert!(!enabled(&logger.directives, Level::Info, ""));
372 assert!(!enabled(&logger.directives, Level::Debug, ""));
373 assert!(!enabled(&logger.directives, Level::Trace, ""));
374 }
375
376 #[test]
377 fn parse_default_bare_level_info_lc() {
378 let logger = Builder::new().parse("info").build();
379 assert!(enabled(&logger.directives, Level::Error, ""));
380 assert!(enabled(&logger.directives, Level::Warn, ""));
381 assert!(enabled(&logger.directives, Level::Info, ""));
382 assert!(!enabled(&logger.directives, Level::Debug, ""));
383 assert!(!enabled(&logger.directives, Level::Trace, ""));
384 }
385
386 #[test]
387 fn parse_default_bare_level_info_uc() {
388 let logger = Builder::new().parse("INFO").build();
389 assert!(enabled(&logger.directives, Level::Error, ""));
390 assert!(enabled(&logger.directives, Level::Warn, ""));
391 assert!(enabled(&logger.directives, Level::Info, ""));
392 assert!(!enabled(&logger.directives, Level::Debug, ""));
393 assert!(!enabled(&logger.directives, Level::Trace, ""));
394 }
395
396 #[test]
397 fn parse_default_bare_level_debug_lc() {
398 let logger = Builder::new().parse("debug").build();
399 assert!(enabled(&logger.directives, Level::Error, ""));
400 assert!(enabled(&logger.directives, Level::Warn, ""));
401 assert!(enabled(&logger.directives, Level::Info, ""));
402 assert!(enabled(&logger.directives, Level::Debug, ""));
403 assert!(!enabled(&logger.directives, Level::Trace, ""));
404 }
405
406 #[test]
407 fn parse_default_bare_level_debug_uc() {
408 let logger = Builder::new().parse("DEBUG").build();
409 assert!(enabled(&logger.directives, Level::Error, ""));
410 assert!(enabled(&logger.directives, Level::Warn, ""));
411 assert!(enabled(&logger.directives, Level::Info, ""));
412 assert!(enabled(&logger.directives, Level::Debug, ""));
413 assert!(!enabled(&logger.directives, Level::Trace, ""));
414 }
415
416 #[test]
417 fn parse_default_bare_level_trace_lc() {
418 let logger = Builder::new().parse("trace").build();
419 assert!(enabled(&logger.directives, Level::Error, ""));
420 assert!(enabled(&logger.directives, Level::Warn, ""));
421 assert!(enabled(&logger.directives, Level::Info, ""));
422 assert!(enabled(&logger.directives, Level::Debug, ""));
423 assert!(enabled(&logger.directives, Level::Trace, ""));
424 }
425
426 #[test]
427 fn parse_default_bare_level_trace_uc() {
428 let logger = Builder::new().parse("TRACE").build();
429 assert!(enabled(&logger.directives, Level::Error, ""));
430 assert!(enabled(&logger.directives, Level::Warn, ""));
431 assert!(enabled(&logger.directives, Level::Info, ""));
432 assert!(enabled(&logger.directives, Level::Debug, ""));
433 assert!(enabled(&logger.directives, Level::Trace, ""));
434 }
435
436 #[test]
441 fn parse_default_bare_level_debug_mixed() {
442 {
443 let logger = Builder::new().parse("Debug").build();
444 assert!(enabled(&logger.directives, Level::Error, ""));
445 assert!(enabled(&logger.directives, Level::Warn, ""));
446 assert!(enabled(&logger.directives, Level::Info, ""));
447 assert!(enabled(&logger.directives, Level::Debug, ""));
448 assert!(!enabled(&logger.directives, Level::Trace, ""));
449 }
450 {
451 let logger = Builder::new().parse("debuG").build();
452 assert!(enabled(&logger.directives, Level::Error, ""));
453 assert!(enabled(&logger.directives, Level::Warn, ""));
454 assert!(enabled(&logger.directives, Level::Info, ""));
455 assert!(enabled(&logger.directives, Level::Debug, ""));
456 assert!(!enabled(&logger.directives, Level::Trace, ""));
457 }
458 {
459 let logger = Builder::new().parse("deBug").build();
460 assert!(enabled(&logger.directives, Level::Error, ""));
461 assert!(enabled(&logger.directives, Level::Warn, ""));
462 assert!(enabled(&logger.directives, Level::Info, ""));
463 assert!(enabled(&logger.directives, Level::Debug, ""));
464 assert!(!enabled(&logger.directives, Level::Trace, ""));
465 }
466 {
467 let logger = Builder::new().parse("DeBuG").build(); assert!(enabled(&logger.directives, Level::Error, ""));
469 assert!(enabled(&logger.directives, Level::Warn, ""));
470 assert!(enabled(&logger.directives, Level::Info, ""));
471 assert!(enabled(&logger.directives, Level::Debug, ""));
472 assert!(!enabled(&logger.directives, Level::Trace, ""));
473 }
474 }
475
476 #[test]
477 fn try_parse_valid_filter() {
478 let logger = Builder::new()
479 .try_parse("info,crate1::mod1=warn")
480 .expect("valid filter returned error")
481 .build();
482 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
483 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
484 }
485
486 #[test]
487 fn try_parse_invalid_filter() {
488 let error = Builder::new().try_parse("info,crate1=invalid").unwrap_err();
489 assert_data_eq!(
490 error,
491 str!["error parsing logger filter: invalid logging spec 'invalid'"]
492 );
493 }
494
495 #[test]
496 fn match_full_path() {
497 let logger = make_logger_filter(vec![
498 Directive {
499 name: Some("crate2".to_owned()),
500 level: LevelFilter::Info,
501 },
502 Directive {
503 name: Some("crate1::mod1".to_owned()),
504 level: LevelFilter::Warn,
505 },
506 ]);
507 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
508 assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1"));
509 assert!(enabled(&logger.directives, Level::Info, "crate2"));
510 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
511 }
512
513 #[test]
514 fn no_match() {
515 let logger = make_logger_filter(vec![
516 Directive {
517 name: Some("crate2".to_owned()),
518 level: LevelFilter::Info,
519 },
520 Directive {
521 name: Some("crate1::mod1".to_owned()),
522 level: LevelFilter::Warn,
523 },
524 ]);
525 assert!(!enabled(&logger.directives, Level::Warn, "crate3"));
526 }
527
528 #[test]
529 fn match_beginning() {
530 let logger = make_logger_filter(vec![
531 Directive {
532 name: Some("crate2".to_owned()),
533 level: LevelFilter::Info,
534 },
535 Directive {
536 name: Some("crate1::mod1".to_owned()),
537 level: LevelFilter::Warn,
538 },
539 ]);
540 assert!(enabled(&logger.directives, Level::Info, "crate2::mod1"));
541 }
542
543 #[test]
544 fn match_beginning_longest_match() {
545 let logger = make_logger_filter(vec![
546 Directive {
547 name: Some("crate2".to_owned()),
548 level: LevelFilter::Info,
549 },
550 Directive {
551 name: Some("crate2::mod".to_owned()),
552 level: LevelFilter::Debug,
553 },
554 Directive {
555 name: Some("crate1::mod1".to_owned()),
556 level: LevelFilter::Warn,
557 },
558 ]);
559 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
560 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
561 }
562
563 #[test]
564 fn match_default() {
565 let logger = make_logger_filter(vec![
566 Directive {
567 name: None,
568 level: LevelFilter::Info,
569 },
570 Directive {
571 name: Some("crate1::mod1".to_owned()),
572 level: LevelFilter::Warn,
573 },
574 ]);
575 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
576 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
577 }
578
579 #[test]
580 fn zero_level() {
581 let logger = make_logger_filter(vec![
582 Directive {
583 name: None,
584 level: LevelFilter::Info,
585 },
586 Directive {
587 name: Some("crate1::mod1".to_owned()),
588 level: LevelFilter::Off,
589 },
590 ]);
591 assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1"));
592 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
593 }
594}