1use alloc::{borrow::ToOwned, string::ToString, vec::Vec};
2use core::{fmt, mem};
3
4use log::{LevelFilter, Metadata, Record};
5
6use crate::enabled;
7use crate::parse_spec;
8use crate::parser::ParseResult;
9use crate::Directive;
10use crate::FilterOp;
11use crate::ParseError;
12
13pub struct Builder {
36 directives: Vec<Directive>,
37 filter: Option<FilterOp>,
38 built: bool,
39}
40
41impl Builder {
42 pub fn new() -> Builder {
44 Builder {
45 directives: Vec::new(),
46 filter: None,
47 built: false,
48 }
49 }
50
51 #[cfg(feature = "std")]
53 pub fn from_env(env: &str) -> Builder {
54 let mut builder = Builder::new();
55
56 if let Ok(s) = std::env::var(env) {
57 builder.parse(&s);
58 }
59
60 builder
61 }
62
63 fn insert_directive(&mut self, mut directive: Directive) {
65 if let Some(pos) = self
66 .directives
67 .iter()
68 .position(|d| d.name == directive.name)
69 {
70 mem::swap(&mut self.directives[pos], &mut directive);
71 } else {
72 self.directives.push(directive);
73 }
74 }
75
76 pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self {
78 self.filter(Some(module), level)
79 }
80
81 pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self {
83 self.filter(None, level)
84 }
85
86 pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self {
91 self.insert_directive(Directive {
92 name: module.map(|s| s.to_owned()),
93 level,
94 });
95 self
96 }
97
98 #[cfg(feature = "std")]
104 pub fn parse(&mut self, filters: &str) -> &mut Self {
105 #![allow(clippy::print_stderr)] let ParseResult {
108 directives,
109 filter,
110 errors,
111 } = parse_spec(filters);
112
113 for error in errors {
114 { ::std::io::_eprint(format_args!("warning: {0}, ignoring it\n", error)); };eprintln!("warning: {error}, ignoring it");
115 }
116
117 self.filter = filter;
118
119 for directive in directives {
120 self.insert_directive(directive);
121 }
122 self
123 }
124
125 pub fn try_parse(&mut self, filters: &str) -> Result<&mut Self, ParseError> {
131 let (directives, filter) = parse_spec(filters).ok()?;
132
133 self.filter = filter;
134
135 for directive in directives {
136 self.insert_directive(directive);
137 }
138 Ok(self)
139 }
140
141 pub fn build(&mut self) -> Filter {
143 if !!self.built {
{
::core::panicking::panic_fmt(format_args!("attempt to re-use consumed builder"));
}
};assert!(!self.built, "attempt to re-use consumed builder");
144 self.built = true;
145
146 let mut directives = Vec::new();
147 if self.directives.is_empty() {
148 directives.push(Directive {
150 name: None,
151 level: LevelFilter::Error,
152 });
153 } else {
154 directives = mem::take(&mut self.directives);
156 directives.sort_by(|a, b| {
159 let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0);
160 let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0);
161 alen.cmp(&blen)
162 });
163 }
164
165 Filter {
166 directives: mem::take(&mut directives),
167 filter: mem::take(&mut self.filter),
168 }
169 }
170}
171
172impl Default for Builder {
173 fn default() -> Self {
174 Builder::new()
175 }
176}
177
178impl fmt::Debug for Builder {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 if self.built {
181 f.debug_struct("Filter").field("built", &true).finish()
182 } else {
183 f.debug_struct("Filter")
184 .field("filter", &self.filter)
185 .field("directives", &self.directives)
186 .finish()
187 }
188 }
189}
190
191#[derive(#[automatically_derived]
impl ::core::clone::Clone for Filter {
#[inline]
fn clone(&self) -> Filter {
Filter {
directives: ::core::clone::Clone::clone(&self.directives),
filter: ::core::clone::Clone::clone(&self.filter),
}
}
}Clone)]
199pub struct Filter {
200 directives: Vec<Directive>,
201 filter: Option<FilterOp>,
202}
203
204impl Filter {
205 pub fn filter(&self) -> LevelFilter {
222 self.directives
223 .iter()
224 .map(|d| d.level)
225 .max()
226 .unwrap_or(LevelFilter::Off)
227 }
228
229 pub fn matches(&self, record: &Record<'_>) -> bool {
231 if !self.enabled(record.metadata()) {
232 return false;
233 }
234
235 if let Some(filter) = self.filter.as_ref() {
236 if !filter.is_match(&record.args().to_string()) {
237 return false;
238 }
239 }
240
241 true
242 }
243
244 pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
246 let level = metadata.level();
247 let target = metadata.target();
248
249 enabled(&self.directives, level, target)
250 }
251}
252
253impl fmt::Debug for Filter {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 f.debug_struct("Filter")
256 .field("filter", &self.filter)
257 .field("directives", &self.directives)
258 .finish()
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use log::{Level, LevelFilter};
265 use snapbox::{assert_data_eq, str};
266
267 use super::{enabled, Builder, Directive, Filter};
268
269 fn make_logger_filter(dirs: Vec<Directive>) -> Filter {
270 let mut logger = Builder::new().build();
271 logger.directives = dirs;
272 logger
273 }
274
275 #[test]
276 fn filter_info() {
277 let logger = Builder::new().filter(None, LevelFilter::Info).build();
278 assert!(enabled(&logger.directives, Level::Info, "crate1"));
279 assert!(!enabled(&logger.directives, Level::Debug, "crate1"));
280 }
281
282 #[test]
283 fn filter_beginning_longest_match() {
284 let logger = Builder::new()
285 .filter(Some("crate2"), LevelFilter::Info)
286 .filter(Some("crate2::mod"), LevelFilter::Debug)
287 .filter(Some("crate1::mod1"), LevelFilter::Warn)
288 .build();
289 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
290 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
291 }
292
293 #[test]
306 fn ensure_tests_cover_level_universe() {
307 let level_universe: Level = Level::Trace; match level_universe {
309 Level::Error | Level::Warn | Level::Info | Level::Debug | Level::Trace => (),
310 }
311 }
312
313 #[test]
314 fn parse_default() {
315 let logger = Builder::new()
316 .try_parse("info,crate1::mod1=warn")
317 .unwrap()
318 .build();
319 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
320 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
321 }
322
323 #[test]
324 fn parse_default_bare_level_off_lc() {
325 let logger = Builder::new().try_parse("off").unwrap().build();
326 assert!(!enabled(&logger.directives, Level::Error, ""));
327 assert!(!enabled(&logger.directives, Level::Warn, ""));
328 assert!(!enabled(&logger.directives, Level::Info, ""));
329 assert!(!enabled(&logger.directives, Level::Debug, ""));
330 assert!(!enabled(&logger.directives, Level::Trace, ""));
331 }
332
333 #[test]
334 fn parse_default_bare_level_off_uc() {
335 let logger = Builder::new().try_parse("OFF").unwrap().build();
336 assert!(!enabled(&logger.directives, Level::Error, ""));
337 assert!(!enabled(&logger.directives, Level::Warn, ""));
338 assert!(!enabled(&logger.directives, Level::Info, ""));
339 assert!(!enabled(&logger.directives, Level::Debug, ""));
340 assert!(!enabled(&logger.directives, Level::Trace, ""));
341 }
342
343 #[test]
344 fn parse_default_bare_level_error_lc() {
345 let logger = Builder::new().try_parse("error").unwrap().build();
346 assert!(enabled(&logger.directives, Level::Error, ""));
347 assert!(!enabled(&logger.directives, Level::Warn, ""));
348 assert!(!enabled(&logger.directives, Level::Info, ""));
349 assert!(!enabled(&logger.directives, Level::Debug, ""));
350 assert!(!enabled(&logger.directives, Level::Trace, ""));
351 }
352
353 #[test]
354 fn parse_default_bare_level_error_uc() {
355 let logger = Builder::new().try_parse("ERROR").unwrap().build();
356 assert!(enabled(&logger.directives, Level::Error, ""));
357 assert!(!enabled(&logger.directives, Level::Warn, ""));
358 assert!(!enabled(&logger.directives, Level::Info, ""));
359 assert!(!enabled(&logger.directives, Level::Debug, ""));
360 assert!(!enabled(&logger.directives, Level::Trace, ""));
361 }
362
363 #[test]
364 fn parse_default_bare_level_warn_lc() {
365 let logger = Builder::new().try_parse("warn").unwrap().build();
366 assert!(enabled(&logger.directives, Level::Error, ""));
367 assert!(enabled(&logger.directives, Level::Warn, ""));
368 assert!(!enabled(&logger.directives, Level::Info, ""));
369 assert!(!enabled(&logger.directives, Level::Debug, ""));
370 assert!(!enabled(&logger.directives, Level::Trace, ""));
371 }
372
373 #[test]
374 fn parse_default_bare_level_warn_uc() {
375 let logger = Builder::new().try_parse("WARN").unwrap().build();
376 assert!(enabled(&logger.directives, Level::Error, ""));
377 assert!(enabled(&logger.directives, Level::Warn, ""));
378 assert!(!enabled(&logger.directives, Level::Info, ""));
379 assert!(!enabled(&logger.directives, Level::Debug, ""));
380 assert!(!enabled(&logger.directives, Level::Trace, ""));
381 }
382
383 #[test]
384 fn parse_default_bare_level_info_lc() {
385 let logger = Builder::new().try_parse("info").unwrap().build();
386 assert!(enabled(&logger.directives, Level::Error, ""));
387 assert!(enabled(&logger.directives, Level::Warn, ""));
388 assert!(enabled(&logger.directives, Level::Info, ""));
389 assert!(!enabled(&logger.directives, Level::Debug, ""));
390 assert!(!enabled(&logger.directives, Level::Trace, ""));
391 }
392
393 #[test]
394 fn parse_default_bare_level_info_uc() {
395 let logger = Builder::new().try_parse("INFO").unwrap().build();
396 assert!(enabled(&logger.directives, Level::Error, ""));
397 assert!(enabled(&logger.directives, Level::Warn, ""));
398 assert!(enabled(&logger.directives, Level::Info, ""));
399 assert!(!enabled(&logger.directives, Level::Debug, ""));
400 assert!(!enabled(&logger.directives, Level::Trace, ""));
401 }
402
403 #[test]
404 fn parse_default_bare_level_debug_lc() {
405 let logger = Builder::new().try_parse("debug").unwrap().build();
406 assert!(enabled(&logger.directives, Level::Error, ""));
407 assert!(enabled(&logger.directives, Level::Warn, ""));
408 assert!(enabled(&logger.directives, Level::Info, ""));
409 assert!(enabled(&logger.directives, Level::Debug, ""));
410 assert!(!enabled(&logger.directives, Level::Trace, ""));
411 }
412
413 #[test]
414 fn parse_default_bare_level_debug_uc() {
415 let logger = Builder::new().try_parse("DEBUG").unwrap().build();
416 assert!(enabled(&logger.directives, Level::Error, ""));
417 assert!(enabled(&logger.directives, Level::Warn, ""));
418 assert!(enabled(&logger.directives, Level::Info, ""));
419 assert!(enabled(&logger.directives, Level::Debug, ""));
420 assert!(!enabled(&logger.directives, Level::Trace, ""));
421 }
422
423 #[test]
424 fn parse_default_bare_level_trace_lc() {
425 let logger = Builder::new().try_parse("trace").unwrap().build();
426 assert!(enabled(&logger.directives, Level::Error, ""));
427 assert!(enabled(&logger.directives, Level::Warn, ""));
428 assert!(enabled(&logger.directives, Level::Info, ""));
429 assert!(enabled(&logger.directives, Level::Debug, ""));
430 assert!(enabled(&logger.directives, Level::Trace, ""));
431 }
432
433 #[test]
434 fn parse_default_bare_level_trace_uc() {
435 let logger = Builder::new().try_parse("TRACE").unwrap().build();
436 assert!(enabled(&logger.directives, Level::Error, ""));
437 assert!(enabled(&logger.directives, Level::Warn, ""));
438 assert!(enabled(&logger.directives, Level::Info, ""));
439 assert!(enabled(&logger.directives, Level::Debug, ""));
440 assert!(enabled(&logger.directives, Level::Trace, ""));
441 }
442
443 #[test]
448 fn parse_default_bare_level_debug_mixed() {
449 {
450 let logger = Builder::new().try_parse("Debug").unwrap().build();
451 assert!(enabled(&logger.directives, Level::Error, ""));
452 assert!(enabled(&logger.directives, Level::Warn, ""));
453 assert!(enabled(&logger.directives, Level::Info, ""));
454 assert!(enabled(&logger.directives, Level::Debug, ""));
455 assert!(!enabled(&logger.directives, Level::Trace, ""));
456 }
457 {
458 let logger = Builder::new().try_parse("debuG").unwrap().build();
459 assert!(enabled(&logger.directives, Level::Error, ""));
460 assert!(enabled(&logger.directives, Level::Warn, ""));
461 assert!(enabled(&logger.directives, Level::Info, ""));
462 assert!(enabled(&logger.directives, Level::Debug, ""));
463 assert!(!enabled(&logger.directives, Level::Trace, ""));
464 }
465 {
466 let logger = Builder::new().try_parse("deBug").unwrap().build();
467 assert!(enabled(&logger.directives, Level::Error, ""));
468 assert!(enabled(&logger.directives, Level::Warn, ""));
469 assert!(enabled(&logger.directives, Level::Info, ""));
470 assert!(enabled(&logger.directives, Level::Debug, ""));
471 assert!(!enabled(&logger.directives, Level::Trace, ""));
472 }
473 {
474 let logger = Builder::new().try_parse("DeBuG").unwrap().build(); assert!(enabled(&logger.directives, Level::Error, ""));
476 assert!(enabled(&logger.directives, Level::Warn, ""));
477 assert!(enabled(&logger.directives, Level::Info, ""));
478 assert!(enabled(&logger.directives, Level::Debug, ""));
479 assert!(!enabled(&logger.directives, Level::Trace, ""));
480 }
481 }
482
483 #[test]
484 fn try_parse_valid_filter() {
485 let logger = Builder::new()
486 .try_parse("info,crate1::mod1=warn")
487 .expect("valid filter returned error")
488 .build();
489 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
490 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
491 }
492
493 #[test]
494 fn try_parse_invalid_filter() {
495 let error = Builder::new().try_parse("info,crate1=invalid").unwrap_err();
496 assert_data_eq!(
497 error,
498 str!["error parsing logger filter: invalid logging spec 'invalid'"]
499 );
500 }
501
502 #[test]
503 fn match_full_path() {
504 let logger = make_logger_filter(vec![
505 Directive {
506 name: Some("crate2".to_owned()),
507 level: LevelFilter::Info,
508 },
509 Directive {
510 name: Some("crate1::mod1".to_owned()),
511 level: LevelFilter::Warn,
512 },
513 ]);
514 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
515 assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1"));
516 assert!(enabled(&logger.directives, Level::Info, "crate2"));
517 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
518 }
519
520 #[test]
521 fn no_match() {
522 let logger = make_logger_filter(vec![
523 Directive {
524 name: Some("crate2".to_owned()),
525 level: LevelFilter::Info,
526 },
527 Directive {
528 name: Some("crate1::mod1".to_owned()),
529 level: LevelFilter::Warn,
530 },
531 ]);
532 assert!(!enabled(&logger.directives, Level::Warn, "crate3"));
533 }
534
535 #[test]
536 fn match_beginning() {
537 let logger = make_logger_filter(vec![
538 Directive {
539 name: Some("crate2".to_owned()),
540 level: LevelFilter::Info,
541 },
542 Directive {
543 name: Some("crate1::mod1".to_owned()),
544 level: LevelFilter::Warn,
545 },
546 ]);
547 assert!(enabled(&logger.directives, Level::Info, "crate2::mod1"));
548 }
549
550 #[test]
551 fn match_beginning_longest_match() {
552 let logger = make_logger_filter(vec![
553 Directive {
554 name: Some("crate2".to_owned()),
555 level: LevelFilter::Info,
556 },
557 Directive {
558 name: Some("crate2::mod".to_owned()),
559 level: LevelFilter::Debug,
560 },
561 Directive {
562 name: Some("crate1::mod1".to_owned()),
563 level: LevelFilter::Warn,
564 },
565 ]);
566 assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
567 assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
568 }
569
570 #[test]
571 fn match_default() {
572 let logger = make_logger_filter(vec![
573 Directive {
574 name: None,
575 level: LevelFilter::Info,
576 },
577 Directive {
578 name: Some("crate1::mod1".to_owned()),
579 level: LevelFilter::Warn,
580 },
581 ]);
582 assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
583 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
584 }
585
586 #[test]
587 fn zero_level() {
588 let logger = make_logger_filter(vec![
589 Directive {
590 name: None,
591 level: LevelFilter::Info,
592 },
593 Directive {
594 name: Some("crate1::mod1".to_owned()),
595 level: LevelFilter::Off,
596 },
597 ]);
598 assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1"));
599 assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
600 }
601}