aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiƩbaud Weksteen <tweek@google.com>2021-03-04 08:17:29 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-03-04 08:17:29 +0000
commit85bd36e3462182ff95e9bbcfe85f1b89bd6085e0 (patch)
tree445137be149a627423611e1bc736fe55a624e276
parent168e17506cce243aed6dc55c185870f7130b48f9 (diff)
parentfec76ba12bc74bee46acebf2ec6ff242690f9fe0 (diff)
downloadenv_logger-85bd36e3462182ff95e9bbcfe85f1b89bd6085e0.tar.gz
Merge "Upgrade rust/crates/env_logger to 0.8.3"
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml114
-rw-r--r--.github/workflows/docs.yml40
-rw-r--r--Android.bp4
-rw-r--r--Cargo.toml3
-rw-r--r--Cargo.toml.orig3
-rw-r--r--METADATA10
-rw-r--r--README.md37
-rw-r--r--TEST_MAPPING20
-rw-r--r--examples/custom_default_format.rs40
-rw-r--r--examples/custom_format.rs54
-rw-r--r--examples/custom_logger.rs62
-rw-r--r--examples/default.rs38
-rw-r--r--examples/direct_logger.rs39
-rw-r--r--examples/filters_from_code.rs20
-rw-r--r--examples/in_tests.rs54
-rw-r--r--examples/syslog_friendly_format.rs24
-rw-r--r--rust-toolchain1
-rw-r--r--src/filter/mod.rs261
-rw-r--r--src/fmt/mod.rs63
-rw-r--r--src/lib.rs77
21 files changed, 435 insertions, 531 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 7e09207..8b186b2 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "0f53c8dd5bf65b80d1fdb8ea0befd848f120c631"
+ "sha1": "67adcba945148ef3bc1a867832f1422779d626cc"
}
}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index d2e8979..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,114 +0,0 @@
-name: Continuous Integration
-
-on:
- pull_request:
- paths:
- - "**.rs"
- - "Cargo.toml"
- - "Cargo.lock"
-
-jobs:
- fmt:
- name: Source formatting check
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: nightly
- override: true
- components: rustfmt
-
- - name: Check formatting
- uses: actions-rs/cargo@v1
- with:
- command: fmt
- args: -- --check
-
- check:
- name: Compilation check
- runs-on: ubuntu-latest
- strategy:
- fail-fast: true
- matrix:
- rust:
- - stable
- - beta
- - nightly
- - 1.41.0
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: ${{ matrix.rust }}
- override: true
-
- - name: Run cargo check
- uses: actions-rs/cargo@v1
- with:
- command: check
-
- clippy:
- name: Lint check
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- components: clippy
-
- - name: Run lints
- uses: actions-rs/cargo@v1
- with:
- command: clippy
- args: -- -D warnings
-
- ci-crate:
- name: CI crate check
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
-
- - name: Run ci crate
- uses: actions-rs/cargo@v1
- with:
- command: run
- args: -p ci
-
- crate-example:
- name: Crate example check
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
-
- - name: Run crate example
- uses: actions-rs/cargo@v1
- with:
- command: run
- args: --example default
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
deleted file mode 100644
index 4b6110b..0000000
--- a/.github/workflows/docs.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: Continuous Integration - Docs
-
-on:
- push:
- branches:
- - master
- paths:
- - "**.rs"
- - "Cargo.toml"
- - "Cargo.lock"
- workflow_dispatch:
-
-jobs:
- docs:
- name: Generate crate documentation
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: nightly
- override: true
-
- - name: Generate documentation
- uses: actions-rs/cargo@v1
- env:
- RUSTDOCFLAGS: "--enable-index-page -Zunstable-options"
- with:
- command: doc
- args: --no-deps
-
- - name: Deploy documentation
- uses: peaceiris/actions-gh-pages@v3
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: ./target/doc
diff --git a/Android.bp b/Android.bp
index 20af602..8eaf57e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -152,5 +152,5 @@ rust_library {
}
// dependent_library ["feature_list"]
-// cfg-if-0.1.10
-// log-0.4.13 "std"
+// cfg-if-1.0.0
+// log-0.4.14 "std"
diff --git a/Cargo.toml b/Cargo.toml
index f84ed82..bd952f8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,8 +13,9 @@
[package]
edition = "2018"
name = "env_logger"
-version = "0.8.2"
+version = "0.8.3"
authors = ["The Rust Project Developers"]
+include = ["src/**/*", "tests", "LICENSE-*", "README.md", "CHANGELOG.md"]
description = "A logging implementation for `log` which is configured via an environment\nvariable.\n"
documentation = "https://docs.rs/env_logger"
readme = "README.md"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 449deaa..42fa5ae 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
[package]
name = "env_logger"
edition = "2018"
-version = "0.8.2" # remember to update html_root_url
+version = "0.8.3"
authors = ["The Rust Project Developers"]
license = "MIT/Apache-2.0"
readme = "README.md"
@@ -13,6 +13,7 @@ variable.
"""
categories = ["development-tools::debugging"]
keywords = ["logging", "log", "logger"]
+include = ["src/**/*", "tests", "LICENSE-*", "README.md", "CHANGELOG.md"]
[workspace]
members = [
diff --git a/METADATA b/METADATA
index a22f130..b1e7cb0 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/env_logger/env_logger-0.8.2.crate"
+ value: "https://static.crates.io/crates/env_logger/env_logger-0.8.3.crate"
}
- version: "0.8.2"
+ version: "0.8.3"
license_type: NOTICE
last_upgrade_date {
- year: 2020
- month: 11
- day: 18
+ year: 2021
+ month: 2
+ day: 11
}
}
diff --git a/README.md b/README.md
index 9f01ed4..329d1be 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
# env_logger
-[![Build Status](https://travis-ci.org/env-logger-rs/env_logger.svg?branch=master)](https://travis-ci.org/env-logger-rs/env_logger)
[![Maintenance](https://img.shields.io/badge/maintenance-actively%20maintained-brightgreen.svg)](https://github.com/env-logger-rs/env_logger)
[![crates.io](https://img.shields.io/crates/v/env_logger.svg)](https://crates.io/crates/env_logger)
[![Documentation](https://docs.rs/env_logger/badge.svg)](https://docs.rs/env_logger)
@@ -22,7 +21,7 @@ It must be added along with `log` to the project dependencies:
```toml
[dependencies]
log = "0.4.0"
-env_logger = "0.8.2"
+env_logger = "0.8.3"
```
`env_logger` must be initialized as early as possible in the project. After it's initialized, you can use the `log` macros to do actual logging.
@@ -40,7 +39,7 @@ fn main() {
}
```
-Then when running the executable, specify a value for the `RUST_LOG`
+Then when running the executable, specify a value for the **`RUST_LOG`**
environment variable that corresponds with the log messages you want to show.
```bash
@@ -48,6 +47,36 @@ $ RUST_LOG=info ./main
[2018-11-03T06:09:06Z INFO default] starting up
```
+The letter case is not significant for the logging level names; e.g., `debug`,
+`DEBUG`, and `dEbuG` all represent the same logging level. Therefore, the
+previous example could also have been written this way, specifying the log
+level as `INFO` rather than as `info`:
+
+```bash
+$ RUST_LOG=INFO ./main
+[2018-11-03T06:09:06Z INFO default] starting up
+```
+
+So which form should you use? For consistency, our convention is to use lower
+case names. Where our docs do use other forms, they do so in the context of
+specific examples, so you won't be surprised if you see similar usage in the
+wild.
+
+The log levels that may be specified correspond to the [`log::Level`][level-enum]
+enum from the `log` crate. They are:
+
+ * `error`
+ * `warn`
+ * `info`
+ * `debug`
+ * `trace`
+
+[level-enum]: https://docs.rs/log/latest/log/enum.Level.html "log::Level (docs.rs)"
+
+There is also a pseudo logging level, `off`, which may be specified to disable
+all logging for a given module or for the entire application. As with the
+logging levels, the letter case is not significant.
+
`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.
### In tests
@@ -59,7 +88,7 @@ Tests can use the `env_logger` crate to see log messages generated during that t
log = "0.4.0"
[dev-dependencies]
-env_logger = "0.8.2"
+env_logger = "0.8.3"
```
```rust
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 5ab713d..15e6776 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,32 +1,32 @@
-// Generated by cargo2android.py for tests that depend on this crate.
+// Generated by update_crate_tests.py for tests that depend on this crate.
{
"presubmit": [
{
- "name": "env_logger_device_test_tests_init-twice-retains-filter"
+ "name": "keystore2_test"
},
{
- "name": "env_logger_device_test_tests_log-in-log"
+ "name": "env_logger_device_test_tests_regexp_filter"
},
{
- "name": "env_logger_device_test_tests_regexp_filter"
+ "name": "env_logger_device_test_src_lib"
},
{
- "name": "android_logger_device_test_src_lib"
+ "name": "env_logger_device_test_tests_log-in-log"
},
{
- "name": "keystore2_selinux_test"
+ "name": "env_logger_device_test_tests_init-twice-retains-filter"
},
{
- "name": "env_logger_device_test_tests_log_tls_dtors"
+ "name": "libsqlite3-sys_device_test_src_lib"
},
{
- "name": "keystore2_test"
+ "name": "android_logger_device_test_src_lib"
},
{
- "name": "libsqlite3-sys_device_test_src_lib"
+ "name": "keystore2_selinux_test"
},
{
- "name": "env_logger_device_test_src_lib"
+ "name": "env_logger_device_test_tests_log_tls_dtors"
}
]
}
diff --git a/examples/custom_default_format.rs b/examples/custom_default_format.rs
deleted file mode 100644
index b04eb60..0000000
--- a/examples/custom_default_format.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-/*!
-Disabling parts of the default format.
-
-Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
-
-```no_run,shell
-$ export MY_LOG_LEVEL='info'
-```
-
-Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors
-or `auto` to enable them:
-
-```no_run,shell
-$ export MY_LOG_STYLE=never
-```
-
-If you want to control the logging output completely, see the `custom_logger` example.
-*/
-
-#[macro_use]
-extern crate log;
-
-use env_logger::{Builder, Env};
-
-fn init_logger() {
- let env = Env::default()
- .filter("MY_LOG_LEVEL")
- .write_style("MY_LOG_STYLE");
-
- Builder::from_env(env)
- .format_level(false)
- .format_timestamp_nanos()
- .init();
-}
-
-fn main() {
- init_logger();
-
- info!("a log from `MyLogger`");
-}
diff --git a/examples/custom_format.rs b/examples/custom_format.rs
deleted file mode 100644
index d8585a5..0000000
--- a/examples/custom_format.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-/*!
-Changing the default logging format.
-
-Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
-
-```no_run,shell
-$ export MY_LOG_LEVEL='info'
-```
-
-Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors
-or `auto` to enable them:
-
-```no_run,shell
-$ export MY_LOG_STYLE=never
-```
-
-If you want to control the logging output completely, see the `custom_logger` example.
-*/
-
-#[cfg(all(feature = "termcolor", feature = "humantime"))]
-fn main() {
- use env_logger::{fmt::Color, Builder, Env};
-
- use std::io::Write;
-
- fn init_logger() {
- let env = Env::default()
- .filter("MY_LOG_LEVEL")
- .write_style("MY_LOG_STYLE");
-
- Builder::from_env(env)
- .format(|buf, record| {
- let mut style = buf.style();
- style.set_bg(Color::Yellow).set_bold(true);
-
- let timestamp = buf.timestamp();
-
- writeln!(
- buf,
- "My formatted log ({}): {}",
- timestamp,
- style.value(record.args())
- )
- })
- .init();
- }
-
- init_logger();
-
- log::info!("a log from `MyLogger`");
-}
-
-#[cfg(not(all(feature = "termcolor", feature = "humantime")))]
-fn main() {}
diff --git a/examples/custom_logger.rs b/examples/custom_logger.rs
deleted file mode 100644
index 3d4dc5b..0000000
--- a/examples/custom_logger.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-/*!
-Using `env_logger` to drive a custom logger.
-
-Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
-
-```no_run,shell
-$ export MY_LOG_LEVEL='info'
-```
-
-If you only want to change the way logs are formatted, look at the `custom_format` example.
-*/
-
-#[macro_use]
-extern crate log;
-
-use env_logger::filter::{Builder, Filter};
-
-use log::{Log, Metadata, Record, SetLoggerError};
-
-const FILTER_ENV: &'static str = "MY_LOG_LEVEL";
-
-struct MyLogger {
- inner: Filter,
-}
-
-impl MyLogger {
- fn new() -> MyLogger {
- let mut builder = Builder::from_env(FILTER_ENV);
-
- MyLogger {
- inner: builder.build(),
- }
- }
-
- fn init() -> Result<(), SetLoggerError> {
- let logger = Self::new();
-
- log::set_max_level(logger.inner.filter());
- log::set_boxed_logger(Box::new(logger))
- }
-}
-
-impl Log for MyLogger {
- fn enabled(&self, metadata: &Metadata) -> bool {
- self.inner.enabled(metadata)
- }
-
- fn log(&self, record: &Record) {
- // Check if the record is matched by the logger before logging
- if self.inner.matches(record) {
- println!("{} - {}", record.level(), record.args());
- }
- }
-
- fn flush(&self) {}
-}
-
-fn main() {
- MyLogger::init().unwrap();
-
- info!("a log from `MyLogger`");
-}
diff --git a/examples/default.rs b/examples/default.rs
deleted file mode 100644
index 67bb030..0000000
--- a/examples/default.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*!
-Using `env_logger`.
-
-Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
-
-```no_run,shell
-$ export MY_LOG_LEVEL='info'
-```
-
-Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors
-or `auto` to enable them:
-
-```no_run,shell
-$ export MY_LOG_STYLE=never
-```
-*/
-
-#[macro_use]
-extern crate log;
-
-use env_logger::Env;
-
-fn main() {
- // The `Env` lets us tweak what the environment
- // variables to read are and what the default
- // value is if they're missing
- let env = Env::default()
- .filter_or("MY_LOG_LEVEL", "trace")
- .write_style_or("MY_LOG_STYLE", "always");
-
- env_logger::init_from_env(env);
-
- trace!("some trace log");
- debug!("some debug log");
- info!("some information log");
- warn!("some warning log");
- error!("some error log");
-}
diff --git a/examples/direct_logger.rs b/examples/direct_logger.rs
deleted file mode 100644
index 4d7f39d..0000000
--- a/examples/direct_logger.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*!
-Using `env_logger::Logger` and the `log::Log` trait directly.
-
-This example doesn't rely on environment variables, or having a static logger installed.
-*/
-
-use env_logger::{Builder, WriteStyle};
-
-use log::{Level, LevelFilter, Log, MetadataBuilder, Record};
-
-fn record() -> Record<'static> {
- let error_metadata = MetadataBuilder::new()
- .target("myApp")
- .level(Level::Error)
- .build();
-
- Record::builder()
- .metadata(error_metadata)
- .args(format_args!("Error!"))
- .line(Some(433))
- .file(Some("app.rs"))
- .module_path(Some("server"))
- .build()
-}
-
-fn main() {
- let stylish_logger = Builder::new()
- .filter(None, LevelFilter::Error)
- .write_style(WriteStyle::Always)
- .build();
-
- let unstylish_logger = Builder::new()
- .filter(None, LevelFilter::Error)
- .write_style(WriteStyle::Never)
- .build();
-
- stylish_logger.log(&record());
- unstylish_logger.log(&record());
-}
diff --git a/examples/filters_from_code.rs b/examples/filters_from_code.rs
deleted file mode 100644
index c877a44..0000000
--- a/examples/filters_from_code.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-/*!
-Specify logging filters in code instead of using an environment variable.
-*/
-
-#[macro_use]
-extern crate log;
-
-use env_logger::Builder;
-
-use log::LevelFilter;
-
-fn main() {
- Builder::new().filter_level(LevelFilter::max()).init();
-
- trace!("some trace log");
- debug!("some debug log");
- info!("some information log");
- warn!("some warning log");
- error!("some error log");
-}
diff --git a/examples/in_tests.rs b/examples/in_tests.rs
deleted file mode 100644
index c4487cc..0000000
--- a/examples/in_tests.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-/*!
-Using `env_logger` in tests.
-
-Log events will be captured by `cargo` and only printed if the test fails.
-You can run this example by calling:
-
-```text
-cargo test --example in_tests
-```
-
-You should see the `it_does_not_work` test fail and include its log output.
-*/
-
-#[cfg_attr(test, macro_use)]
-extern crate log;
-
-fn main() {}
-
-#[cfg(test)]
-mod tests {
- fn init_logger() {
- let _ = env_logger::builder()
- // Include all events in tests
- .filter_level(log::LevelFilter::max())
- // Ensure events are captured by `cargo test`
- .is_test(true)
- // Ignore errors initializing the logger if tests race to configure it
- .try_init();
- }
-
- #[test]
- fn it_works() {
- init_logger();
-
- let a = 1;
- let b = 2;
-
- debug!("checking whether {} + {} = 3", a, b);
-
- assert_eq!(3, a + b);
- }
-
- #[test]
- fn it_does_not_work() {
- init_logger();
-
- let a = 1;
- let b = 2;
-
- debug!("checking whether {} + {} = 6", a, b);
-
- assert_eq!(6, a + b);
- }
-}
diff --git a/examples/syslog_friendly_format.rs b/examples/syslog_friendly_format.rs
deleted file mode 100644
index 9809ab3..0000000
--- a/examples/syslog_friendly_format.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use std::io::Write;
-
-fn main() {
- match std::env::var("RUST_LOG_STYLE") {
- Ok(s) if s == "SYSTEMD" => env_logger::builder()
- .format(|buf, record| {
- writeln!(
- buf,
- "<{}>{}: {}",
- match record.level() {
- log::Level::Error => 3,
- log::Level::Warn => 4,
- log::Level::Info => 6,
- log::Level::Debug => 7,
- log::Level::Trace => 7,
- },
- record.target(),
- record.args()
- )
- })
- .init(),
- _ => env_logger::init(),
- };
-}
diff --git a/rust-toolchain b/rust-toolchain
deleted file mode 100644
index 033080c..0000000
--- a/rust-toolchain
+++ /dev/null
@@ -1 +0,0 @@
-1.41.0
diff --git a/src/filter/mod.rs b/src/filter/mod.rs
index ba81302..8f7787f 100644
--- a/src/filter/mod.rs
+++ b/src/filter/mod.rs
@@ -299,7 +299,7 @@ fn parse_spec(spec: &str) -> (Vec<Directive>, Option<inner::Filter>) {
return (dirs, None);
}
if let Some(m) = mods {
- for s in m.split(',') {
+ for s in m.split(',').map(|ss| ss.trim()) {
if s.is_empty() {
continue;
}
@@ -395,6 +395,26 @@ mod tests {
assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
}
+ // Some of our tests are only correct or complete when they cover the full
+ // universe of variants for log::Level. In the unlikely event that a new
+ // variant is added in the future, this test will detect the scenario and
+ // alert us to the need to review and update the tests. In such a
+ // situation, this test will fail to compile, and the error message will
+ // look something like this:
+ //
+ // error[E0004]: non-exhaustive patterns: `NewVariant` not covered
+ // --> src/filter/mod.rs:413:15
+ // |
+ // 413 | match level_universe {
+ // | ^^^^^^^^^^^^^^ pattern `NewVariant` not covered
+ #[test]
+ fn ensure_tests_cover_level_universe() {
+ let level_universe: Level = Level::Trace; // use of trace variant is arbitrary
+ match level_universe {
+ Level::Error | Level::Warn | Level::Info | Level::Debug | Level::Trace => (),
+ }
+ }
+
#[test]
fn parse_default() {
let logger = Builder::new().parse("info,crate1::mod1=warn").build();
@@ -403,6 +423,166 @@ mod tests {
}
#[test]
+ fn parse_default_bare_level_off_lc() {
+ let logger = Builder::new().parse("off").build();
+ assert!(!enabled(&logger.directives, Level::Error, ""));
+ assert!(!enabled(&logger.directives, Level::Warn, ""));
+ assert!(!enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_off_uc() {
+ let logger = Builder::new().parse("OFF").build();
+ assert!(!enabled(&logger.directives, Level::Error, ""));
+ assert!(!enabled(&logger.directives, Level::Warn, ""));
+ assert!(!enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_error_lc() {
+ let logger = Builder::new().parse("error").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(!enabled(&logger.directives, Level::Warn, ""));
+ assert!(!enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_error_uc() {
+ let logger = Builder::new().parse("ERROR").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(!enabled(&logger.directives, Level::Warn, ""));
+ assert!(!enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_warn_lc() {
+ let logger = Builder::new().parse("warn").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(!enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_warn_uc() {
+ let logger = Builder::new().parse("WARN").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(!enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_info_lc() {
+ let logger = Builder::new().parse("info").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_info_uc() {
+ let logger = Builder::new().parse("INFO").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(!enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_debug_lc() {
+ let logger = Builder::new().parse("debug").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_debug_uc() {
+ let logger = Builder::new().parse("DEBUG").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_trace_lc() {
+ let logger = Builder::new().parse("trace").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ #[test]
+ fn parse_default_bare_level_trace_uc() {
+ let logger = Builder::new().parse("TRACE").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(enabled(&logger.directives, Level::Trace, ""));
+ }
+
+ // In practice, the desired log level is typically specified by a token
+ // that is either all lowercase (e.g., 'trace') or all uppercase (.e.g,
+ // 'TRACE'), but this tests serves as a reminder that
+ // log::Level::from_str() ignores all case variants.
+ #[test]
+ fn parse_default_bare_level_debug_mixed() {
+ {
+ let logger = Builder::new().parse("Debug").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+ {
+ let logger = Builder::new().parse("debuG").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+ {
+ let logger = Builder::new().parse("deBug").build();
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+ {
+ let logger = Builder::new().parse("DeBuG").build(); // LaTeX flavor!
+ assert!(enabled(&logger.directives, Level::Error, ""));
+ assert!(enabled(&logger.directives, Level::Warn, ""));
+ assert!(enabled(&logger.directives, Level::Info, ""));
+ assert!(enabled(&logger.directives, Level::Debug, ""));
+ assert!(!enabled(&logger.directives, Level::Trace, ""));
+ }
+ }
+
+ #[test]
fn match_full_path() {
let logger = make_logger_filter(vec![
Directive {
@@ -558,6 +738,55 @@ mod tests {
}
#[test]
+ fn parse_spec_empty_level_isolated() {
+ // test parse_spec with "" as log level (and the entire spec str)
+ let (dirs, filter) = parse_spec(""); // should be ignored
+ assert_eq!(dirs.len(), 0);
+ assert!(filter.is_none());
+ }
+
+ #[test]
+ fn parse_spec_blank_level_isolated() {
+ // test parse_spec with a white-space-only string specified as the log
+ // level (and the entire spec str)
+ let (dirs, filter) = parse_spec(" "); // should be ignored
+ assert_eq!(dirs.len(), 0);
+ assert!(filter.is_none());
+ }
+
+ #[test]
+ fn parse_spec_blank_level_isolated_comma_only() {
+ // The spec should contain zero or more comma-separated string slices,
+ // so a comma-only string should be interpretted as two empty strings
+ // (which should both be treated as invalid, so ignored).
+ let (dirs, filter) = parse_spec(","); // should be ignored
+ assert_eq!(dirs.len(), 0);
+ assert!(filter.is_none());
+ }
+
+ #[test]
+ fn parse_spec_blank_level_isolated_comma_blank() {
+ // The spec should contain zero or more comma-separated string slices,
+ // so this bogus spec should be interpretted as containing one empty
+ // string and one blank string. Both should both be treated as
+ // invalid, so ignored.
+ let (dirs, filter) = parse_spec(", "); // should be ignored
+ assert_eq!(dirs.len(), 0);
+ assert!(filter.is_none());
+ }
+
+ #[test]
+ fn parse_spec_blank_level_isolated_blank_comma() {
+ // The spec should contain zero or more comma-separated string slices,
+ // so this bogus spec should be interpretted as containing one blank
+ // string and one empty string. Both should both be treated as
+ // invalid, so ignored.
+ let (dirs, filter) = parse_spec(" ,"); // should be ignored
+ assert_eq!(dirs.len(), 0);
+ assert!(filter.is_none());
+ }
+
+ #[test]
fn parse_spec_global() {
// test parse_spec with no crate
let (dirs, filter) = parse_spec("warn,crate2=debug");
@@ -570,6 +799,36 @@ mod tests {
}
#[test]
+ fn parse_spec_global_bare_warn_lc() {
+ // test parse_spec with no crate, in isolation, all lowercase
+ let (dirs, filter) = parse_spec("warn");
+ assert_eq!(dirs.len(), 1);
+ assert_eq!(dirs[0].name, None);
+ assert_eq!(dirs[0].level, LevelFilter::Warn);
+ assert!(filter.is_none());
+ }
+
+ #[test]
+ fn parse_spec_global_bare_warn_uc() {
+ // test parse_spec with no crate, in isolation, all uppercase
+ let (dirs, filter) = parse_spec("WARN");
+ assert_eq!(dirs.len(), 1);
+ assert_eq!(dirs[0].name, None);
+ assert_eq!(dirs[0].level, LevelFilter::Warn);
+ assert!(filter.is_none());
+ }
+
+ #[test]
+ fn parse_spec_global_bare_warn_mixed() {
+ // test parse_spec with no crate, in isolation, mixed case
+ let (dirs, filter) = parse_spec("wArN");
+ assert_eq!(dirs.len(), 1);
+ assert_eq!(dirs[0].name, None);
+ assert_eq!(dirs[0].level, LevelFilter::Warn);
+ assert!(filter.is_none());
+ }
+
+ #[test]
fn parse_spec_valid_filter() {
let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug/abc");
assert_eq!(dirs.len(), 3);
diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs
index 558c4d9..3c4fee0 100644
--- a/src/fmt/mod.rs
+++ b/src/fmt/mod.rs
@@ -144,6 +144,7 @@ pub(crate) struct Builder {
pub format_level: bool,
pub format_indent: Option<usize>,
pub custom_format: Option<FormatFn>,
+ pub format_suffix: &'static str,
built: bool,
}
@@ -155,6 +156,7 @@ impl Default for Builder {
format_level: true,
format_indent: Some(4),
custom_format: None,
+ format_suffix: "\n",
built: false,
}
}
@@ -187,6 +189,7 @@ impl Builder {
level: built.format_level,
written_header_value: false,
indent: built.format_indent,
+ suffix: built.format_suffix,
buf,
};
@@ -211,6 +214,7 @@ struct DefaultFormat<'a> {
written_header_value: bool,
indent: Option<usize>,
buf: &'a mut Formatter,
+ suffix: &'a str,
}
impl<'a> DefaultFormat<'a> {
@@ -319,7 +323,7 @@ impl<'a> DefaultFormat<'a> {
fn write_args(&mut self, record: &Record) -> io::Result<()> {
match self.indent {
// Fast path for no indentation
- None => writeln!(self.buf, "{}", record.args()),
+ None => write!(self.buf, "{}{}", record.args(), self.suffix),
Some(indent_count) => {
// Create a wrapper around the buffer only if we have to actually indent the message
@@ -334,7 +338,13 @@ impl<'a> DefaultFormat<'a> {
let mut first = true;
for chunk in buf.split(|&x| x == b'\n') {
if !first {
- write!(self.fmt.buf, "\n{:width$}", "", width = self.indent_count)?;
+ write!(
+ self.fmt.buf,
+ "{}{:width$}",
+ self.fmt.suffix,
+ "",
+ width = self.indent_count
+ )?;
}
self.fmt.buf.write_all(chunk)?;
first = false;
@@ -357,7 +367,7 @@ impl<'a> DefaultFormat<'a> {
write!(wrapper, "{}", record.args())?;
}
- writeln!(self.buf)?;
+ write!(self.buf, "{}", self.suffix)?;
Ok(())
}
@@ -402,6 +412,7 @@ mod tests {
level: true,
written_header_value: false,
indent: None,
+ suffix: "\n",
buf: &mut f,
});
@@ -422,6 +433,7 @@ mod tests {
level: false,
written_header_value: false,
indent: None,
+ suffix: "\n",
buf: &mut f,
});
@@ -442,6 +454,7 @@ mod tests {
level: true,
written_header_value: false,
indent: Some(4),
+ suffix: "\n",
buf: &mut f,
});
@@ -462,6 +475,7 @@ mod tests {
level: true,
written_header_value: false,
indent: Some(0),
+ suffix: "\n",
buf: &mut f,
});
@@ -482,9 +496,52 @@ mod tests {
level: false,
written_header_value: false,
indent: Some(4),
+ suffix: "\n",
buf: &mut f,
});
assert_eq!("log\n message\n", written);
}
+
+ #[test]
+ fn format_suffix() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: false,
+ level: false,
+ written_header_value: false,
+ indent: None,
+ suffix: "\n\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("log\nmessage\n\n", written);
+ }
+
+ #[test]
+ fn format_suffix_with_indent() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: false,
+ level: false,
+ written_header_value: false,
+ indent: Some(4),
+ suffix: "\n\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("log\n\n message\n\n", written);
+ }
}
diff --git a/src/lib.rs b/src/lib.rs
index 36f30c0..31ea7c3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,9 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! A simple logger configured via environment variables which writes
-//! to stdout or stderr, for use with the logging facade exposed by the
-//! [`log` crate][log-crate-url].
+//! A simple logger that can be configured via environment variables, for use
+//! with the logging facade exposed by the [`log` crate][log-crate-url].
+//!
+//! Despite having "env" in its name, **`env_logger`** can also be configured by
+//! other means besides environment variables. See [the examples][gh-repo-examples]
+//! in the source repository for more approaches.
+//!
+//! By default, `env_logger` writes logs to `stderr`, but can be configured to
+//! instead write them to `stdout`.
//!
//! ## Example
//!
@@ -83,11 +89,12 @@
//!
//! ## Enabling logging
//!
-//! Log levels are controlled on a per-module basis, and by default all logging
-//! is disabled except for `error!`. Logging is controlled via the `RUST_LOG`
-//! environment variable. The value of this environment variable is a
-//! comma-separated list of logging directives. A logging directive is of the
-//! form:
+//! Log levels are controlled on a per-module basis, and **by default all
+//! logging is disabled except for the `error` level**.
+//!
+//! Logging is controlled via the **`RUST_LOG`** environment variable. The
+//! value of this environment variable is a comma-separated list of *logging
+//! directives*. A logging directive is of the form:
//!
//! ```text
//! path::to::module=level
@@ -99,21 +106,51 @@
//! Furthermore, this path is a prefix-search, so all modules nested in the
//! specified module will also have logging enabled.
//!
-//! The actual `level` is optional to specify. If omitted, all logging will
-//! be enabled. If specified, it must be one of the strings `debug`, `error`,
-//! `info`, `warn`, or `trace`.
+//! When providing the crate name or a module path, explicitly specifying the
+//! log level is optional. If omitted, all logging for the item (and its
+//! children) will be enabled.
+//!
+//! The names of the log levels that may be specified correspond to the
+//! variations of the [`log::Level`][level-enum] enum from the `log`
+//! crate. They are:
+//!
+//! * `error`
+//! * `warn`
+//! * `info`
+//! * `debug`
+//! * `trace`
+//!
+//! There is also a pseudo logging level, `off`, which may be specified to
+//! disable all logging for a given module or for the entire application. As
+//! with the logging levels, the letter case is not significant[^fn-off].
+//!
+//! [^fn-off]: Similar to the universe of log level names, the `off` pseudo
+//! log level feature is also provided by the underlying `log` crate.
+//!
+//! The letter case is not significant for the logging level names; e.g.,
+//! `debug`, `DEBUG`, and `dEbuG` all represent the same logging level. For
+//! consistency, our convention is to use the lower case names. Where our docs
+//! do use other forms, they do so in the context of specific examples, so you
+//! won't be surprised if you see similar usage in the wild.
//!
//! As the log level for a module is optional, the module to enable logging for
-//! is also optional. If only a `level` is provided, then the global log
-//! level for all modules is set to this value.
+//! is also optional. **If only a level is provided, then the global log
+//! level for all modules is set to this value.**
//!
//! Some examples of valid values of `RUST_LOG` are:
//!
//! * `hello` turns on all logging for the 'hello' module
+//! * `trace` turns on all logging for the application, regardless of its name
+//! * `TRACE` turns on all logging for the application, regardless of its name (same as previous)
//! * `info` turns on all info logging
+//! * `INFO` turns on all info logging (same as previous)
//! * `hello=debug` turns on debug logging for 'hello'
+//! * `hello=DEBUG` turns on debug logging for 'hello' (same as previous)
//! * `hello,std::option` turns on hello, and std's option logging
//! * `error,hello=warn` turn on global error logging and also warn for hello
+//! * `error,hello=off` turn on global error logging, but turn off logging for hello
+//! * `off` turns off all logging for the application
+//! * `OFF` turns off all logging for the application (same as previous)
//!
//! ## Filtering results
//!
@@ -223,6 +260,8 @@
//! env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
//! ```
//!
+//! [gh-repo-examples]: https://github.com/env-logger-rs/env_logger/tree/master/examples
+//! [level-enum]: https://docs.rs/log/latest/log/enum.Level.html
//! [log-crate-url]: https://docs.rs/log/
//! [`Builder`]: struct.Builder.html
//! [`Builder::is_test`]: struct.Builder.html#method.is_test
@@ -231,15 +270,13 @@
#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "https://www.rust-lang.org/static/images/favicon.ico",
- html_root_url = "https://docs.rs/env_logger/0.8.2"
+ html_favicon_url = "https://www.rust-lang.org/static/images/favicon.ico"
)]
-#![cfg_attr(test, deny(warnings))]
// When compiled for the rustc compiler itself we want to make sure that this is
// an unstable crate
#![cfg_attr(rustbuild, feature(staged_api, rustc_private))]
#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))]
-#![deny(missing_debug_implementations, missing_docs, warnings)]
+#![deny(missing_debug_implementations, missing_docs)]
use std::{borrow::Cow, cell::RefCell, env, io};
@@ -594,6 +631,12 @@ impl Builder {
self.format_timestamp(Some(fmt::TimestampPrecision::Nanos))
}
+ /// Configures the end of line suffix.
+ pub fn format_suffix(&mut self, suffix: &'static str) -> &mut Self {
+ self.format.format_suffix = suffix;
+ self
+ }
+
/// Adds a directive to the filter for a specific module.
///
/// # Examples