Upgrade rust/crates/env_logger to 0.8.3

Test: make
Change-Id: Id07857de21e3d6dab1c3772e45b39466ef22984a
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 a1abfe9..a877979 100644
--- a/Android.bp
+++ b/Android.bp
@@ -112,5 +112,5 @@
 }
 
 // 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 @@
 """
 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 @@
   }
   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 @@
 ```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 @@
 }
 ```
 
-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 @@
 [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 @@
 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,14 +1,23 @@
-// 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_regexp_filter"
+    },
+    {
+      "name": "env_logger_device_test_src_lib"
     },
     {
       "name": "env_logger_device_test_tests_log-in-log"
     },
     {
-      "name": "env_logger_device_test_tests_regexp_filter"
+      "name": "env_logger_device_test_tests_init-twice-retains-filter"
+    },
+    {
+      "name": "libsqlite3-sys_device_test_src_lib"
     },
     {
       "name": "android_logger_device_test_src_lib"
@@ -18,15 +27,6 @@
     },
     {
       "name": "env_logger_device_test_tests_log_tls_dtors"
-    },
-    {
-      "name": "keystore2_test"
-    },
-    {
-      "name": "libsqlite3-sys_device_test_src_lib"
-    },
-    {
-      "name": "env_logger_device_test_src_lib"
     }
   ]
 }
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 @@
         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 @@
         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 @@
     }
 
     #[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 @@
     }
 
     #[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 @@
     }
 
     #[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 format_level: bool,
     pub format_indent: Option<usize>,
     pub custom_format: Option<FormatFn>,
+    pub format_suffix: &'static str,
     built: bool,
 }
 
@@ -155,6 +156,7 @@
             format_level: true,
             format_indent: Some(4),
             custom_format: None,
+            format_suffix: "\n",
             built: false,
         }
     }
@@ -187,6 +189,7 @@
                     level: built.format_level,
                     written_header_value: false,
                     indent: built.format_indent,
+                    suffix: built.format_suffix,
                     buf,
                 };
 
@@ -211,6 +214,7 @@
     written_header_value: bool,
     indent: Option<usize>,
     buf: &'a mut Formatter,
+    suffix: &'a str,
 }
 
 impl<'a> DefaultFormat<'a> {
@@ -319,7 +323,7 @@
     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 @@
                         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 @@
                     write!(wrapper, "{}", record.args())?;
                 }
 
-                writeln!(self.buf)?;
+                write!(self.buf, "{}", self.suffix)?;
 
                 Ok(())
             }
@@ -402,6 +412,7 @@
             level: true,
             written_header_value: false,
             indent: None,
+            suffix: "\n",
             buf: &mut f,
         });
 
@@ -422,6 +433,7 @@
             level: false,
             written_header_value: false,
             indent: None,
+            suffix: "\n",
             buf: &mut f,
         });
 
@@ -442,6 +454,7 @@
             level: true,
             written_header_value: false,
             indent: Some(4),
+            suffix: "\n",
             buf: &mut f,
         });
 
@@ -462,6 +475,7 @@
             level: true,
             written_header_value: false,
             indent: Some(0),
+            suffix: "\n",
             buf: &mut f,
         });
 
@@ -482,9 +496,52 @@
             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 @@
         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