Skip to content

Commit a36b72d

Browse files
authored
Merge pull request #189 from salewski/ads/parse-spec-raw-level-tests
add unit tests, docs related to available log level names
2 parents 6e8b7f5 + 5595a4d commit a36b72d

File tree

3 files changed

+293
-14
lines changed

3 files changed

+293
-14
lines changed

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,44 @@ fn main() {
3939
}
4040
```
4141

42-
Then when running the executable, specify a value for the `RUST_LOG`
42+
Then when running the executable, specify a value for the **`RUST_LOG`**
4343
environment variable that corresponds with the log messages you want to show.
4444

4545
```bash
4646
$ RUST_LOG=info ./main
4747
[2018-11-03T06:09:06Z INFO default] starting up
4848
```
4949

50+
The letter case is not significant for the logging level names; e.g., `debug`,
51+
`DEBUG`, and `dEbuG` all represent the same logging level. Therefore, the
52+
previous example could also have been written this way, specifying the log
53+
level as `INFO` rather than as `info`:
54+
55+
```bash
56+
$ RUST_LOG=INFO ./main
57+
[2018-11-03T06:09:06Z INFO default] starting up
58+
```
59+
60+
So which form should you use? For consistency, our convention is to use lower
61+
case names. Where our docs do use other forms, they do so in the context of
62+
specific examples, so you won't be surprised if you see similar usage in the
63+
wild.
64+
65+
The log levels that may be specified correspond to the [`log::Level`][level-enum]
66+
enum from the `log` crate. They are:
67+
68+
* `error`
69+
* `warn`
70+
* `info`
71+
* `debug`
72+
* `trace`
73+
74+
[level-enum]: https://docs.rs/log/latest/log/enum.Level.html "log::Level (docs.rs)"
75+
76+
There is also a pseudo logging level, `off`, which may be specified to disable
77+
all logging for a given module or for the entire application. As with the
78+
logging levels, the letter case is not significant.
79+
5080
`env_logger` can be configured in other ways besides an environment variable. See [the examples](https://github.com/env-logger-rs/env_logger/tree/master/examples) for more approaches.
5181

5282
### In tests

src/filter/mod.rs

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,13 +395,193 @@ mod tests {
395395
assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
396396
}
397397

398+
// Some of our tests are only correct or complete when they cover the full
399+
// universe of variants for log::Level. In the unlikely event that a new
400+
// variant is added in the future, this test will detect the scenario and
401+
// alert us to the need to review and update the tests. In such a
402+
// situation, this test will fail to compile, and the error message will
403+
// look something like this:
404+
//
405+
// error[E0004]: non-exhaustive patterns: `NewVariant` not covered
406+
// --> src/filter/mod.rs:413:15
407+
// |
408+
// 413 | match level_universe {
409+
// | ^^^^^^^^^^^^^^ pattern `NewVariant` not covered
410+
#[test]
411+
fn ensure_tests_cover_level_universe() {
412+
let level_universe: Level = Level::Trace; // use of trace variant is arbitrary
413+
match level_universe {
414+
Level::Error | Level::Warn | Level::Info | Level::Debug | Level::Trace => (),
415+
}
416+
}
417+
398418
#[test]
399419
fn parse_default() {
400420
let logger = Builder::new().parse("info,crate1::mod1=warn").build();
401421
assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
402422
assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
403423
}
404424

425+
#[test]
426+
fn parse_default_bare_level_off_lc() {
427+
let logger = Builder::new().parse("off").build();
428+
assert!(!enabled(&logger.directives, Level::Error, ""));
429+
assert!(!enabled(&logger.directives, Level::Warn, ""));
430+
assert!(!enabled(&logger.directives, Level::Info, ""));
431+
assert!(!enabled(&logger.directives, Level::Debug, ""));
432+
assert!(!enabled(&logger.directives, Level::Trace, ""));
433+
}
434+
435+
#[test]
436+
fn parse_default_bare_level_off_uc() {
437+
let logger = Builder::new().parse("OFF").build();
438+
assert!(!enabled(&logger.directives, Level::Error, ""));
439+
assert!(!enabled(&logger.directives, Level::Warn, ""));
440+
assert!(!enabled(&logger.directives, Level::Info, ""));
441+
assert!(!enabled(&logger.directives, Level::Debug, ""));
442+
assert!(!enabled(&logger.directives, Level::Trace, ""));
443+
}
444+
445+
#[test]
446+
fn parse_default_bare_level_error_lc() {
447+
let logger = Builder::new().parse("error").build();
448+
assert!(enabled(&logger.directives, Level::Error, ""));
449+
assert!(!enabled(&logger.directives, Level::Warn, ""));
450+
assert!(!enabled(&logger.directives, Level::Info, ""));
451+
assert!(!enabled(&logger.directives, Level::Debug, ""));
452+
assert!(!enabled(&logger.directives, Level::Trace, ""));
453+
}
454+
455+
#[test]
456+
fn parse_default_bare_level_error_uc() {
457+
let logger = Builder::new().parse("ERROR").build();
458+
assert!(enabled(&logger.directives, Level::Error, ""));
459+
assert!(!enabled(&logger.directives, Level::Warn, ""));
460+
assert!(!enabled(&logger.directives, Level::Info, ""));
461+
assert!(!enabled(&logger.directives, Level::Debug, ""));
462+
assert!(!enabled(&logger.directives, Level::Trace, ""));
463+
}
464+
465+
#[test]
466+
fn parse_default_bare_level_warn_lc() {
467+
let logger = Builder::new().parse("warn").build();
468+
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+
#[test]
476+
fn parse_default_bare_level_warn_uc() {
477+
let logger = Builder::new().parse("WARN").build();
478+
assert!(enabled(&logger.directives, Level::Error, ""));
479+
assert!(enabled(&logger.directives, Level::Warn, ""));
480+
assert!(!enabled(&logger.directives, Level::Info, ""));
481+
assert!(!enabled(&logger.directives, Level::Debug, ""));
482+
assert!(!enabled(&logger.directives, Level::Trace, ""));
483+
}
484+
485+
#[test]
486+
fn parse_default_bare_level_info_lc() {
487+
let logger = Builder::new().parse("info").build();
488+
assert!(enabled(&logger.directives, Level::Error, ""));
489+
assert!(enabled(&logger.directives, Level::Warn, ""));
490+
assert!(enabled(&logger.directives, Level::Info, ""));
491+
assert!(!enabled(&logger.directives, Level::Debug, ""));
492+
assert!(!enabled(&logger.directives, Level::Trace, ""));
493+
}
494+
495+
#[test]
496+
fn parse_default_bare_level_info_uc() {
497+
let logger = Builder::new().parse("INFO").build();
498+
assert!(enabled(&logger.directives, Level::Error, ""));
499+
assert!(enabled(&logger.directives, Level::Warn, ""));
500+
assert!(enabled(&logger.directives, Level::Info, ""));
501+
assert!(!enabled(&logger.directives, Level::Debug, ""));
502+
assert!(!enabled(&logger.directives, Level::Trace, ""));
503+
}
504+
505+
#[test]
506+
fn parse_default_bare_level_debug_lc() {
507+
let logger = Builder::new().parse("debug").build();
508+
assert!(enabled(&logger.directives, Level::Error, ""));
509+
assert!(enabled(&logger.directives, Level::Warn, ""));
510+
assert!(enabled(&logger.directives, Level::Info, ""));
511+
assert!(enabled(&logger.directives, Level::Debug, ""));
512+
assert!(!enabled(&logger.directives, Level::Trace, ""));
513+
}
514+
515+
#[test]
516+
fn parse_default_bare_level_debug_uc() {
517+
let logger = Builder::new().parse("DEBUG").build();
518+
assert!(enabled(&logger.directives, Level::Error, ""));
519+
assert!(enabled(&logger.directives, Level::Warn, ""));
520+
assert!(enabled(&logger.directives, Level::Info, ""));
521+
assert!(enabled(&logger.directives, Level::Debug, ""));
522+
assert!(!enabled(&logger.directives, Level::Trace, ""));
523+
}
524+
525+
#[test]
526+
fn parse_default_bare_level_trace_lc() {
527+
let logger = Builder::new().parse("trace").build();
528+
assert!(enabled(&logger.directives, Level::Error, ""));
529+
assert!(enabled(&logger.directives, Level::Warn, ""));
530+
assert!(enabled(&logger.directives, Level::Info, ""));
531+
assert!(enabled(&logger.directives, Level::Debug, ""));
532+
assert!(enabled(&logger.directives, Level::Trace, ""));
533+
}
534+
535+
#[test]
536+
fn parse_default_bare_level_trace_uc() {
537+
let logger = Builder::new().parse("TRACE").build();
538+
assert!(enabled(&logger.directives, Level::Error, ""));
539+
assert!(enabled(&logger.directives, Level::Warn, ""));
540+
assert!(enabled(&logger.directives, Level::Info, ""));
541+
assert!(enabled(&logger.directives, Level::Debug, ""));
542+
assert!(enabled(&logger.directives, Level::Trace, ""));
543+
}
544+
545+
// In practice, the desired log level is typically specified by a token
546+
// that is either all lowercase (e.g., 'trace') or all uppercase (.e.g,
547+
// 'TRACE'), but this tests serves as a reminder that
548+
// log::Level::from_str() ignores all case variants.
549+
#[test]
550+
fn parse_default_bare_level_debug_mixed() {
551+
{
552+
let logger = Builder::new().parse("Debug").build();
553+
assert!(enabled(&logger.directives, Level::Error, ""));
554+
assert!(enabled(&logger.directives, Level::Warn, ""));
555+
assert!(enabled(&logger.directives, Level::Info, ""));
556+
assert!(enabled(&logger.directives, Level::Debug, ""));
557+
assert!(!enabled(&logger.directives, Level::Trace, ""));
558+
}
559+
{
560+
let logger = Builder::new().parse("debuG").build();
561+
assert!(enabled(&logger.directives, Level::Error, ""));
562+
assert!(enabled(&logger.directives, Level::Warn, ""));
563+
assert!(enabled(&logger.directives, Level::Info, ""));
564+
assert!(enabled(&logger.directives, Level::Debug, ""));
565+
assert!(!enabled(&logger.directives, Level::Trace, ""));
566+
}
567+
{
568+
let logger = Builder::new().parse("deBug").build();
569+
assert!(enabled(&logger.directives, Level::Error, ""));
570+
assert!(enabled(&logger.directives, Level::Warn, ""));
571+
assert!(enabled(&logger.directives, Level::Info, ""));
572+
assert!(enabled(&logger.directives, Level::Debug, ""));
573+
assert!(!enabled(&logger.directives, Level::Trace, ""));
574+
}
575+
{
576+
let logger = Builder::new().parse("DeBuG").build(); // LaTeX flavor!
577+
assert!(enabled(&logger.directives, Level::Error, ""));
578+
assert!(enabled(&logger.directives, Level::Warn, ""));
579+
assert!(enabled(&logger.directives, Level::Info, ""));
580+
assert!(enabled(&logger.directives, Level::Debug, ""));
581+
assert!(!enabled(&logger.directives, Level::Trace, ""));
582+
}
583+
}
584+
405585
#[test]
406586
fn match_full_path() {
407587
let logger = make_logger_filter(vec![
@@ -569,6 +749,36 @@ mod tests {
569749
assert!(filter.is_none());
570750
}
571751

752+
#[test]
753+
fn parse_spec_global_bare_warn_lc() {
754+
// test parse_spec with no crate, in isolation, all lowercase
755+
let (dirs, filter) = parse_spec("warn");
756+
assert_eq!(dirs.len(), 1);
757+
assert_eq!(dirs[0].name, None);
758+
assert_eq!(dirs[0].level, LevelFilter::Warn);
759+
assert!(filter.is_none());
760+
}
761+
762+
#[test]
763+
fn parse_spec_global_bare_warn_uc() {
764+
// test parse_spec with no crate, in isolation, all uppercase
765+
let (dirs, filter) = parse_spec("WARN");
766+
assert_eq!(dirs.len(), 1);
767+
assert_eq!(dirs[0].name, None);
768+
assert_eq!(dirs[0].level, LevelFilter::Warn);
769+
assert!(filter.is_none());
770+
}
771+
772+
#[test]
773+
fn parse_spec_global_bare_warn_mixed() {
774+
// test parse_spec with no crate, in isolation, mixed case
775+
let (dirs, filter) = parse_spec("wArN");
776+
assert_eq!(dirs.len(), 1);
777+
assert_eq!(dirs[0].name, None);
778+
assert_eq!(dirs[0].level, LevelFilter::Warn);
779+
assert!(filter.is_none());
780+
}
781+
572782
#[test]
573783
fn parse_spec_valid_filter() {
574784
let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug/abc");

src/lib.rs

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! A simple logger configured via environment variables which writes
12-
//! to stdout or stderr, for use with the logging facade exposed by the
13-
//! [`log` crate][log-crate-url].
11+
//! A simple logger that can be configured via environment variables, for use
12+
//! with the logging facade exposed by the [`log` crate][log-crate-url].
13+
//!
14+
//! Despite having "env" in its name, **`env_logger`** can also be configured by
15+
//! other means besides environment variables. See [the examples][gh-repo-examples]
16+
//! in the source repository for more approaches.
17+
//!
18+
//! By default, `env_logger` writes logs to `stderr`, but can be configured to
19+
//! instead write them to `stdout`.
1420
//!
1521
//! ## Example
1622
//!
@@ -83,11 +89,12 @@
8389
//!
8490
//! ## Enabling logging
8591
//!
86-
//! Log levels are controlled on a per-module basis, and by default all logging
87-
//! is disabled except for `error!`. Logging is controlled via the `RUST_LOG`
88-
//! environment variable. The value of this environment variable is a
89-
//! comma-separated list of logging directives. A logging directive is of the
90-
//! form:
92+
//! Log levels are controlled on a per-module basis, and **by default all
93+
//! logging is disabled except for the `error` level**.
94+
//!
95+
//! Logging is controlled via the **`RUST_LOG`** environment variable. The
96+
//! value of this environment variable is a comma-separated list of *logging
97+
//! directives*. A logging directive is of the form:
9198
//!
9299
//! ```text
93100
//! path::to::module=level
@@ -99,21 +106,51 @@
99106
//! Furthermore, this path is a prefix-search, so all modules nested in the
100107
//! specified module will also have logging enabled.
101108
//!
102-
//! The actual `level` is optional to specify. If omitted, all logging will
103-
//! be enabled. If specified, it must be one of the strings `debug`, `error`,
104-
//! `info`, `warn`, or `trace`.
109+
//! When providing the crate name or a module path, explicitly specifying the
110+
//! log level is optional. If omitted, all logging for the item (and its
111+
//! children) will be enabled.
112+
//!
113+
//! The names of the log levels that may be specified correspond to the
114+
//! variations of the [`log::Level`][level-enum] enum from the `log`
115+
//! crate. They are:
116+
//!
117+
//! * `error`
118+
//! * `warn`
119+
//! * `info`
120+
//! * `debug`
121+
//! * `trace`
122+
//!
123+
//! There is also a pseudo logging level, `off`, which may be specified to
124+
//! disable all logging for a given module or for the entire application. As
125+
//! with the logging levels, the letter case is not significant[^fn-off].
126+
//!
127+
//! [^fn-off]: Similar to the universe of log level names, the `off` pseudo
128+
//! log level feature is also provided by the underlying `log` crate.
129+
//!
130+
//! The letter case is not significant for the logging level names; e.g.,
131+
//! `debug`, `DEBUG`, and `dEbuG` all represent the same logging level. For
132+
//! consistency, our convention is to use the lower case names. Where our docs
133+
//! do use other forms, they do so in the context of specific examples, so you
134+
//! won't be surprised if you see similar usage in the wild.
105135
//!
106136
//! As the log level for a module is optional, the module to enable logging for
107-
//! is also optional. If only a `level` is provided, then the global log
108-
//! level for all modules is set to this value.
137+
//! is also optional. **If only a level is provided, then the global log
138+
//! level for all modules is set to this value.**
109139
//!
110140
//! Some examples of valid values of `RUST_LOG` are:
111141
//!
112142
//! * `hello` turns on all logging for the 'hello' module
143+
//! * `trace` turns on all logging for the application, regardless of its name
144+
//! * `TRACE` turns on all logging for the application, regardless of its name (same as previous)
113145
//! * `info` turns on all info logging
146+
//! * `INFO` turns on all info logging (same as previous)
114147
//! * `hello=debug` turns on debug logging for 'hello'
148+
//! * `hello=DEBUG` turns on debug logging for 'hello' (same as previous)
115149
//! * `hello,std::option` turns on hello, and std's option logging
116150
//! * `error,hello=warn` turn on global error logging and also warn for hello
151+
//! * `error,hello=off`` turn on global error logging, but turn off logging for hello
152+
//! * `off` turns off all logging for the application
153+
//! * `OFF` turns off all logging for the application (same as previous)
117154
//!
118155
//! ## Filtering results
119156
//!
@@ -223,6 +260,8 @@
223260
//! env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
224261
//! ```
225262
//!
263+
//! [gh-repo-examples]: https://github.com/env-logger-rs/env_logger/tree/master/examples
264+
//! [level-enum]: https://docs.rs/log/latest/log/enum.Level.html
226265
//! [log-crate-url]: https://docs.rs/log/
227266
//! [`Builder`]: struct.Builder.html
228267
//! [`Builder::is_test`]: struct.Builder.html#method.is_test

0 commit comments

Comments
 (0)