Import env_logger-0.7.1

Change-Id: I26daac7e33bfb65bcb57e1eee8b61f76e5e84dea
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..787e6a8
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "68a170094649c48c6ce7471acf3a33fd2799541c"
+  }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a01f99d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+target/
+Cargo.lock
+.emacs*
+*~
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..af8f18d
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,24 @@
+language: rust
+sudo: false
+rust:
+  - 1.31.0
+  - stable
+  - beta
+  - nightly
+before_script:
+  - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
+script:
+  - if [ "${MINIMAL_VERSIONS}" = "y" ]; then cargo update -Z minimal-versions; fi
+  - cargo run -p ci
+  - cargo run --example default
+after_success:
+  - travis-cargo --only nightly doc-upload
+
+matrix:
+  include:
+    - rust: nightly
+      env: MINIMAL_VERSIONS=y
+
+notifications:
+  email:
+on_success: never
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..f849eef
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+Changes to this crate are tracked via [GitHub Releases][releases].
+
+[releases]: https://github.com/sebasmagri/env_logger/releases
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..c34a1ee
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,62 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "env_logger"
+version = "0.7.1"
+authors = ["The Rust Project Developers"]
+description = "A logging implementation for `log` which is configured via an environment\nvariable.\n"
+documentation = "https://docs.rs/env_logger"
+readme = "README.md"
+keywords = ["logging", "log", "logger"]
+categories = ["development-tools::debugging"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/sebasmagri/env_logger/"
+
+[[test]]
+name = "regexp_filter"
+harness = false
+
+[[test]]
+name = "log-in-log"
+harness = false
+
+[[test]]
+name = "log_tls_dtors"
+harness = false
+
+[[test]]
+name = "init-twice-retains-filter"
+harness = false
+[dependencies.atty]
+version = "0.2.5"
+optional = true
+
+[dependencies.humantime]
+version = "1.3"
+optional = true
+
+[dependencies.log]
+version = "0.4.8"
+features = ["std"]
+
+[dependencies.regex]
+version = "1.0.3"
+optional = true
+
+[dependencies.termcolor]
+version = "1.0.2"
+optional = true
+
+[features]
+default = ["termcolor", "atty", "humantime", "regex"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..148543b
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,46 @@
+[package]
+name = "env_logger"
+edition = "2018"
+version = "0.7.1" # remember to update html_root_url
+authors = ["The Rust Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/sebasmagri/env_logger/"
+documentation = "https://docs.rs/env_logger"
+description = """
+A logging implementation for `log` which is configured via an environment
+variable.
+"""
+categories = ["development-tools::debugging"]
+keywords = ["logging", "log", "logger"]
+
+[workspace]
+members = [
+    "ci"
+]
+
+[dependencies]
+log = { version = "0.4.8", features = ["std"] }
+regex = { version = "1.0.3", optional = true }
+termcolor = { version = "1.0.2", optional = true }
+humantime = { version = "1.3", optional = true }
+atty = { version = "0.2.5", optional = true }
+
+[[test]]
+name = "regexp_filter"
+harness = false
+
+[[test]]
+name = "log-in-log"
+harness = false
+
+[[test]]
+name = "log_tls_dtors"
+harness = false
+
+[[test]]
+name = "init-twice-retains-filter"
+harness = false
+
+[features]
+default = ["termcolor", "atty", "humantime", "regex"]
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..39d4bdb
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..34e4194
--- /dev/null
+++ b/README.md
@@ -0,0 +1,150 @@
+env_logger [![Build Status](https://travis-ci.org/sebasmagri/env_logger.svg?branch=master)](https://travis-ci.org/sebasmagri/env_logger) [![Maintenance](https://img.shields.io/badge/maintenance-actively%20maintained-brightgreen.svg)](https://github.com/sebasmagri/env_logger) [![crates.io](https://img.shields.io/crates/v/env_logger.svg)](https://crates.io/crates/env_logger) [![Documentation](https://img.shields.io/badge/docs-current-blue.svg)](https://docs.rs/env_logger)
+==========
+
+Implements a logger that can be configured via environment variables.
+
+## Usage
+
+### In libraries
+
+`env_logger` makes sense when used in executables (binary projects). Libraries should use the [`log`](https://doc.rust-lang.org/log) crate instead.
+
+### In executables
+
+It must be added along with `log` to the project dependencies:
+
+```toml
+[dependencies]
+log = "0.4.0"
+env_logger = "0.7.1"
+```
+
+`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.
+
+```rust
+#[macro_use]
+extern crate log;
+
+fn main() {
+    env_logger::init();
+
+    info!("starting up");
+
+    // ...
+}
+```
+
+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
+$ RUST_LOG=info ./main
+[2018-11-03T06:09:06Z INFO  default] starting up
+```
+
+`env_logger` can be configured in other ways besides an environment variable. See [the examples](https://github.com/sebasmagri/env_logger/tree/master/examples) for more approaches.
+
+### In tests
+
+Tests can use the `env_logger` crate to see log messages generated during that test:
+
+```toml
+[dependencies]
+log = "0.4.0"
+
+[dev-dependencies]
+env_logger = "0.7.1"
+```
+
+```rust
+#[macro_use]
+extern crate log;
+
+fn add_one(num: i32) -> i32 {
+    info!("add_one called with {}", num);
+    num + 1
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn init() {
+        let _ = env_logger::builder().is_test(true).try_init();
+    }
+
+    #[test]
+    fn it_adds_one() {
+        init();
+
+        info!("can log from the test too");
+        assert_eq!(3, add_one(2));
+    }
+
+    #[test]
+    fn it_handles_negative_numbers() {
+        init();
+
+        info!("logging from another test");
+        assert_eq!(-7, add_one(-8));
+    }
+}
+```
+
+Assuming the module under test is called `my_lib`, running the tests with the
+`RUST_LOG` filtering to info messages from this module looks like:
+
+```bash
+$ RUST_LOG=my_lib=info cargo test
+     Running target/debug/my_lib-...
+
+running 2 tests
+[INFO my_lib::tests] logging from another test
+[INFO my_lib] add_one called with -8
+test tests::it_handles_negative_numbers ... ok
+[INFO my_lib::tests] can log from the test too
+[INFO my_lib] add_one called with 2
+test tests::it_adds_one ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
+```
+
+Note that `env_logger::try_init()` needs to be called in each test in which you
+want to enable logging. Additionally, the default behavior of tests to
+run in parallel means that logging output may be interleaved with test output.
+Either run tests in a single thread by specifying `RUST_TEST_THREADS=1` or by
+running one test by specifying its name as an argument to the test binaries as
+directed by the `cargo test` help docs:
+
+```bash
+$ RUST_LOG=my_lib=info cargo test it_adds_one
+     Running target/debug/my_lib-...
+
+running 1 test
+[INFO my_lib::tests] can log from the test too
+[INFO my_lib] add_one called with 2
+test tests::it_adds_one ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+```
+
+## Configuring log target
+
+By default, `env_logger` logs to stderr. If you want to log to stdout instead,
+you can use the `Builder` to change the log target:
+
+```rust
+use std::env;
+use env_logger::{Builder, Target};
+
+let mut builder = Builder::from_default_env();
+builder.target(Target::Stdout);
+
+builder.init();
+```
+
+## Stability of the default format
+
+The default format won't optimise for long-term stability, and explicitly makes no guarantees about the stability of its output across major, minor or patch version bumps during `0.x`.
+
+If you want to capture or interpret the output of `env_logger` programmatically then you should use a custom format.
diff --git a/examples/custom_default_format.rs b/examples/custom_default_format.rs
new file mode 100644
index 0000000..4397924
--- /dev/null
+++ b/examples/custom_default_format.rs
@@ -0,0 +1,41 @@
+/*!
+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");
+
+    let mut builder = Builder::from_env(env);
+
+    builder.format_level(false).format_timestamp_nanos();
+
+    builder.init();
+}
+
+fn main() {
+    init_logger();
+
+    info!("a log from `MyLogger`");
+}
diff --git a/examples/custom_format.rs b/examples/custom_format.rs
new file mode 100644
index 0000000..df5a8e5
--- /dev/null
+++ b/examples/custom_format.rs
@@ -0,0 +1,53 @@
+/*!
+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, 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(fmt::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
new file mode 100644
index 0000000..85de45b
--- /dev/null
+++ b/examples/custom_logger.rs
@@ -0,0 +1,60 @@
+/*!
+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::Filter;
+use log::{Log, Metadata, Record, SetLoggerError};
+
+struct MyLogger {
+    inner: Filter,
+}
+
+impl MyLogger {
+    fn new() -> MyLogger {
+        use env_logger::filter::Builder;
+        let mut builder = Builder::from_env("MY_LOG_LEVEL");
+
+        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
new file mode 100644
index 0000000..67bb030
--- /dev/null
+++ b/examples/default.rs
@@ -0,0 +1,38 @@
+/*!
+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
new file mode 100644
index 0000000..4ba023f
--- /dev/null
+++ b/examples/direct_logger.rs
@@ -0,0 +1,37 @@
+/*!
+Using `env_logger::Logger` and the `log::Log` trait directly.
+
+This example doesn't rely on environment variables, or having a static logger installed.
+*/
+
+fn record() -> log::Record<'static> {
+    let error_metadata = log::MetadataBuilder::new()
+        .target("myApp")
+        .level(log::Level::Error)
+        .build();
+
+    log::Record::builder()
+        .metadata(error_metadata)
+        .args(format_args!("Error!"))
+        .line(Some(433))
+        .file(Some("app.rs"))
+        .module_path(Some("server"))
+        .build()
+}
+
+fn main() {
+    use log::Log;
+
+    let stylish_logger = env_logger::Builder::new()
+        .filter(None, log::LevelFilter::Error)
+        .write_style(env_logger::WriteStyle::Always)
+        .build();
+
+    let unstylish_logger = env_logger::Builder::new()
+        .filter(None, log::LevelFilter::Error)
+        .write_style(env_logger::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
new file mode 100644
index 0000000..4137c91
--- /dev/null
+++ b/examples/filters_from_code.rs
@@ -0,0 +1,18 @@
+/*!
+Specify logging filters in code instead of using an environment variable.
+*/
+
+#[macro_use]
+extern crate log;
+
+fn main() {
+    env_logger::builder()
+        .filter_level(log::LevelFilter::Trace)
+        .init();
+
+    trace!("some trace log");
+    debug!("some debug log");
+    info!("some information log");
+    warn!("some warning log");
+    error!("some error log");
+}
diff --git a/src/filter/mod.rs b/src/filter/mod.rs
new file mode 100644
index 0000000..a994f4d
--- /dev/null
+++ b/src/filter/mod.rs
@@ -0,0 +1,616 @@
+//! Filtering for log records.
+//!
+//! This module contains the log filtering used by `env_logger` to match records.
+//! You can use the `Filter` type in your own logger implementation to use the same
+//! filter parsing and matching as `env_logger`. For more details about the format
+//! for directive strings see [Enabling Logging].
+//!
+//! ## Using `env_logger` in your own logger
+//!
+//! You can use `env_logger`'s filtering functionality with your own logger.
+//! Call [`Builder::parse`] to parse directives from a string when constructing
+//! your logger. Call [`Filter::matches`] to check whether a record should be
+//! logged based on the parsed filters when log records are received.
+//!
+//! ```
+//! extern crate log;
+//! extern crate env_logger;
+//! use env_logger::filter::Filter;
+//! use log::{Log, Metadata, Record};
+//!
+//! struct MyLogger {
+//!     filter: Filter
+//! }
+//!
+//! impl MyLogger {
+//!     fn new() -> MyLogger {
+//!         use env_logger::filter::Builder;
+//!         let mut builder = Builder::new();
+//!
+//!         // Parse a directives string from an environment variable
+//!         if let Ok(ref filter) = std::env::var("MY_LOG_LEVEL") {
+//!            builder.parse(filter);
+//!         }
+//!
+//!         MyLogger {
+//!             filter: builder.build()
+//!         }
+//!     }
+//! }
+//!
+//! impl Log for MyLogger {
+//!     fn enabled(&self, metadata: &Metadata) -> bool {
+//!         self.filter.enabled(metadata)
+//!     }
+//!
+//!     fn log(&self, record: &Record) {
+//!         // Check if the record is matched by the filter
+//!         if self.filter.matches(record) {
+//!             println!("{:?}", record);
+//!         }
+//!     }
+//!
+//!     fn flush(&self) {}
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! [Enabling Logging]: ../index.html#enabling-logging
+//! [`Builder::parse`]: struct.Builder.html#method.parse
+//! [`Filter::matches`]: struct.Filter.html#method.matches
+
+use log::{Level, LevelFilter, Metadata, Record};
+use std::env;
+use std::fmt;
+use std::mem;
+
+#[cfg(feature = "regex")]
+#[path = "regex.rs"]
+mod inner;
+
+#[cfg(not(feature = "regex"))]
+#[path = "string.rs"]
+mod inner;
+
+/// A log filter.
+///
+/// This struct can be used to determine whether or not a log record
+/// should be written to the output.
+/// Use the [`Builder`] type to parse and construct a `Filter`.
+///
+/// [`Builder`]: struct.Builder.html
+pub struct Filter {
+    directives: Vec<Directive>,
+    filter: Option<inner::Filter>,
+}
+
+/// A builder for a log filter.
+///
+/// It can be used to parse a set of directives from a string before building
+/// a [`Filter`] instance.
+///
+/// ## Example
+///
+/// ```
+/// #[macro_use]
+/// extern crate log;
+/// extern crate env_logger;
+///
+/// use std::env;
+/// use std::io;
+/// use env_logger::filter::Builder;
+///
+/// fn main() {
+///     let mut builder = Builder::new();
+///
+///     // Parse a logging filter from an environment variable.
+///     if let Ok(rust_log) = env::var("RUST_LOG") {
+///        builder.parse(&rust_log);
+///     }
+///
+///     let filter = builder.build();
+/// }
+/// ```
+///
+/// [`Filter`]: struct.Filter.html
+pub struct Builder {
+    directives: Vec<Directive>,
+    filter: Option<inner::Filter>,
+    built: bool,
+}
+
+#[derive(Debug)]
+struct Directive {
+    name: Option<String>,
+    level: LevelFilter,
+}
+
+impl Filter {
+    /// Returns the maximum `LevelFilter` that this filter instance is
+    /// configured to output.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// extern crate log;
+    /// extern crate env_logger;
+    ///
+    /// use log::LevelFilter;
+    /// use env_logger::filter::Builder;
+    ///
+    /// fn main() {
+    ///     let mut builder = Builder::new();
+    ///     builder.filter(Some("module1"), LevelFilter::Info);
+    ///     builder.filter(Some("module2"), LevelFilter::Error);
+    ///
+    ///     let filter = builder.build();
+    ///     assert_eq!(filter.filter(), LevelFilter::Info);
+    /// }
+    /// ```
+    pub fn filter(&self) -> LevelFilter {
+        self.directives
+            .iter()
+            .map(|d| d.level)
+            .max()
+            .unwrap_or(LevelFilter::Off)
+    }
+
+    /// Checks if this record matches the configured filter.
+    pub fn matches(&self, record: &Record) -> bool {
+        if !self.enabled(record.metadata()) {
+            return false;
+        }
+
+        if let Some(filter) = self.filter.as_ref() {
+            if !filter.is_match(&*record.args().to_string()) {
+                return false;
+            }
+        }
+
+        true
+    }
+
+    /// Determines if a log message with the specified metadata would be logged.
+    pub fn enabled(&self, metadata: &Metadata) -> bool {
+        let level = metadata.level();
+        let target = metadata.target();
+
+        enabled(&self.directives, level, target)
+    }
+}
+
+impl Builder {
+    /// Initializes the filter builder with defaults.
+    pub fn new() -> Builder {
+        Builder {
+            directives: Vec::new(),
+            filter: None,
+            built: false,
+        }
+    }
+
+    /// Initializes the filter builder from an environment.
+    pub fn from_env(env: &str) -> Builder {
+        let mut builder = Builder::new();
+
+        if let Ok(s) = env::var(env) {
+            builder.parse(&s);
+        }
+
+        builder
+    }
+
+    /// Adds a directive to the filter for a specific module.
+    pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self {
+        self.filter(Some(module), level)
+    }
+
+    /// Adds a directive to the filter for all modules.
+    pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self {
+        self.filter(None, level)
+    }
+
+    /// Adds a directive to the filter.
+    ///
+    /// The given module (if any) will log at most the specified level provided.
+    /// If no module is provided then the filter will apply to all log messages.
+    pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self {
+        self.directives.push(Directive {
+            name: module.map(|s| s.to_string()),
+            level,
+        });
+        self
+    }
+
+    /// Parses the directives string.
+    ///
+    /// See the [Enabling Logging] section for more details.
+    ///
+    /// [Enabling Logging]: ../index.html#enabling-logging
+    pub fn parse(&mut self, filters: &str) -> &mut Self {
+        let (directives, filter) = parse_spec(filters);
+
+        self.filter = filter;
+
+        for directive in directives {
+            self.directives.push(directive);
+        }
+        self
+    }
+
+    /// Build a log filter.
+    pub fn build(&mut self) -> Filter {
+        assert!(!self.built, "attempt to re-use consumed builder");
+        self.built = true;
+
+        if self.directives.is_empty() {
+            // Adds the default filter if none exist
+            self.directives.push(Directive {
+                name: None,
+                level: LevelFilter::Error,
+            });
+        } else {
+            // Sort the directives by length of their name, this allows a
+            // little more efficient lookup at runtime.
+            self.directives.sort_by(|a, b| {
+                let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0);
+                let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0);
+                alen.cmp(&blen)
+            });
+        }
+
+        Filter {
+            directives: mem::replace(&mut self.directives, Vec::new()),
+            filter: mem::replace(&mut self.filter, None),
+        }
+    }
+}
+
+impl Default for Builder {
+    fn default() -> Self {
+        Builder::new()
+    }
+}
+
+impl fmt::Debug for Filter {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Filter")
+            .field("filter", &self.filter)
+            .field("directives", &self.directives)
+            .finish()
+    }
+}
+
+impl fmt::Debug for Builder {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.built {
+            f.debug_struct("Filter").field("built", &true).finish()
+        } else {
+            f.debug_struct("Filter")
+                .field("filter", &self.filter)
+                .field("directives", &self.directives)
+                .finish()
+        }
+    }
+}
+
+/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=error/foo")
+/// and return a vector with log directives.
+fn parse_spec(spec: &str) -> (Vec<Directive>, Option<inner::Filter>) {
+    let mut dirs = Vec::new();
+
+    let mut parts = spec.split('/');
+    let mods = parts.next();
+    let filter = parts.next();
+    if parts.next().is_some() {
+        eprintln!(
+            "warning: invalid logging spec '{}', \
+             ignoring it (too many '/'s)",
+            spec
+        );
+        return (dirs, None);
+    }
+    mods.map(|m| {
+        for s in m.split(',') {
+            if s.len() == 0 {
+                continue;
+            }
+            let mut parts = s.split('=');
+            let (log_level, name) =
+                match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
+                    (Some(part0), None, None) => {
+                        // if the single argument is a log-level string or number,
+                        // treat that as a global fallback
+                        match part0.parse() {
+                            Ok(num) => (num, None),
+                            Err(_) => (LevelFilter::max(), Some(part0)),
+                        }
+                    }
+                    (Some(part0), Some(""), None) => (LevelFilter::max(), Some(part0)),
+                    (Some(part0), Some(part1), None) => match part1.parse() {
+                        Ok(num) => (num, Some(part0)),
+                        _ => {
+                            eprintln!(
+                                "warning: invalid logging spec '{}', \
+                                 ignoring it",
+                                part1
+                            );
+                            continue;
+                        }
+                    },
+                    _ => {
+                        eprintln!(
+                            "warning: invalid logging spec '{}', \
+                             ignoring it",
+                            s
+                        );
+                        continue;
+                    }
+                };
+            dirs.push(Directive {
+                name: name.map(|s| s.to_string()),
+                level: log_level,
+            });
+        }
+    });
+
+    let filter = filter.map_or(None, |filter| match inner::Filter::new(filter) {
+        Ok(re) => Some(re),
+        Err(e) => {
+            eprintln!("warning: invalid regex filter - {}", e);
+            None
+        }
+    });
+
+    return (dirs, filter);
+}
+
+// Check whether a level and target are enabled by the set of directives.
+fn enabled(directives: &[Directive], level: Level, target: &str) -> bool {
+    // Search for the longest match, the vector is assumed to be pre-sorted.
+    for directive in directives.iter().rev() {
+        match directive.name {
+            Some(ref name) if !target.starts_with(&**name) => {}
+            Some(..) | None => return level <= directive.level,
+        }
+    }
+    false
+}
+
+#[cfg(test)]
+mod tests {
+    use log::{Level, LevelFilter};
+
+    use super::{enabled, parse_spec, Builder, Directive, Filter};
+
+    fn make_logger_filter(dirs: Vec<Directive>) -> Filter {
+        let mut logger = Builder::new().build();
+        logger.directives = dirs;
+        logger
+    }
+
+    #[test]
+    fn filter_info() {
+        let logger = Builder::new().filter(None, LevelFilter::Info).build();
+        assert!(enabled(&logger.directives, Level::Info, "crate1"));
+        assert!(!enabled(&logger.directives, Level::Debug, "crate1"));
+    }
+
+    #[test]
+    fn filter_beginning_longest_match() {
+        let logger = Builder::new()
+            .filter(Some("crate2"), LevelFilter::Info)
+            .filter(Some("crate2::mod"), LevelFilter::Debug)
+            .filter(Some("crate1::mod1"), LevelFilter::Warn)
+            .build();
+        assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
+        assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
+    }
+
+    #[test]
+    fn parse_default() {
+        let logger = Builder::new().parse("info,crate1::mod1=warn").build();
+        assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
+        assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
+    }
+
+    #[test]
+    fn match_full_path() {
+        let logger = make_logger_filter(vec![
+            Directive {
+                name: Some("crate2".to_string()),
+                level: LevelFilter::Info,
+            },
+            Directive {
+                name: Some("crate1::mod1".to_string()),
+                level: LevelFilter::Warn,
+            },
+        ]);
+        assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
+        assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1"));
+        assert!(enabled(&logger.directives, Level::Info, "crate2"));
+        assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
+    }
+
+    #[test]
+    fn no_match() {
+        let logger = make_logger_filter(vec![
+            Directive {
+                name: Some("crate2".to_string()),
+                level: LevelFilter::Info,
+            },
+            Directive {
+                name: Some("crate1::mod1".to_string()),
+                level: LevelFilter::Warn,
+            },
+        ]);
+        assert!(!enabled(&logger.directives, Level::Warn, "crate3"));
+    }
+
+    #[test]
+    fn match_beginning() {
+        let logger = make_logger_filter(vec![
+            Directive {
+                name: Some("crate2".to_string()),
+                level: LevelFilter::Info,
+            },
+            Directive {
+                name: Some("crate1::mod1".to_string()),
+                level: LevelFilter::Warn,
+            },
+        ]);
+        assert!(enabled(&logger.directives, Level::Info, "crate2::mod1"));
+    }
+
+    #[test]
+    fn match_beginning_longest_match() {
+        let logger = make_logger_filter(vec![
+            Directive {
+                name: Some("crate2".to_string()),
+                level: LevelFilter::Info,
+            },
+            Directive {
+                name: Some("crate2::mod".to_string()),
+                level: LevelFilter::Debug,
+            },
+            Directive {
+                name: Some("crate1::mod1".to_string()),
+                level: LevelFilter::Warn,
+            },
+        ]);
+        assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
+        assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
+    }
+
+    #[test]
+    fn match_default() {
+        let logger = make_logger_filter(vec![
+            Directive {
+                name: None,
+                level: LevelFilter::Info,
+            },
+            Directive {
+                name: Some("crate1::mod1".to_string()),
+                level: LevelFilter::Warn,
+            },
+        ]);
+        assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
+        assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
+    }
+
+    #[test]
+    fn zero_level() {
+        let logger = make_logger_filter(vec![
+            Directive {
+                name: None,
+                level: LevelFilter::Info,
+            },
+            Directive {
+                name: Some("crate1::mod1".to_string()),
+                level: LevelFilter::Off,
+            },
+        ]);
+        assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1"));
+        assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
+    }
+
+    #[test]
+    fn parse_spec_valid() {
+        let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug");
+        assert_eq!(dirs.len(), 3);
+        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::Error);
+
+        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
+        assert_eq!(dirs[1].level, LevelFilter::max());
+
+        assert_eq!(dirs[2].name, Some("crate2".to_string()));
+        assert_eq!(dirs[2].level, LevelFilter::Debug);
+        assert!(filter.is_none());
+    }
+
+    #[test]
+    fn parse_spec_invalid_crate() {
+        // test parse_spec with multiple = in specification
+        let (dirs, filter) = parse_spec("crate1::mod1=warn=info,crate2=debug");
+        assert_eq!(dirs.len(), 1);
+        assert_eq!(dirs[0].name, Some("crate2".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::Debug);
+        assert!(filter.is_none());
+    }
+
+    #[test]
+    fn parse_spec_invalid_level() {
+        // test parse_spec with 'noNumber' as log level
+        let (dirs, filter) = parse_spec("crate1::mod1=noNumber,crate2=debug");
+        assert_eq!(dirs.len(), 1);
+        assert_eq!(dirs[0].name, Some("crate2".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::Debug);
+        assert!(filter.is_none());
+    }
+
+    #[test]
+    fn parse_spec_string_level() {
+        // test parse_spec with 'warn' as log level
+        let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2=warn");
+        assert_eq!(dirs.len(), 1);
+        assert_eq!(dirs[0].name, Some("crate2".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::Warn);
+        assert!(filter.is_none());
+    }
+
+    #[test]
+    fn parse_spec_empty_level() {
+        // test parse_spec with '' as log level
+        let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2=");
+        assert_eq!(dirs.len(), 1);
+        assert_eq!(dirs[0].name, Some("crate2".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::max());
+        assert!(filter.is_none());
+    }
+
+    #[test]
+    fn parse_spec_global() {
+        // test parse_spec with no crate
+        let (dirs, filter) = parse_spec("warn,crate2=debug");
+        assert_eq!(dirs.len(), 2);
+        assert_eq!(dirs[0].name, None);
+        assert_eq!(dirs[0].level, LevelFilter::Warn);
+        assert_eq!(dirs[1].name, Some("crate2".to_string()));
+        assert_eq!(dirs[1].level, LevelFilter::Debug);
+        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);
+        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::Error);
+
+        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
+        assert_eq!(dirs[1].level, LevelFilter::max());
+
+        assert_eq!(dirs[2].name, Some("crate2".to_string()));
+        assert_eq!(dirs[2].level, LevelFilter::Debug);
+        assert!(filter.is_some() && filter.unwrap().to_string() == "abc");
+    }
+
+    #[test]
+    fn parse_spec_invalid_crate_filter() {
+        let (dirs, filter) = parse_spec("crate1::mod1=error=warn,crate2=debug/a.c");
+        assert_eq!(dirs.len(), 1);
+        assert_eq!(dirs[0].name, Some("crate2".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::Debug);
+        assert!(filter.is_some() && filter.unwrap().to_string() == "a.c");
+    }
+
+    #[test]
+    fn parse_spec_empty_with_filter() {
+        let (dirs, filter) = parse_spec("crate1/a*c");
+        assert_eq!(dirs.len(), 1);
+        assert_eq!(dirs[0].name, Some("crate1".to_string()));
+        assert_eq!(dirs[0].level, LevelFilter::max());
+        assert!(filter.is_some() && filter.unwrap().to_string() == "a*c");
+    }
+}
diff --git a/src/filter/regex.rs b/src/filter/regex.rs
new file mode 100644
index 0000000..fb21528
--- /dev/null
+++ b/src/filter/regex.rs
@@ -0,0 +1,29 @@
+extern crate regex;
+
+use std::fmt;
+
+use self::regex::Regex;
+
+#[derive(Debug)]
+pub struct Filter {
+    inner: Regex,
+}
+
+impl Filter {
+    pub fn new(spec: &str) -> Result<Filter, String> {
+        match Regex::new(spec) {
+            Ok(r) => Ok(Filter { inner: r }),
+            Err(e) => Err(e.to_string()),
+        }
+    }
+
+    pub fn is_match(&self, s: &str) -> bool {
+        self.inner.is_match(s)
+    }
+}
+
+impl fmt::Display for Filter {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
diff --git a/src/filter/string.rs b/src/filter/string.rs
new file mode 100644
index 0000000..ea476e4
--- /dev/null
+++ b/src/filter/string.rs
@@ -0,0 +1,24 @@
+use std::fmt;
+
+#[derive(Debug)]
+pub struct Filter {
+    inner: String,
+}
+
+impl Filter {
+    pub fn new(spec: &str) -> Result<Filter, String> {
+        Ok(Filter {
+            inner: spec.to_string(),
+        })
+    }
+
+    pub fn is_match(&self, s: &str) -> bool {
+        s.contains(&self.inner)
+    }
+}
+
+impl fmt::Display for Filter {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
diff --git a/src/fmt/humantime/extern_impl.rs b/src/fmt/humantime/extern_impl.rs
new file mode 100644
index 0000000..19dec1b
--- /dev/null
+++ b/src/fmt/humantime/extern_impl.rs
@@ -0,0 +1,118 @@
+use std::fmt;
+use std::time::SystemTime;
+
+use humantime::{
+    format_rfc3339_micros, format_rfc3339_millis, format_rfc3339_nanos, format_rfc3339_seconds,
+};
+
+use crate::fmt::{Formatter, TimestampPrecision};
+
+pub(in crate::fmt) mod glob {
+    pub use super::*;
+}
+
+impl Formatter {
+    /// Get a [`Timestamp`] for the current date and time in UTC.
+    ///
+    /// # Examples
+    ///
+    /// Include the current timestamp with the log record:
+    ///
+    /// ```
+    /// use std::io::Write;
+    ///
+    /// let mut builder = env_logger::Builder::new();
+    ///
+    /// builder.format(|buf, record| {
+    ///     let ts = buf.timestamp();
+    ///
+    ///     writeln!(buf, "{}: {}: {}", ts, record.level(), record.args())
+    /// });
+    /// ```
+    ///
+    /// [`Timestamp`]: struct.Timestamp.html
+    pub fn timestamp(&self) -> Timestamp {
+        Timestamp {
+            time: SystemTime::now(),
+            precision: TimestampPrecision::Seconds,
+        }
+    }
+
+    /// Get a [`Timestamp`] for the current date and time in UTC with full
+    /// second precision.
+    pub fn timestamp_seconds(&self) -> Timestamp {
+        Timestamp {
+            time: SystemTime::now(),
+            precision: TimestampPrecision::Seconds,
+        }
+    }
+
+    /// Get a [`Timestamp`] for the current date and time in UTC with
+    /// millisecond precision.
+    pub fn timestamp_millis(&self) -> Timestamp {
+        Timestamp {
+            time: SystemTime::now(),
+            precision: TimestampPrecision::Millis,
+        }
+    }
+
+    /// Get a [`Timestamp`] for the current date and time in UTC with
+    /// microsecond precision.
+    pub fn timestamp_micros(&self) -> Timestamp {
+        Timestamp {
+            time: SystemTime::now(),
+            precision: TimestampPrecision::Micros,
+        }
+    }
+
+    /// Get a [`Timestamp`] for the current date and time in UTC with
+    /// nanosecond precision.
+    pub fn timestamp_nanos(&self) -> Timestamp {
+        Timestamp {
+            time: SystemTime::now(),
+            precision: TimestampPrecision::Nanos,
+        }
+    }
+}
+
+/// An [RFC3339] formatted timestamp.
+///
+/// The timestamp implements [`Display`] and can be written to a [`Formatter`].
+///
+/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt
+/// [`Display`]: https://doc.rust-lang.org/stable/std/fmt/trait.Display.html
+/// [`Formatter`]: struct.Formatter.html
+pub struct Timestamp {
+    time: SystemTime,
+    precision: TimestampPrecision,
+}
+
+impl fmt::Debug for Timestamp {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        /// A `Debug` wrapper for `Timestamp` that uses the `Display` implementation.
+        struct TimestampValue<'a>(&'a Timestamp);
+
+        impl<'a> fmt::Debug for TimestampValue<'a> {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                fmt::Display::fmt(&self.0, f)
+            }
+        }
+
+        f.debug_tuple("Timestamp")
+            .field(&TimestampValue(&self))
+            .finish()
+    }
+}
+
+impl fmt::Display for Timestamp {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let formatter = match self.precision {
+            TimestampPrecision::Seconds => format_rfc3339_seconds,
+            TimestampPrecision::Millis => format_rfc3339_millis,
+            TimestampPrecision::Micros => format_rfc3339_micros,
+            TimestampPrecision::Nanos => format_rfc3339_nanos,
+        };
+
+        formatter(self.time).fmt(f)
+    }
+}
diff --git a/src/fmt/humantime/mod.rs b/src/fmt/humantime/mod.rs
new file mode 100644
index 0000000..ac23ae2
--- /dev/null
+++ b/src/fmt/humantime/mod.rs
@@ -0,0 +1,11 @@
+/*
+This internal module contains the timestamp implementation.
+
+Its public API is available when the `humantime` crate is available.
+*/
+
+#[cfg_attr(feature = "humantime", path = "extern_impl.rs")]
+#[cfg_attr(not(feature = "humantime"), path = "shim_impl.rs")]
+mod imp;
+
+pub(in crate::fmt) use self::imp::*;
diff --git a/src/fmt/humantime/shim_impl.rs b/src/fmt/humantime/shim_impl.rs
new file mode 100644
index 0000000..906bf9e
--- /dev/null
+++ b/src/fmt/humantime/shim_impl.rs
@@ -0,0 +1,5 @@
+/*
+Timestamps aren't available when we don't have a `humantime` dependency.
+*/
+
+pub(in crate::fmt) mod glob {}
diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs
new file mode 100644
index 0000000..e699e21
--- /dev/null
+++ b/src/fmt/mod.rs
@@ -0,0 +1,489 @@
+//! Formatting for log records.
+//!
+//! This module contains a [`Formatter`] that can be used to format log records
+//! into without needing temporary allocations. Usually you won't need to worry
+//! about the contents of this module and can use the `Formatter` like an ordinary
+//! [`Write`].
+//!
+//! # Formatting log records
+//!
+//! The format used to print log records can be customised using the [`Builder::format`]
+//! method.
+//! Custom formats can apply different color and weight to printed values using
+//! [`Style`] builders.
+//!
+//! ```
+//! use std::io::Write;
+//!
+//! let mut builder = env_logger::Builder::new();
+//!
+//! builder.format(|buf, record| {
+//!     writeln!(buf, "{}: {}",
+//!         record.level(),
+//!         record.args())
+//! });
+//! ```
+//!
+//! [`Formatter`]: struct.Formatter.html
+//! [`Style`]: struct.Style.html
+//! [`Builder::format`]: ../struct.Builder.html#method.format
+//! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
+
+use std::cell::RefCell;
+use std::fmt::Display;
+use std::io::prelude::*;
+use std::rc::Rc;
+use std::{fmt, io, mem};
+
+use log::Record;
+
+mod humantime;
+pub(crate) mod writer;
+
+pub use self::humantime::glob::*;
+pub use self::writer::glob::*;
+
+use self::writer::{Buffer, Writer};
+
+pub(crate) mod glob {
+    pub use super::{Target, TimestampPrecision, WriteStyle};
+}
+
+/// Formatting precision of timestamps.
+///
+/// Seconds give precision of full seconds, milliseconds give thousands of a
+/// second (3 decimal digits), microseconds are millionth of a second (6 decimal
+/// digits) and nanoseconds are billionth of a second (9 decimal digits).
+#[derive(Copy, Clone, Debug)]
+pub enum TimestampPrecision {
+    /// Full second precision (0 decimal digits)
+    Seconds,
+    /// Millisecond precision (3 decimal digits)
+    Millis,
+    /// Microsecond precision (6 decimal digits)
+    Micros,
+    /// Nanosecond precision (9 decimal digits)
+    Nanos,
+}
+
+/// The default timestamp precision is seconds.
+impl Default for TimestampPrecision {
+    fn default() -> Self {
+        TimestampPrecision::Seconds
+    }
+}
+
+/// A formatter to write logs into.
+///
+/// `Formatter` implements the standard [`Write`] trait for writing log records.
+/// It also supports terminal colors, through the [`style`] method.
+///
+/// # Examples
+///
+/// Use the [`writeln`] macro to format a log record.
+/// An instance of a `Formatter` is passed to an `env_logger` format as `buf`:
+///
+/// ```
+/// use std::io::Write;
+///
+/// let mut builder = env_logger::Builder::new();
+///
+/// builder.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()));
+/// ```
+///
+/// [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
+/// [`writeln`]: https://doc.rust-lang.org/stable/std/macro.writeln.html
+/// [`style`]: #method.style
+pub struct Formatter {
+    buf: Rc<RefCell<Buffer>>,
+    write_style: WriteStyle,
+}
+
+impl Formatter {
+    pub(crate) fn new(writer: &Writer) -> Self {
+        Formatter {
+            buf: Rc::new(RefCell::new(writer.buffer())),
+            write_style: writer.write_style(),
+        }
+    }
+
+    pub(crate) fn write_style(&self) -> WriteStyle {
+        self.write_style
+    }
+
+    pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
+        writer.print(&self.buf.borrow())
+    }
+
+    pub(crate) fn clear(&mut self) {
+        self.buf.borrow_mut().clear()
+    }
+}
+
+impl Write for Formatter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.buf.borrow_mut().write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.buf.borrow_mut().flush()
+    }
+}
+
+impl fmt::Debug for Formatter {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Formatter").finish()
+    }
+}
+
+pub(crate) struct Builder {
+    pub format_timestamp: Option<TimestampPrecision>,
+    pub format_module_path: bool,
+    pub format_level: bool,
+    pub format_indent: Option<usize>,
+    #[allow(unknown_lints, bare_trait_objects)]
+    pub custom_format: Option<Box<Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>>,
+    built: bool,
+}
+
+impl Default for Builder {
+    fn default() -> Self {
+        Builder {
+            format_timestamp: Some(Default::default()),
+            format_module_path: true,
+            format_level: true,
+            format_indent: Some(4),
+            custom_format: None,
+            built: false,
+        }
+    }
+}
+
+impl Builder {
+    /// Convert the format into a callable function.
+    ///
+    /// If the `custom_format` is `Some`, then any `default_format` switches are ignored.
+    /// If the `custom_format` is `None`, then a default format is returned.
+    /// Any `default_format` switches set to `false` won't be written by the format.
+    #[allow(unknown_lints, bare_trait_objects)]
+    pub fn build(&mut self) -> Box<Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send> {
+        assert!(!self.built, "attempt to re-use consumed builder");
+
+        let built = mem::replace(
+            self,
+            Builder {
+                built: true,
+                ..Default::default()
+            },
+        );
+
+        if let Some(fmt) = built.custom_format {
+            fmt
+        } else {
+            Box::new(move |buf, record| {
+                let fmt = DefaultFormat {
+                    timestamp: built.format_timestamp,
+                    module_path: built.format_module_path,
+                    level: built.format_level,
+                    written_header_value: false,
+                    indent: built.format_indent,
+                    buf,
+                };
+
+                fmt.write(record)
+            })
+        }
+    }
+}
+
+#[cfg(feature = "termcolor")]
+type SubtleStyle = StyledValue<'static, &'static str>;
+#[cfg(not(feature = "termcolor"))]
+type SubtleStyle = &'static str;
+
+/// The default format.
+///
+/// This format needs to work with any combination of crate features.
+struct DefaultFormat<'a> {
+    timestamp: Option<TimestampPrecision>,
+    module_path: bool,
+    level: bool,
+    written_header_value: bool,
+    indent: Option<usize>,
+    buf: &'a mut Formatter,
+}
+
+impl<'a> DefaultFormat<'a> {
+    fn write(mut self, record: &Record) -> io::Result<()> {
+        self.write_timestamp()?;
+        self.write_level(record)?;
+        self.write_module_path(record)?;
+        self.finish_header()?;
+
+        self.write_args(record)
+    }
+
+    fn subtle_style(&self, text: &'static str) -> SubtleStyle {
+        #[cfg(feature = "termcolor")]
+        {
+            self.buf
+                .style()
+                .set_color(Color::Black)
+                .set_intense(true)
+                .into_value(text)
+        }
+        #[cfg(not(feature = "termcolor"))]
+        {
+            text
+        }
+    }
+
+    fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
+    where
+        T: Display,
+    {
+        if !self.written_header_value {
+            self.written_header_value = true;
+
+            let open_brace = self.subtle_style("[");
+            write!(self.buf, "{}{}", open_brace, value)
+        } else {
+            write!(self.buf, " {}", value)
+        }
+    }
+
+    fn write_level(&mut self, record: &Record) -> io::Result<()> {
+        if !self.level {
+            return Ok(());
+        }
+
+        let level = {
+            #[cfg(feature = "termcolor")]
+            {
+                self.buf.default_styled_level(record.level())
+            }
+            #[cfg(not(feature = "termcolor"))]
+            {
+                record.level()
+            }
+        };
+
+        self.write_header_value(format_args!("{:<5}", level))
+    }
+
+    fn write_timestamp(&mut self) -> io::Result<()> {
+        #[cfg(feature = "humantime")]
+        {
+            use self::TimestampPrecision::*;
+            let ts = match self.timestamp {
+                None => return Ok(()),
+                Some(Seconds) => self.buf.timestamp_seconds(),
+                Some(Millis) => self.buf.timestamp_millis(),
+                Some(Micros) => self.buf.timestamp_micros(),
+                Some(Nanos) => self.buf.timestamp_nanos(),
+            };
+
+            self.write_header_value(ts)
+        }
+        #[cfg(not(feature = "humantime"))]
+        {
+            // Trick the compiler to think we have used self.timestamp
+            // Workaround for "field is never used: `timestamp`" compiler nag.
+            let _ = self.timestamp;
+            Ok(())
+        }
+    }
+
+    fn write_module_path(&mut self, record: &Record) -> io::Result<()> {
+        if !self.module_path {
+            return Ok(());
+        }
+
+        if let Some(module_path) = record.module_path() {
+            self.write_header_value(module_path)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn finish_header(&mut self) -> io::Result<()> {
+        if self.written_header_value {
+            let close_brace = self.subtle_style("]");
+            write!(self.buf, "{} ", close_brace)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn write_args(&mut self, record: &Record) -> io::Result<()> {
+        match self.indent {
+            // Fast path for no indentation
+            None => writeln!(self.buf, "{}", record.args()),
+
+            Some(indent_count) => {
+                // Create a wrapper around the buffer only if we have to actually indent the message
+
+                struct IndentWrapper<'a, 'b: 'a> {
+                    fmt: &'a mut DefaultFormat<'b>,
+                    indent_count: usize,
+                }
+
+                impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
+                    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+                        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)?;
+                            }
+                            self.fmt.buf.write_all(chunk)?;
+                            first = false;
+                        }
+
+                        Ok(buf.len())
+                    }
+
+                    fn flush(&mut self) -> io::Result<()> {
+                        self.fmt.buf.flush()
+                    }
+                }
+
+                // The explicit scope here is just to make older versions of Rust happy
+                {
+                    let mut wrapper = IndentWrapper {
+                        fmt: self,
+                        indent_count,
+                    };
+                    write!(wrapper, "{}", record.args())?;
+                }
+
+                writeln!(self.buf)?;
+
+                Ok(())
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use log::{Level, Record};
+
+    fn write(fmt: DefaultFormat) -> String {
+        let buf = fmt.buf.buf.clone();
+
+        let record = Record::builder()
+            .args(format_args!("log\nmessage"))
+            .level(Level::Info)
+            .file(Some("test.rs"))
+            .line(Some(144))
+            .module_path(Some("test::path"))
+            .build();
+
+        fmt.write(&record).expect("failed to write record");
+
+        let buf = buf.borrow();
+        String::from_utf8(buf.bytes().to_vec()).expect("failed to read record")
+    }
+
+    #[test]
+    fn format_with_header() {
+        let writer = writer::Builder::new()
+            .write_style(WriteStyle::Never)
+            .build();
+
+        let mut f = Formatter::new(&writer);
+
+        let written = write(DefaultFormat {
+            timestamp: None,
+            module_path: true,
+            level: true,
+            written_header_value: false,
+            indent: None,
+            buf: &mut f,
+        });
+
+        assert_eq!("[INFO  test::path] log\nmessage\n", written);
+    }
+
+    #[test]
+    fn format_no_header() {
+        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,
+            buf: &mut f,
+        });
+
+        assert_eq!("log\nmessage\n", written);
+    }
+
+    #[test]
+    fn format_indent_spaces() {
+        let writer = writer::Builder::new()
+            .write_style(WriteStyle::Never)
+            .build();
+
+        let mut f = Formatter::new(&writer);
+
+        let written = write(DefaultFormat {
+            timestamp: None,
+            module_path: true,
+            level: true,
+            written_header_value: false,
+            indent: Some(4),
+            buf: &mut f,
+        });
+
+        assert_eq!("[INFO  test::path] log\n    message\n", written);
+    }
+
+    #[test]
+    fn format_indent_zero_spaces() {
+        let writer = writer::Builder::new()
+            .write_style(WriteStyle::Never)
+            .build();
+
+        let mut f = Formatter::new(&writer);
+
+        let written = write(DefaultFormat {
+            timestamp: None,
+            module_path: true,
+            level: true,
+            written_header_value: false,
+            indent: Some(0),
+            buf: &mut f,
+        });
+
+        assert_eq!("[INFO  test::path] log\nmessage\n", written);
+    }
+
+    #[test]
+    fn format_indent_spaces_no_header() {
+        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),
+            buf: &mut f,
+        });
+
+        assert_eq!("log\n    message\n", written);
+    }
+}
diff --git a/src/fmt/writer/atty.rs b/src/fmt/writer/atty.rs
new file mode 100644
index 0000000..f671841
--- /dev/null
+++ b/src/fmt/writer/atty.rs
@@ -0,0 +1,34 @@
+/*
+This internal module contains the terminal detection implementation.
+
+If the `atty` crate is available then we use it to detect whether we're
+attached to a particular TTY. If the `atty` crate is not available we
+assume we're not attached to anything. This effectively prevents styles
+from being printed.
+*/
+
+#[cfg(feature = "atty")]
+mod imp {
+    use atty;
+
+    pub(in crate::fmt) fn is_stdout() -> bool {
+        atty::is(atty::Stream::Stdout)
+    }
+
+    pub(in crate::fmt) fn is_stderr() -> bool {
+        atty::is(atty::Stream::Stderr)
+    }
+}
+
+#[cfg(not(feature = "atty"))]
+mod imp {
+    pub(in crate::fmt) fn is_stdout() -> bool {
+        false
+    }
+
+    pub(in crate::fmt) fn is_stderr() -> bool {
+        false
+    }
+}
+
+pub(in crate::fmt) use self::imp::*;
diff --git a/src/fmt/writer/mod.rs b/src/fmt/writer/mod.rs
new file mode 100644
index 0000000..6ee63a3
--- /dev/null
+++ b/src/fmt/writer/mod.rs
@@ -0,0 +1,201 @@
+mod atty;
+mod termcolor;
+
+use self::atty::{is_stderr, is_stdout};
+use self::termcolor::BufferWriter;
+use std::{fmt, io};
+
+pub(in crate::fmt) mod glob {
+    pub use super::termcolor::glob::*;
+    pub use super::*;
+}
+
+pub(in crate::fmt) use self::termcolor::Buffer;
+
+/// Log target, either `stdout` or `stderr`.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum Target {
+    /// Logs will be sent to standard output.
+    Stdout,
+    /// Logs will be sent to standard error.
+    Stderr,
+}
+
+impl Default for Target {
+    fn default() -> Self {
+        Target::Stderr
+    }
+}
+
+/// Whether or not to print styles to the target.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum WriteStyle {
+    /// Try to print styles, but don't force the issue.
+    Auto,
+    /// Try very hard to print styles.
+    Always,
+    /// Never print styles.
+    Never,
+}
+
+impl Default for WriteStyle {
+    fn default() -> Self {
+        WriteStyle::Auto
+    }
+}
+
+/// A terminal target with color awareness.
+pub(crate) struct Writer {
+    inner: BufferWriter,
+    write_style: WriteStyle,
+}
+
+impl Writer {
+    pub fn write_style(&self) -> WriteStyle {
+        self.write_style
+    }
+
+    pub(in crate::fmt) fn buffer(&self) -> Buffer {
+        self.inner.buffer()
+    }
+
+    pub(in crate::fmt) fn print(&self, buf: &Buffer) -> io::Result<()> {
+        self.inner.print(buf)
+    }
+}
+
+/// A builder for a terminal writer.
+///
+/// The target and style choice can be configured before building.
+pub(crate) struct Builder {
+    target: Target,
+    write_style: WriteStyle,
+    is_test: bool,
+    built: bool,
+}
+
+impl Builder {
+    /// Initialize the writer builder with defaults.
+    pub(crate) fn new() -> Self {
+        Builder {
+            target: Default::default(),
+            write_style: Default::default(),
+            is_test: false,
+            built: false,
+        }
+    }
+
+    /// Set the target to write to.
+    pub(crate) fn target(&mut self, target: Target) -> &mut Self {
+        self.target = target;
+        self
+    }
+
+    /// Parses a style choice string.
+    ///
+    /// See the [Disabling colors] section for more details.
+    ///
+    /// [Disabling colors]: ../index.html#disabling-colors
+    pub(crate) fn parse_write_style(&mut self, write_style: &str) -> &mut Self {
+        self.write_style(parse_write_style(write_style))
+    }
+
+    /// Whether or not to print style characters when writing.
+    pub(crate) fn write_style(&mut self, write_style: WriteStyle) -> &mut Self {
+        self.write_style = write_style;
+        self
+    }
+
+    /// Whether or not to capture logs for `cargo test`.
+    pub(crate) fn is_test(&mut self, is_test: bool) -> &mut Self {
+        self.is_test = is_test;
+        self
+    }
+
+    /// Build a terminal writer.
+    pub(crate) fn build(&mut self) -> Writer {
+        assert!(!self.built, "attempt to re-use consumed builder");
+        self.built = true;
+
+        let color_choice = match self.write_style {
+            WriteStyle::Auto => {
+                if match self.target {
+                    Target::Stderr => is_stderr(),
+                    Target::Stdout => is_stdout(),
+                } {
+                    WriteStyle::Auto
+                } else {
+                    WriteStyle::Never
+                }
+            }
+            color_choice => color_choice,
+        };
+
+        let writer = match self.target {
+            Target::Stderr => BufferWriter::stderr(self.is_test, color_choice),
+            Target::Stdout => BufferWriter::stdout(self.is_test, color_choice),
+        };
+
+        Writer {
+            inner: writer,
+            write_style: self.write_style,
+        }
+    }
+}
+
+impl Default for Builder {
+    fn default() -> Self {
+        Builder::new()
+    }
+}
+
+impl fmt::Debug for Builder {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Logger")
+            .field("target", &self.target)
+            .field("write_style", &self.write_style)
+            .finish()
+    }
+}
+
+impl fmt::Debug for Writer {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Writer").finish()
+    }
+}
+
+fn parse_write_style(spec: &str) -> WriteStyle {
+    match spec {
+        "auto" => WriteStyle::Auto,
+        "always" => WriteStyle::Always,
+        "never" => WriteStyle::Never,
+        _ => Default::default(),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parse_write_style_valid() {
+        let inputs = vec![
+            ("auto", WriteStyle::Auto),
+            ("always", WriteStyle::Always),
+            ("never", WriteStyle::Never),
+        ];
+
+        for (input, expected) in inputs {
+            assert_eq!(expected, parse_write_style(input));
+        }
+    }
+
+    #[test]
+    fn parse_write_style_invalid() {
+        let inputs = vec!["", "true", "false", "NEVER!!"];
+
+        for input in inputs {
+            assert_eq!(WriteStyle::Auto, parse_write_style(input));
+        }
+    }
+}
diff --git a/src/fmt/writer/termcolor/extern_impl.rs b/src/fmt/writer/termcolor/extern_impl.rs
new file mode 100644
index 0000000..2d38e37
--- /dev/null
+++ b/src/fmt/writer/termcolor/extern_impl.rs
@@ -0,0 +1,486 @@
+use std::borrow::Cow;
+use std::cell::RefCell;
+use std::fmt;
+use std::io::{self, Write};
+use std::rc::Rc;
+
+use log::Level;
+use termcolor::{self, ColorChoice, ColorSpec, WriteColor};
+
+use crate::fmt::{Formatter, Target, WriteStyle};
+
+pub(in crate::fmt::writer) mod glob {
+    pub use super::*;
+}
+
+impl Formatter {
+    /// Begin a new [`Style`].
+    ///
+    /// # Examples
+    ///
+    /// Create a bold, red colored style and use it to print the log level:
+    ///
+    /// ```
+    /// use std::io::Write;
+    /// use env_logger::fmt::Color;
+    ///
+    /// let mut builder = env_logger::Builder::new();
+    ///
+    /// builder.format(|buf, record| {
+    ///     let mut level_style = buf.style();
+    ///
+    ///     level_style.set_color(Color::Red).set_bold(true);
+    ///
+    ///     writeln!(buf, "{}: {}",
+    ///         level_style.value(record.level()),
+    ///         record.args())
+    /// });
+    /// ```
+    ///
+    /// [`Style`]: struct.Style.html
+    pub fn style(&self) -> Style {
+        Style {
+            buf: self.buf.clone(),
+            spec: ColorSpec::new(),
+        }
+    }
+
+    /// Get the default [`Style`] for the given level.
+    ///
+    /// The style can be used to print other values besides the level.
+    pub fn default_level_style(&self, level: Level) -> Style {
+        let mut level_style = self.style();
+        match level {
+            Level::Trace => level_style.set_color(Color::Black).set_intense(true),
+            Level::Debug => level_style.set_color(Color::White),
+            Level::Info => level_style.set_color(Color::Green),
+            Level::Warn => level_style.set_color(Color::Yellow),
+            Level::Error => level_style.set_color(Color::Red).set_bold(true),
+        };
+        level_style
+    }
+
+    /// Get a printable [`Style`] for the given level.
+    ///
+    /// The style can only be used to print the level.
+    pub fn default_styled_level(&self, level: Level) -> StyledValue<'static, Level> {
+        self.default_level_style(level).into_value(level)
+    }
+}
+
+pub(in crate::fmt::writer) struct BufferWriter {
+    inner: termcolor::BufferWriter,
+    test_target: Option<Target>,
+}
+
+pub(in crate::fmt) struct Buffer {
+    inner: termcolor::Buffer,
+    test_target: Option<Target>,
+}
+
+impl BufferWriter {
+    pub(in crate::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self {
+        BufferWriter {
+            inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
+            test_target: if is_test { Some(Target::Stderr) } else { None },
+        }
+    }
+
+    pub(in crate::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self {
+        BufferWriter {
+            inner: termcolor::BufferWriter::stdout(write_style.into_color_choice()),
+            test_target: if is_test { Some(Target::Stdout) } else { None },
+        }
+    }
+
+    pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
+        Buffer {
+            inner: self.inner.buffer(),
+            test_target: self.test_target,
+        }
+    }
+
+    pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
+        if let Some(target) = self.test_target {
+            // This impl uses the `eprint` and `print` macros
+            // instead of `termcolor`'s buffer.
+            // This is so their output can be captured by `cargo test`
+            let log = String::from_utf8_lossy(buf.bytes());
+
+            match target {
+                Target::Stderr => eprint!("{}", log),
+                Target::Stdout => print!("{}", log),
+            }
+
+            Ok(())
+        } else {
+            self.inner.print(&buf.inner)
+        }
+    }
+}
+
+impl Buffer {
+    pub(in crate::fmt) fn clear(&mut self) {
+        self.inner.clear()
+    }
+
+    pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.inner.write(buf)
+    }
+
+    pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()
+    }
+
+    pub(in crate::fmt) fn bytes(&self) -> &[u8] {
+        self.inner.as_slice()
+    }
+
+    fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
+        // Ignore styles for test captured logs because they can't be printed
+        if self.test_target.is_none() {
+            self.inner.set_color(spec)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn reset(&mut self) -> io::Result<()> {
+        // Ignore styles for test captured logs because they can't be printed
+        if self.test_target.is_none() {
+            self.inner.reset()
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl WriteStyle {
+    fn into_color_choice(self) -> ColorChoice {
+        match self {
+            WriteStyle::Always => ColorChoice::Always,
+            WriteStyle::Auto => ColorChoice::Auto,
+            WriteStyle::Never => ColorChoice::Never,
+        }
+    }
+}
+
+/// A set of styles to apply to the terminal output.
+///
+/// Call [`Formatter::style`] to get a `Style` and use the builder methods to
+/// set styling properties, like [color] and [weight].
+/// To print a value using the style, wrap it in a call to [`value`] when the log
+/// record is formatted.
+///
+/// # Examples
+///
+/// Create a bold, red colored style and use it to print the log level:
+///
+/// ```
+/// use std::io::Write;
+/// use env_logger::fmt::Color;
+///
+/// let mut builder = env_logger::Builder::new();
+///
+/// builder.format(|buf, record| {
+///     let mut level_style = buf.style();
+///
+///     level_style.set_color(Color::Red).set_bold(true);
+///
+///     writeln!(buf, "{}: {}",
+///         level_style.value(record.level()),
+///         record.args())
+/// });
+/// ```
+///
+/// Styles can be re-used to output multiple values:
+///
+/// ```
+/// use std::io::Write;
+/// use env_logger::fmt::Color;
+///
+/// let mut builder = env_logger::Builder::new();
+///
+/// builder.format(|buf, record| {
+///     let mut bold = buf.style();
+///
+///     bold.set_bold(true);
+///
+///     writeln!(buf, "{}: {} {}",
+///         bold.value(record.level()),
+///         bold.value("some bold text"),
+///         record.args())
+/// });
+/// ```
+///
+/// [`Formatter::style`]: struct.Formatter.html#method.style
+/// [color]: #method.set_color
+/// [weight]: #method.set_bold
+/// [`value`]: #method.value
+#[derive(Clone)]
+pub struct Style {
+    buf: Rc<RefCell<Buffer>>,
+    spec: ColorSpec,
+}
+
+/// A value that can be printed using the given styles.
+///
+/// It is the result of calling [`Style::value`].
+///
+/// [`Style::value`]: struct.Style.html#method.value
+pub struct StyledValue<'a, T> {
+    style: Cow<'a, Style>,
+    value: T,
+}
+
+impl Style {
+    /// Set the text color.
+    ///
+    /// # Examples
+    ///
+    /// Create a style with red text:
+    ///
+    /// ```
+    /// use std::io::Write;
+    /// use env_logger::fmt::Color;
+    ///
+    /// let mut builder = env_logger::Builder::new();
+    ///
+    /// builder.format(|buf, record| {
+    ///     let mut style = buf.style();
+    ///
+    ///     style.set_color(Color::Red);
+    ///
+    ///     writeln!(buf, "{}", style.value(record.args()))
+    /// });
+    /// ```
+    pub fn set_color(&mut self, color: Color) -> &mut Style {
+        self.spec.set_fg(color.into_termcolor());
+        self
+    }
+
+    /// Set the text weight.
+    ///
+    /// If `yes` is true then text will be written in bold.
+    /// If `yes` is false then text will be written in the default weight.
+    ///
+    /// # Examples
+    ///
+    /// Create a style with bold text:
+    ///
+    /// ```
+    /// use std::io::Write;
+    ///
+    /// let mut builder = env_logger::Builder::new();
+    ///
+    /// builder.format(|buf, record| {
+    ///     let mut style = buf.style();
+    ///
+    ///     style.set_bold(true);
+    ///
+    ///     writeln!(buf, "{}", style.value(record.args()))
+    /// });
+    /// ```
+    pub fn set_bold(&mut self, yes: bool) -> &mut Style {
+        self.spec.set_bold(yes);
+        self
+    }
+
+    /// Set the text intensity.
+    ///
+    /// If `yes` is true then text will be written in a brighter color.
+    /// If `yes` is false then text will be written in the default color.
+    ///
+    /// # Examples
+    ///
+    /// Create a style with intense text:
+    ///
+    /// ```
+    /// use std::io::Write;
+    ///
+    /// let mut builder = env_logger::Builder::new();
+    ///
+    /// builder.format(|buf, record| {
+    ///     let mut style = buf.style();
+    ///
+    ///     style.set_intense(true);
+    ///
+    ///     writeln!(buf, "{}", style.value(record.args()))
+    /// });
+    /// ```
+    pub fn set_intense(&mut self, yes: bool) -> &mut Style {
+        self.spec.set_intense(yes);
+        self
+    }
+
+    /// Set the background color.
+    ///
+    /// # Examples
+    ///
+    /// Create a style with a yellow background:
+    ///
+    /// ```
+    /// use std::io::Write;
+    /// use env_logger::fmt::Color;
+    ///
+    /// let mut builder = env_logger::Builder::new();
+    ///
+    /// builder.format(|buf, record| {
+    ///     let mut style = buf.style();
+    ///
+    ///     style.set_bg(Color::Yellow);
+    ///
+    ///     writeln!(buf, "{}", style.value(record.args()))
+    /// });
+    /// ```
+    pub fn set_bg(&mut self, color: Color) -> &mut Style {
+        self.spec.set_bg(color.into_termcolor());
+        self
+    }
+
+    /// Wrap a value in the style.
+    ///
+    /// The same `Style` can be used to print multiple different values.
+    ///
+    /// # Examples
+    ///
+    /// Create a bold, red colored style and use it to print the log level:
+    ///
+    /// ```
+    /// use std::io::Write;
+    /// use env_logger::fmt::Color;
+    ///
+    /// let mut builder = env_logger::Builder::new();
+    ///
+    /// builder.format(|buf, record| {
+    ///     let mut style = buf.style();
+    ///
+    ///     style.set_color(Color::Red).set_bold(true);
+    ///
+    ///     writeln!(buf, "{}: {}",
+    ///         style.value(record.level()),
+    ///         record.args())
+    /// });
+    /// ```
+    pub fn value<T>(&self, value: T) -> StyledValue<T> {
+        StyledValue {
+            style: Cow::Borrowed(self),
+            value,
+        }
+    }
+
+    /// Wrap a value in the style by taking ownership of it.
+    pub(crate) fn into_value<T>(&mut self, value: T) -> StyledValue<'static, T> {
+        StyledValue {
+            style: Cow::Owned(self.clone()),
+            value,
+        }
+    }
+}
+
+impl<'a, T> StyledValue<'a, T> {
+    fn write_fmt<F>(&self, f: F) -> fmt::Result
+    where
+        F: FnOnce() -> fmt::Result,
+    {
+        self.style
+            .buf
+            .borrow_mut()
+            .set_color(&self.style.spec)
+            .map_err(|_| fmt::Error)?;
+
+        // Always try to reset the terminal style, even if writing failed
+        let write = f();
+        let reset = self.style.buf.borrow_mut().reset().map_err(|_| fmt::Error);
+
+        write.and(reset)
+    }
+}
+
+impl fmt::Debug for Style {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Style").field("spec", &self.spec).finish()
+    }
+}
+
+macro_rules! impl_styled_value_fmt {
+    ($($fmt_trait:path),*) => {
+        $(
+            impl<'a, T: $fmt_trait> $fmt_trait for StyledValue<'a, T> {
+                fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
+                    self.write_fmt(|| T::fmt(&self.value, f))
+                }
+            }
+        )*
+    };
+}
+
+impl_styled_value_fmt!(
+    fmt::Debug,
+    fmt::Display,
+    fmt::Pointer,
+    fmt::Octal,
+    fmt::Binary,
+    fmt::UpperHex,
+    fmt::LowerHex,
+    fmt::UpperExp,
+    fmt::LowerExp
+);
+
+// The `Color` type is copied from https://github.com/BurntSushi/ripgrep/tree/master/termcolor
+
+/// The set of available colors for the terminal foreground/background.
+///
+/// The `Ansi256` and `Rgb` colors will only output the correct codes when
+/// paired with the `Ansi` `WriteColor` implementation.
+///
+/// The `Ansi256` and `Rgb` color types are not supported when writing colors
+/// on Windows using the console. If they are used on Windows, then they are
+/// silently ignored and no colors will be emitted.
+///
+/// This set may expand over time.
+///
+/// This type has a `FromStr` impl that can parse colors from their human
+/// readable form. The format is as follows:
+///
+/// 1. Any of the explicitly listed colors in English. They are matched
+///    case insensitively.
+/// 2. A single 8-bit integer, in either decimal or hexadecimal format.
+/// 3. A triple of 8-bit integers separated by a comma, where each integer is
+///    in decimal or hexadecimal format.
+///
+/// Hexadecimal numbers are written with a `0x` prefix.
+#[allow(missing_docs)]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum Color {
+    Black,
+    Blue,
+    Green,
+    Red,
+    Cyan,
+    Magenta,
+    Yellow,
+    White,
+    Ansi256(u8),
+    Rgb(u8, u8, u8),
+    #[doc(hidden)]
+    __Nonexhaustive,
+}
+
+impl Color {
+    fn into_termcolor(self) -> Option<termcolor::Color> {
+        match self {
+            Color::Black => Some(termcolor::Color::Black),
+            Color::Blue => Some(termcolor::Color::Blue),
+            Color::Green => Some(termcolor::Color::Green),
+            Color::Red => Some(termcolor::Color::Red),
+            Color::Cyan => Some(termcolor::Color::Cyan),
+            Color::Magenta => Some(termcolor::Color::Magenta),
+            Color::Yellow => Some(termcolor::Color::Yellow),
+            Color::White => Some(termcolor::Color::White),
+            Color::Ansi256(value) => Some(termcolor::Color::Ansi256(value)),
+            Color::Rgb(r, g, b) => Some(termcolor::Color::Rgb(r, g, b)),
+            _ => None,
+        }
+    }
+}
diff --git a/src/fmt/writer/termcolor/mod.rs b/src/fmt/writer/termcolor/mod.rs
new file mode 100644
index 0000000..f3e6768
--- /dev/null
+++ b/src/fmt/writer/termcolor/mod.rs
@@ -0,0 +1,12 @@
+/*
+This internal module contains the style and terminal writing implementation.
+
+Its public API is available when the `termcolor` crate is available.
+The terminal printing is shimmed when the `termcolor` crate is not available.
+*/
+
+#[cfg_attr(feature = "termcolor", path = "extern_impl.rs")]
+#[cfg_attr(not(feature = "termcolor"), path = "shim_impl.rs")]
+mod imp;
+
+pub(in crate::fmt) use self::imp::*;
diff --git a/src/fmt/writer/termcolor/shim_impl.rs b/src/fmt/writer/termcolor/shim_impl.rs
new file mode 100644
index 0000000..563f8ad
--- /dev/null
+++ b/src/fmt/writer/termcolor/shim_impl.rs
@@ -0,0 +1,63 @@
+use std::io;
+
+use crate::fmt::{Target, WriteStyle};
+
+pub(in crate::fmt::writer) mod glob {}
+
+pub(in crate::fmt::writer) struct BufferWriter {
+    target: Target,
+}
+
+pub(in crate::fmt) struct Buffer(Vec<u8>);
+
+impl BufferWriter {
+    pub(in crate::fmt::writer) fn stderr(_is_test: bool, _write_style: WriteStyle) -> Self {
+        BufferWriter {
+            target: Target::Stderr,
+        }
+    }
+
+    pub(in crate::fmt::writer) fn stdout(_is_test: bool, _write_style: WriteStyle) -> Self {
+        BufferWriter {
+            target: Target::Stdout,
+        }
+    }
+
+    pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
+        Buffer(Vec::new())
+    }
+
+    pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
+        // This impl uses the `eprint` and `print` macros
+        // instead of using the streams directly.
+        // This is so their output can be captured by `cargo test`
+        let log = String::from_utf8_lossy(&buf.0);
+
+        match self.target {
+            Target::Stderr => eprint!("{}", log),
+            Target::Stdout => print!("{}", log),
+        }
+
+        Ok(())
+    }
+}
+
+impl Buffer {
+    pub(in crate::fmt) fn clear(&mut self) {
+        self.0.clear();
+    }
+
+    pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.extend(buf);
+        Ok(buf.len())
+    }
+
+    pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+
+    #[cfg(test)]
+    pub(in crate::fmt) fn bytes(&self) -> &[u8] {
+        &self.0
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..4151836
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,1177 @@
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// 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].
+//!
+//! ## Example
+//!
+//! ```
+//! #[macro_use] extern crate log;
+//!
+//! use log::Level;
+//!
+//! fn main() {
+//!     env_logger::init();
+//!
+//!     debug!("this is a debug {}", "message");
+//!     error!("this is printed by default");
+//!
+//!     if log_enabled!(Level::Info) {
+//!         let x = 3 * 4; // expensive computation
+//!         info!("the answer was: {}", x);
+//!     }
+//! }
+//! ```
+//!
+//! Assumes the binary is `main`:
+//!
+//! ```{.bash}
+//! $ RUST_LOG=error ./main
+//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
+//! ```
+//!
+//! ```{.bash}
+//! $ RUST_LOG=info ./main
+//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
+//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
+//! ```
+//!
+//! ```{.bash}
+//! $ RUST_LOG=debug ./main
+//! [2017-11-09T02:12:24Z DEBUG main] this is a debug message
+//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
+//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
+//! ```
+//!
+//! You can also set the log level on a per module basis:
+//!
+//! ```{.bash}
+//! $ RUST_LOG=main=info ./main
+//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
+//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
+//! ```
+//!
+//! And enable all logging:
+//!
+//! ```{.bash}
+//! $ RUST_LOG=main ./main
+//! [2017-11-09T02:12:24Z DEBUG main] this is a debug message
+//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
+//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
+//! ```
+//!
+//! If the binary name contains hyphens, you will need to replace
+//! them with underscores:
+//!
+//! ```{.bash}
+//! $ RUST_LOG=my_app ./my-app
+//! [2017-11-09T02:12:24Z DEBUG my_app] this is a debug message
+//! [2017-11-09T02:12:24Z ERROR my_app] this is printed by default
+//! [2017-11-09T02:12:24Z INFO my_app] the answer was: 12
+//! ```
+//!
+//! This is because Rust modules and crates cannot contain hyphens
+//! in their name, although `cargo` continues to accept them.
+//!
+//! See the documentation for the [`log` crate][log-crate-url] for more
+//! information about its API.
+//!
+//! ## 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:
+//!
+//! ```text
+//! path::to::module=level
+//! ```
+//!
+//! The path to the module is rooted in the name of the crate it was compiled
+//! for, so if your program is contained in a file `hello.rs`, for example, to
+//! turn on logging for this file you would use a value of `RUST_LOG=hello`.
+//! 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`.
+//!
+//! 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.
+//!
+//! Some examples of valid values of `RUST_LOG` are:
+//!
+//! * `hello` turns on all logging for the 'hello' module
+//! * `info` turns on all info logging
+//! * `hello=debug` turns on debug logging for 'hello'
+//! * `hello,std::option` turns on hello, and std's option logging
+//! * `error,hello=warn` turn on global error logging and also warn for hello
+//!
+//! ## Filtering results
+//!
+//! A `RUST_LOG` directive may include a regex filter. The syntax is to append `/`
+//! followed by a regex. Each message is checked against the regex, and is only
+//! logged if it matches. Note that the matching is done after formatting the
+//! log string but before adding any logging meta-data. There is a single filter
+//! for all modules.
+//!
+//! Some examples:
+//!
+//! * `hello/foo` turns on all logging for the 'hello' module where the log
+//!   message includes 'foo'.
+//! * `info/f.o` turns on all info logging where the log message includes 'foo',
+//!   'f1o', 'fao', etc.
+//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log
+//!   message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc.
+//! * `error,hello=warn/[0-9]scopes` turn on global error logging and also
+//!   warn for hello. In both cases the log message must include a single digit
+//!   number followed by 'scopes'.
+//!
+//! ## Capturing logs in tests
+//!
+//! Records logged during `cargo test` will not be captured by the test harness by default.
+//! The [`Builder::is_test`] method can be used in unit tests to ensure logs will be captured:
+//!
+//! ```
+//! # #[macro_use] extern crate log;
+//! # fn main() {}
+//! #[cfg(test)]
+//! mod tests {
+//!     fn init() {
+//!         let _ = env_logger::builder().is_test(true).try_init();
+//!     }
+//!
+//!     #[test]
+//!     fn it_works() {
+//!         init();
+//!
+//!         info!("This record will be captured by `cargo test`");
+//!
+//!         assert_eq!(2, 1 + 1);
+//!     }
+//! }
+//! ```
+//!
+//! Enabling test capturing comes at the expense of color and other style support
+//! and may have performance implications.
+//!
+//! ## Disabling colors
+//!
+//! Colors and other styles can be configured with the `RUST_LOG_STYLE`
+//! environment variable. It accepts the following values:
+//!
+//! * `auto` (default) will attempt to print style characters, but don't force the issue.
+//! If the console isn't available on Windows, or if TERM=dumb, for example, then don't print colors.
+//! * `always` will always print style characters even if they aren't supported by the terminal.
+//! This includes emitting ANSI colors on Windows if the console API is unavailable.
+//! * `never` will never print style characters.
+//!
+//! ## Tweaking the default format
+//!
+//! Parts of the default format can be excluded from the log output using the [`Builder`].
+//! The following example excludes the timestamp from the log output:
+//!
+//! ```
+//! env_logger::builder()
+//!     .format_timestamp(None)
+//!     .init();
+//! ```
+//!
+//! ### Stability of the default format
+//!
+//! The default format won't optimise for long-term stability, and explicitly makes no
+//! guarantees about the stability of its output across major, minor or patch version
+//! bumps during `0.x`.
+//!
+//! If you want to capture or interpret the output of `env_logger` programmatically
+//! then you should use a custom format.
+//!
+//! ### Using a custom format
+//!
+//! Custom formats can be provided as closures to the [`Builder`].
+//! These closures take a [`Formatter`] and `log::Record` as arguments:
+//!
+//! ```
+//! use std::io::Write;
+//!
+//! env_logger::builder()
+//!     .format(|buf, record| {
+//!         writeln!(buf, "{}: {}", record.level(), record.args())
+//!     })
+//!     .init();
+//! ```
+//!
+//! See the [`fmt`] module for more details about custom formats.
+//!
+//! ## Specifying defaults for environment variables
+//!
+//! `env_logger` can read configuration from environment variables.
+//! If these variables aren't present, the default value to use can be tweaked with the [`Env`] type.
+//! The following example defaults to log `warn` and above if the `RUST_LOG` environment variable
+//! isn't set:
+//!
+//! ```
+//! use env_logger::Env;
+//!
+//! env_logger::from_env(Env::default().default_filter_or("warn")).init();
+//! ```
+//!
+//! [log-crate-url]: https://docs.rs/log/
+//! [`Builder`]: struct.Builder.html
+//! [`Builder::is_test`]: struct.Builder.html#method.is_test
+//! [`Env`]: struct.Env.html
+//! [`fmt`]: fmt/index.html
+
+#![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.7.1"
+)]
+#![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)]
+
+use std::{borrow::Cow, cell::RefCell, env, io};
+
+use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
+
+pub mod filter;
+pub mod fmt;
+
+pub use self::fmt::glob::*;
+
+use self::filter::Filter;
+use self::fmt::writer::{self, Writer};
+use self::fmt::Formatter;
+
+/// The default name for the environment variable to read filters from.
+pub const DEFAULT_FILTER_ENV: &'static str = "RUST_LOG";
+
+/// The default name for the environment variable to read style preferences from.
+pub const DEFAULT_WRITE_STYLE_ENV: &'static str = "RUST_LOG_STYLE";
+
+/// Set of environment variables to configure from.
+///
+/// # Default environment variables
+///
+/// By default, the `Env` will read the following environment variables:
+///
+/// - `RUST_LOG`: the level filter
+/// - `RUST_LOG_STYLE`: whether or not to print styles with records.
+///
+/// These sources can be configured using the builder methods on `Env`.
+#[derive(Debug)]
+pub struct Env<'a> {
+    filter: Var<'a>,
+    write_style: Var<'a>,
+}
+
+#[derive(Debug)]
+struct Var<'a> {
+    name: Cow<'a, str>,
+    default: Option<Cow<'a, str>>,
+}
+
+/// The env logger.
+///
+/// This struct implements the `Log` trait from the [`log` crate][log-crate-url],
+/// which allows it to act as a logger.
+///
+/// The [`init()`], [`try_init()`], [`Builder::init()`] and [`Builder::try_init()`]
+/// methods will each construct a `Logger` and immediately initialize it as the
+/// default global logger.
+///
+/// If you'd instead need access to the constructed `Logger`, you can use
+/// the associated [`Builder`] and install it with the
+/// [`log` crate][log-crate-url] directly.
+///
+/// [log-crate-url]: https://docs.rs/log/
+/// [`init()`]: fn.init.html
+/// [`try_init()`]: fn.try_init.html
+/// [`Builder::init()`]: struct.Builder.html#method.init
+/// [`Builder::try_init()`]: struct.Builder.html#method.try_init
+/// [`Builder`]: struct.Builder.html
+pub struct Logger {
+    writer: Writer,
+    filter: Filter,
+    #[allow(unknown_lints, bare_trait_objects)]
+    format: Box<Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>,
+}
+
+/// `Builder` acts as builder for initializing a `Logger`.
+///
+/// It can be used to customize the log format, change the environment variable used
+/// to provide the logging directives and also set the default log level filter.
+///
+/// # Examples
+///
+/// ```
+/// #[macro_use] extern crate log;
+///
+/// use std::env;
+/// use std::io::Write;
+/// use log::LevelFilter;
+/// use env_logger::Builder;
+///
+/// fn main() {
+///     let mut builder = Builder::from_default_env();
+///
+///     builder.format(|buf, record| writeln!(buf, "{} - {}", record.level(), record.args()))
+///            .filter(None, LevelFilter::Info)
+///            .init();
+///
+///     error!("error message");
+///     info!("info message");
+/// }
+/// ```
+#[derive(Default)]
+pub struct Builder {
+    filter: filter::Builder,
+    writer: writer::Builder,
+    format: fmt::Builder,
+    built: bool,
+}
+
+impl Builder {
+    /// Initializes the log builder with defaults.
+    ///
+    /// **NOTE:** This method won't read from any environment variables.
+    /// Use the [`filter`] and [`write_style`] methods to configure the builder
+    /// or use [`from_env`] or [`from_default_env`] instead.
+    ///
+    /// # Examples
+    ///
+    /// Create a new builder and configure filters and style:
+    ///
+    /// ```
+    /// # fn main() {
+    /// use log::LevelFilter;
+    /// use env_logger::{Builder, WriteStyle};
+    ///
+    /// let mut builder = Builder::new();
+    ///
+    /// builder.filter(None, LevelFilter::Info)
+    ///        .write_style(WriteStyle::Always)
+    ///        .init();
+    /// # }
+    /// ```
+    ///
+    /// [`filter`]: #method.filter
+    /// [`write_style`]: #method.write_style
+    /// [`from_env`]: #method.from_env
+    /// [`from_default_env`]: #method.from_default_env
+    pub fn new() -> Builder {
+        Default::default()
+    }
+
+    /// Initializes the log builder from the environment.
+    ///
+    /// The variables used to read configuration from can be tweaked before
+    /// passing in.
+    ///
+    /// # Examples
+    ///
+    /// Initialise a logger reading the log filter from an environment variable
+    /// called `MY_LOG`:
+    ///
+    /// ```
+    /// use env_logger::Builder;
+    ///
+    /// let mut builder = Builder::from_env("MY_LOG");
+    /// builder.init();
+    /// ```
+    ///
+    /// Initialise a logger using the `MY_LOG` variable for filtering and
+    /// `MY_LOG_STYLE` for whether or not to write styles:
+    ///
+    /// ```
+    /// use env_logger::{Builder, Env};
+    ///
+    /// let env = Env::new().filter("MY_LOG").write_style("MY_LOG_STYLE");
+    ///
+    /// let mut builder = Builder::from_env(env);
+    /// builder.init();
+    /// ```
+    pub fn from_env<'a, E>(env: E) -> Self
+    where
+        E: Into<Env<'a>>,
+    {
+        let mut builder = Builder::new();
+        let env = env.into();
+
+        if let Some(s) = env.get_filter() {
+            builder.parse_filters(&s);
+        }
+
+        if let Some(s) = env.get_write_style() {
+            builder.parse_write_style(&s);
+        }
+
+        builder
+    }
+
+    /// Initializes the log builder from the environment using default variable names.
+    ///
+    /// This method is a convenient way to call `from_env(Env::default())` without
+    /// having to use the `Env` type explicitly. The builder will use the
+    /// [default environment variables].
+    ///
+    /// # Examples
+    ///
+    /// Initialise a logger using the default environment variables:
+    ///
+    /// ```
+    /// use env_logger::Builder;
+    ///
+    /// let mut builder = Builder::from_default_env();
+    /// builder.init();
+    /// ```
+    ///
+    /// [default environment variables]: struct.Env.html#default-environment-variables
+    pub fn from_default_env() -> Self {
+        Self::from_env(Env::default())
+    }
+
+    /// Sets the format function for formatting the log output.
+    ///
+    /// This function is called on each record logged and should format the
+    /// log record and output it to the given [`Formatter`].
+    ///
+    /// The format function is expected to output the string directly to the
+    /// `Formatter` so that implementations can use the [`std::fmt`] macros
+    /// to format and output without intermediate heap allocations. The default
+    /// `env_logger` formatter takes advantage of this.
+    ///
+    /// # Examples
+    ///
+    /// Use a custom format to write only the log message:
+    ///
+    /// ```
+    /// use std::io::Write;
+    /// use env_logger::Builder;
+    ///
+    /// let mut builder = Builder::new();
+    ///
+    /// builder.format(|buf, record| writeln!(buf, "{}", record.args()));
+    /// ```
+    ///
+    /// [`Formatter`]: fmt/struct.Formatter.html
+    /// [`String`]: https://doc.rust-lang.org/stable/std/string/struct.String.html
+    /// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html
+    pub fn format<F: 'static>(&mut self, format: F) -> &mut Self
+    where
+        F: Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send,
+    {
+        self.format.custom_format = Some(Box::new(format));
+        self
+    }
+
+    /// Use the default format.
+    ///
+    /// This method will clear any custom format set on the builder.
+    pub fn default_format(&mut self) -> &mut Self {
+        self.format = Default::default();
+        self
+    }
+
+    /// Whether or not to write the level in the default format.
+    pub fn format_level(&mut self, write: bool) -> &mut Self {
+        self.format.format_level = write;
+        self
+    }
+
+    /// Whether or not to write the module path in the default format.
+    pub fn format_module_path(&mut self, write: bool) -> &mut Self {
+        self.format.format_module_path = write;
+        self
+    }
+
+    /// Configures the amount of spaces to use to indent multiline log records.
+    /// A value of `None` disables any kind of indentation.
+    pub fn format_indent(&mut self, indent: Option<usize>) -> &mut Self {
+        self.format.format_indent = indent;
+        self
+    }
+
+    /// Configures if timestamp should be included and in what precision.
+    pub fn format_timestamp(&mut self, timestamp: Option<fmt::TimestampPrecision>) -> &mut Self {
+        self.format.format_timestamp = timestamp;
+        self
+    }
+
+    /// Configures the timestamp to use second precision.
+    pub fn format_timestamp_secs(&mut self) -> &mut Self {
+        self.format_timestamp(Some(fmt::TimestampPrecision::Seconds))
+    }
+
+    /// Configures the timestamp to use millisecond precision.
+    pub fn format_timestamp_millis(&mut self) -> &mut Self {
+        self.format_timestamp(Some(fmt::TimestampPrecision::Millis))
+    }
+
+    /// Configures the timestamp to use microsecond precision.
+    pub fn format_timestamp_micros(&mut self) -> &mut Self {
+        self.format_timestamp(Some(fmt::TimestampPrecision::Micros))
+    }
+
+    /// Configures the timestamp to use nanosecond precision.
+    pub fn format_timestamp_nanos(&mut self) -> &mut Self {
+        self.format_timestamp(Some(fmt::TimestampPrecision::Nanos))
+    }
+
+    /// Adds a directive to the filter for a specific module.
+    ///
+    /// # Examples
+    ///
+    /// Only include messages for warning and above for logs in `path::to::module`:
+    ///
+    /// ```
+    /// # fn main() {
+    /// use log::LevelFilter;
+    /// use env_logger::Builder;
+    ///
+    /// let mut builder = Builder::new();
+    ///
+    /// builder.filter_module("path::to::module", LevelFilter::Info);
+    /// # }
+    /// ```
+    pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self {
+        self.filter.filter_module(module, level);
+        self
+    }
+
+    /// Adds a directive to the filter for all modules.
+    ///
+    /// # Examples
+    ///
+    /// Only include messages for warning and above for logs in `path::to::module`:
+    ///
+    /// ```
+    /// # fn main() {
+    /// use log::LevelFilter;
+    /// use env_logger::Builder;
+    ///
+    /// let mut builder = Builder::new();
+    ///
+    /// builder.filter_level(LevelFilter::Info);
+    /// # }
+    /// ```
+    pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self {
+        self.filter.filter_level(level);
+        self
+    }
+
+    /// Adds filters to the logger.
+    ///
+    /// The given module (if any) will log at most the specified level provided.
+    /// If no module is provided then the filter will apply to all log messages.
+    ///
+    /// # Examples
+    ///
+    /// Only include messages for warning and above for logs in `path::to::module`:
+    ///
+    /// ```
+    /// # fn main() {
+    /// use log::LevelFilter;
+    /// use env_logger::Builder;
+    ///
+    /// let mut builder = Builder::new();
+    ///
+    /// builder.filter(Some("path::to::module"), LevelFilter::Info);
+    /// # }
+    /// ```
+    pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self {
+        self.filter.filter(module, level);
+        self
+    }
+
+    /// Parses the directives string in the same form as the `RUST_LOG`
+    /// environment variable.
+    ///
+    /// See the module documentation for more details.
+    pub fn parse_filters(&mut self, filters: &str) -> &mut Self {
+        self.filter.parse(filters);
+        self
+    }
+
+    /// Sets the target for the log output.
+    ///
+    /// Env logger can log to either stdout or stderr. The default is stderr.
+    ///
+    /// # Examples
+    ///
+    /// Write log message to `stdout`:
+    ///
+    /// ```
+    /// use env_logger::{Builder, Target};
+    ///
+    /// let mut builder = Builder::new();
+    ///
+    /// builder.target(Target::Stdout);
+    /// ```
+    pub fn target(&mut self, target: fmt::Target) -> &mut Self {
+        self.writer.target(target);
+        self
+    }
+
+    /// Sets whether or not styles will be written.
+    ///
+    /// This can be useful in environments that don't support control characters
+    /// for setting colors.
+    ///
+    /// # Examples
+    ///
+    /// Never attempt to write styles:
+    ///
+    /// ```
+    /// use env_logger::{Builder, WriteStyle};
+    ///
+    /// let mut builder = Builder::new();
+    ///
+    /// builder.write_style(WriteStyle::Never);
+    /// ```
+    pub fn write_style(&mut self, write_style: fmt::WriteStyle) -> &mut Self {
+        self.writer.write_style(write_style);
+        self
+    }
+
+    /// Parses whether or not to write styles in the same form as the `RUST_LOG_STYLE`
+    /// environment variable.
+    ///
+    /// See the module documentation for more details.
+    pub fn parse_write_style(&mut self, write_style: &str) -> &mut Self {
+        self.writer.parse_write_style(write_style);
+        self
+    }
+
+    /// Sets whether or not the logger will be used in unit tests.
+    ///
+    /// If `is_test` is `true` then the logger will allow the testing framework to
+    /// capture log records rather than printing them to the terminal directly.
+    pub fn is_test(&mut self, is_test: bool) -> &mut Self {
+        self.writer.is_test(is_test);
+        self
+    }
+
+    /// Initializes the global logger with the built env logger.
+    ///
+    /// This should be called early in the execution of a Rust program. Any log
+    /// events that occur before initialization will be ignored.
+    ///
+    /// # Errors
+    ///
+    /// This function will fail if it is called more than once, or if another
+    /// library has already initialized a global logger.
+    pub fn try_init(&mut self) -> Result<(), SetLoggerError> {
+        let logger = self.build();
+
+        let max_level = logger.filter();
+        let r = log::set_boxed_logger(Box::new(logger));
+
+        if r.is_ok() {
+            log::set_max_level(max_level);
+        }
+
+        r
+    }
+
+    /// Initializes the global logger with the built env logger.
+    ///
+    /// This should be called early in the execution of a Rust program. Any log
+    /// events that occur before initialization will be ignored.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if it is called more than once, or if another
+    /// library has already initialized a global logger.
+    pub fn init(&mut self) {
+        self.try_init()
+            .expect("Builder::init should not be called after logger initialized");
+    }
+
+    /// Build an env logger.
+    ///
+    /// The returned logger implements the `Log` trait and can be installed manually
+    /// or nested within another logger.
+    pub fn build(&mut self) -> Logger {
+        assert!(!self.built, "attempt to re-use consumed builder");
+        self.built = true;
+
+        Logger {
+            writer: self.writer.build(),
+            filter: self.filter.build(),
+            format: self.format.build(),
+        }
+    }
+}
+
+impl Logger {
+    /// Creates the logger from the environment.
+    ///
+    /// The variables used to read configuration from can be tweaked before
+    /// passing in.
+    ///
+    /// # Examples
+    ///
+    /// Create a logger reading the log filter from an environment variable
+    /// called `MY_LOG`:
+    ///
+    /// ```
+    /// use env_logger::Logger;
+    ///
+    /// let logger = Logger::from_env("MY_LOG");
+    /// ```
+    ///
+    /// Create a logger using the `MY_LOG` variable for filtering and
+    /// `MY_LOG_STYLE` for whether or not to write styles:
+    ///
+    /// ```
+    /// use env_logger::{Logger, Env};
+    ///
+    /// let env = Env::new().filter_or("MY_LOG", "info").write_style_or("MY_LOG_STYLE", "always");
+    ///
+    /// let logger = Logger::from_env(env);
+    /// ```
+    pub fn from_env<'a, E>(env: E) -> Self
+    where
+        E: Into<Env<'a>>,
+    {
+        Builder::from_env(env).build()
+    }
+
+    /// Creates the logger from the environment using default variable names.
+    ///
+    /// This method is a convenient way to call `from_env(Env::default())` without
+    /// having to use the `Env` type explicitly. The logger will use the
+    /// [default environment variables].
+    ///
+    /// # Examples
+    ///
+    /// Creates a logger using the default environment variables:
+    ///
+    /// ```
+    /// use env_logger::Logger;
+    ///
+    /// let logger = Logger::from_default_env();
+    /// ```
+    ///
+    /// [default environment variables]: struct.Env.html#default-environment-variables
+    pub fn from_default_env() -> Self {
+        Builder::from_default_env().build()
+    }
+
+    /// Returns the maximum `LevelFilter` that this env logger instance is
+    /// configured to output.
+    pub fn filter(&self) -> LevelFilter {
+        self.filter.filter()
+    }
+
+    /// Checks if this record matches the configured filter.
+    pub fn matches(&self, record: &Record) -> bool {
+        self.filter.matches(record)
+    }
+}
+
+impl Log for Logger {
+    fn enabled(&self, metadata: &Metadata) -> bool {
+        self.filter.enabled(metadata)
+    }
+
+    fn log(&self, record: &Record) {
+        if self.matches(record) {
+            // Log records are written to a thread-local buffer before being printed
+            // to the terminal. We clear these buffers afterwards, but they aren't shrinked
+            // so will always at least have capacity for the largest log record formatted
+            // on that thread.
+            //
+            // If multiple `Logger`s are used by the same threads then the thread-local
+            // formatter might have different color support. If this is the case the
+            // formatter and its buffer are discarded and recreated.
+
+            thread_local! {
+                static FORMATTER: RefCell<Option<Formatter>> = RefCell::new(None);
+            }
+
+            let print = |formatter: &mut Formatter, record: &Record| {
+                let _ =
+                    (self.format)(formatter, record).and_then(|_| formatter.print(&self.writer));
+
+                // Always clear the buffer afterwards
+                formatter.clear();
+            };
+
+            let printed = FORMATTER
+                .try_with(|tl_buf| {
+                    match tl_buf.try_borrow_mut() {
+                        // There are no active borrows of the buffer
+                        Ok(mut tl_buf) => match *tl_buf {
+                            // We have a previously set formatter
+                            Some(ref mut formatter) => {
+                                // Check the buffer style. If it's different from the logger's
+                                // style then drop the buffer and recreate it.
+                                if formatter.write_style() != self.writer.write_style() {
+                                    *formatter = Formatter::new(&self.writer);
+                                }
+
+                                print(formatter, record);
+                            }
+                            // We don't have a previously set formatter
+                            None => {
+                                let mut formatter = Formatter::new(&self.writer);
+                                print(&mut formatter, record);
+
+                                *tl_buf = Some(formatter);
+                            }
+                        },
+                        // There's already an active borrow of the buffer (due to re-entrancy)
+                        Err(_) => {
+                            print(&mut Formatter::new(&self.writer), record);
+                        }
+                    }
+                })
+                .is_ok();
+
+            if !printed {
+                // The thread-local storage was not available (because its
+                // destructor has already run). Create a new single-use
+                // Formatter on the stack for this call.
+                print(&mut Formatter::new(&self.writer), record);
+            }
+        }
+    }
+
+    fn flush(&self) {}
+}
+
+impl<'a> Env<'a> {
+    /// Get a default set of environment variables.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Specify an environment variable to read the filter from.
+    pub fn filter<E>(mut self, filter_env: E) -> Self
+    where
+        E: Into<Cow<'a, str>>,
+    {
+        self.filter = Var::new(filter_env);
+
+        self
+    }
+
+    /// Specify an environment variable to read the filter from.
+    ///
+    /// If the variable is not set, the default value will be used.
+    pub fn filter_or<E, V>(mut self, filter_env: E, default: V) -> Self
+    where
+        E: Into<Cow<'a, str>>,
+        V: Into<Cow<'a, str>>,
+    {
+        self.filter = Var::new_with_default(filter_env, default);
+
+        self
+    }
+
+    /// Use the default environment variable to read the filter from.
+    ///
+    /// If the variable is not set, the default value will be used.
+    pub fn default_filter_or<V>(mut self, default: V) -> Self
+    where
+        V: Into<Cow<'a, str>>,
+    {
+        self.filter = Var::new_with_default(DEFAULT_FILTER_ENV, default);
+
+        self
+    }
+
+    fn get_filter(&self) -> Option<String> {
+        self.filter.get()
+    }
+
+    /// Specify an environment variable to read the style from.
+    pub fn write_style<E>(mut self, write_style_env: E) -> Self
+    where
+        E: Into<Cow<'a, str>>,
+    {
+        self.write_style = Var::new(write_style_env);
+
+        self
+    }
+
+    /// Specify an environment variable to read the style from.
+    ///
+    /// If the variable is not set, the default value will be used.
+    pub fn write_style_or<E, V>(mut self, write_style_env: E, default: V) -> Self
+    where
+        E: Into<Cow<'a, str>>,
+        V: Into<Cow<'a, str>>,
+    {
+        self.write_style = Var::new_with_default(write_style_env, default);
+
+        self
+    }
+
+    /// Use the default environment variable to read the style from.
+    ///
+    /// If the variable is not set, the default value will be used.
+    pub fn default_write_style_or<V>(mut self, default: V) -> Self
+    where
+        V: Into<Cow<'a, str>>,
+    {
+        self.write_style = Var::new_with_default(DEFAULT_WRITE_STYLE_ENV, default);
+
+        self
+    }
+
+    fn get_write_style(&self) -> Option<String> {
+        self.write_style.get()
+    }
+}
+
+impl<'a> Var<'a> {
+    fn new<E>(name: E) -> Self
+    where
+        E: Into<Cow<'a, str>>,
+    {
+        Var {
+            name: name.into(),
+            default: None,
+        }
+    }
+
+    fn new_with_default<E, V>(name: E, default: V) -> Self
+    where
+        E: Into<Cow<'a, str>>,
+        V: Into<Cow<'a, str>>,
+    {
+        Var {
+            name: name.into(),
+            default: Some(default.into()),
+        }
+    }
+
+    fn get(&self) -> Option<String> {
+        env::var(&*self.name)
+            .ok()
+            .or_else(|| self.default.to_owned().map(|v| v.into_owned()))
+    }
+}
+
+impl<'a, T> From<T> for Env<'a>
+where
+    T: Into<Cow<'a, str>>,
+{
+    fn from(filter_env: T) -> Self {
+        Env::default().filter(filter_env.into())
+    }
+}
+
+impl<'a> Default for Env<'a> {
+    fn default() -> Self {
+        Env {
+            filter: Var::new(DEFAULT_FILTER_ENV),
+            write_style: Var::new(DEFAULT_WRITE_STYLE_ENV),
+        }
+    }
+}
+
+mod std_fmt_impls {
+    use super::*;
+    use std::fmt;
+
+    impl fmt::Debug for Logger {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            f.debug_struct("Logger")
+                .field("filter", &self.filter)
+                .finish()
+        }
+    }
+
+    impl fmt::Debug for Builder {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            if self.built {
+                f.debug_struct("Logger").field("built", &true).finish()
+            } else {
+                f.debug_struct("Logger")
+                    .field("filter", &self.filter)
+                    .field("writer", &self.writer)
+                    .finish()
+            }
+        }
+    }
+}
+
+/// Attempts to initialize the global logger with an env logger.
+///
+/// This should be called early in the execution of a Rust program. Any log
+/// events that occur before initialization will be ignored.
+///
+/// # Errors
+///
+/// This function will fail if it is called more than once, or if another
+/// library has already initialized a global logger.
+pub fn try_init() -> Result<(), SetLoggerError> {
+    try_init_from_env(Env::default())
+}
+
+/// Initializes the global logger with an env logger.
+///
+/// This should be called early in the execution of a Rust program. Any log
+/// events that occur before initialization will be ignored.
+///
+/// # Panics
+///
+/// This function will panic if it is called more than once, or if another
+/// library has already initialized a global logger.
+pub fn init() {
+    try_init().expect("env_logger::init should not be called after logger initialized");
+}
+
+/// Attempts to initialize the global logger with an env logger from the given
+/// environment variables.
+///
+/// This should be called early in the execution of a Rust program. Any log
+/// events that occur before initialization will be ignored.
+///
+/// # Examples
+///
+/// Initialise a logger using the `MY_LOG` environment variable for filters
+/// and `MY_LOG_STYLE` for writing colors:
+///
+/// ```
+/// # extern crate env_logger;
+/// use env_logger::{Builder, Env};
+///
+/// # fn run() -> Result<(), Box<::std::error::Error>> {
+/// let env = Env::new().filter("MY_LOG").write_style("MY_LOG_STYLE");
+///
+/// env_logger::try_init_from_env(env)?;
+///
+/// Ok(())
+/// # }
+/// # fn main() { run().unwrap(); }
+/// ```
+///
+/// # Errors
+///
+/// This function will fail if it is called more than once, or if another
+/// library has already initialized a global logger.
+pub fn try_init_from_env<'a, E>(env: E) -> Result<(), SetLoggerError>
+where
+    E: Into<Env<'a>>,
+{
+    let mut builder = Builder::from_env(env);
+
+    builder.try_init()
+}
+
+/// Initializes the global logger with an env logger from the given environment
+/// variables.
+///
+/// This should be called early in the execution of a Rust program. Any log
+/// events that occur before initialization will be ignored.
+///
+/// # Examples
+///
+/// Initialise a logger using the `MY_LOG` environment variable for filters
+/// and `MY_LOG_STYLE` for writing colors:
+///
+/// ```
+/// use env_logger::{Builder, Env};
+///
+/// let env = Env::new().filter("MY_LOG").write_style("MY_LOG_STYLE");
+///
+/// env_logger::init_from_env(env);
+/// ```
+///
+/// # Panics
+///
+/// This function will panic if it is called more than once, or if another
+/// library has already initialized a global logger.
+pub fn init_from_env<'a, E>(env: E)
+where
+    E: Into<Env<'a>>,
+{
+    try_init_from_env(env)
+        .expect("env_logger::init_from_env should not be called after logger initialized");
+}
+
+/// Create a new builder with the default environment variables.
+///
+/// The builder can be configured before being initialized.
+pub fn builder() -> Builder {
+    Builder::from_default_env()
+}
+
+/// Create a builder from the given environment variables.
+///
+/// The builder can be configured before being initialized.
+pub fn from_env<'a, E>(env: E) -> Builder
+where
+    E: Into<Env<'a>>,
+{
+    Builder::from_env(env)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn env_get_filter_reads_from_var_if_set() {
+        env::set_var("env_get_filter_reads_from_var_if_set", "from var");
+
+        let env = Env::new().filter_or("env_get_filter_reads_from_var_if_set", "from default");
+
+        assert_eq!(Some("from var".to_owned()), env.get_filter());
+    }
+
+    #[test]
+    fn env_get_filter_reads_from_default_if_var_not_set() {
+        env::remove_var("env_get_filter_reads_from_default_if_var_not_set");
+
+        let env = Env::new().filter_or(
+            "env_get_filter_reads_from_default_if_var_not_set",
+            "from default",
+        );
+
+        assert_eq!(Some("from default".to_owned()), env.get_filter());
+    }
+
+    #[test]
+    fn env_get_write_style_reads_from_var_if_set() {
+        env::set_var("env_get_write_style_reads_from_var_if_set", "from var");
+
+        let env =
+            Env::new().write_style_or("env_get_write_style_reads_from_var_if_set", "from default");
+
+        assert_eq!(Some("from var".to_owned()), env.get_write_style());
+    }
+
+    #[test]
+    fn env_get_write_style_reads_from_default_if_var_not_set() {
+        env::remove_var("env_get_write_style_reads_from_default_if_var_not_set");
+
+        let env = Env::new().write_style_or(
+            "env_get_write_style_reads_from_default_if_var_not_set",
+            "from default",
+        );
+
+        assert_eq!(Some("from default".to_owned()), env.get_write_style());
+    }
+}
diff --git a/tests/init-twice-retains-filter.rs b/tests/init-twice-retains-filter.rs
new file mode 100644
index 0000000..673da3f
--- /dev/null
+++ b/tests/init-twice-retains-filter.rs
@@ -0,0 +1,40 @@
+extern crate env_logger;
+extern crate log;
+
+use std::env;
+use std::process;
+use std::str;
+
+fn main() {
+    if env::var("YOU_ARE_TESTING_NOW").is_ok() {
+        // Init from the env (which should set the max level to `Debug`)
+        env_logger::init();
+
+        assert_eq!(log::LevelFilter::Debug, log::max_level());
+
+        // Init again using a different max level
+        // This shouldn't clobber the level that was previously set
+        env_logger::Builder::new()
+            .parse_filters("info")
+            .try_init()
+            .unwrap_err();
+
+        assert_eq!(log::LevelFilter::Debug, log::max_level());
+        return;
+    }
+
+    let exe = env::current_exe().unwrap();
+    let out = process::Command::new(exe)
+        .env("YOU_ARE_TESTING_NOW", "1")
+        .env("RUST_LOG", "debug")
+        .output()
+        .unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
+    if out.status.success() {
+        return;
+    }
+
+    println!("test failed: {}", out.status);
+    println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap());
+    println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap());
+    process::exit(1);
+}
diff --git a/tests/log-in-log.rs b/tests/log-in-log.rs
new file mode 100644
index 0000000..89517ff
--- /dev/null
+++ b/tests/log-in-log.rs
@@ -0,0 +1,39 @@
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+
+use std::env;
+use std::fmt;
+use std::process;
+use std::str;
+
+struct Foo;
+
+impl fmt::Display for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        info!("test");
+        f.write_str("bar")
+    }
+}
+
+fn main() {
+    env_logger::init();
+    if env::var("YOU_ARE_TESTING_NOW").is_ok() {
+        return info!("{}", Foo);
+    }
+
+    let exe = env::current_exe().unwrap();
+    let out = process::Command::new(exe)
+        .env("YOU_ARE_TESTING_NOW", "1")
+        .env("RUST_LOG", "debug")
+        .output()
+        .unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
+    if out.status.success() {
+        return;
+    }
+
+    println!("test failed: {}", out.status);
+    println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap());
+    println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap());
+    process::exit(1);
+}
diff --git a/tests/log_tls_dtors.rs b/tests/log_tls_dtors.rs
new file mode 100644
index 0000000..5db87bd
--- /dev/null
+++ b/tests/log_tls_dtors.rs
@@ -0,0 +1,66 @@
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+
+use std::env;
+use std::process;
+use std::str;
+use std::thread;
+
+struct DropMe;
+
+impl Drop for DropMe {
+    fn drop(&mut self) {
+        debug!("Dropping now");
+    }
+}
+
+fn run() {
+    // Use multiple thread local values to increase the chance that our TLS
+    // value will get destroyed after the FORMATTER key in the library
+    thread_local! {
+        static DROP_ME_0: DropMe = DropMe;
+        static DROP_ME_1: DropMe = DropMe;
+        static DROP_ME_2: DropMe = DropMe;
+        static DROP_ME_3: DropMe = DropMe;
+        static DROP_ME_4: DropMe = DropMe;
+        static DROP_ME_5: DropMe = DropMe;
+        static DROP_ME_6: DropMe = DropMe;
+        static DROP_ME_7: DropMe = DropMe;
+        static DROP_ME_8: DropMe = DropMe;
+        static DROP_ME_9: DropMe = DropMe;
+    }
+    DROP_ME_0.with(|_| {});
+    DROP_ME_1.with(|_| {});
+    DROP_ME_2.with(|_| {});
+    DROP_ME_3.with(|_| {});
+    DROP_ME_4.with(|_| {});
+    DROP_ME_5.with(|_| {});
+    DROP_ME_6.with(|_| {});
+    DROP_ME_7.with(|_| {});
+    DROP_ME_8.with(|_| {});
+    DROP_ME_9.with(|_| {});
+}
+
+fn main() {
+    env_logger::init();
+    if env::var("YOU_ARE_TESTING_NOW").is_ok() {
+        // Run on a separate thread because TLS values on the main thread
+        // won't have their destructors run if pthread is used.
+        // https://doc.rust-lang.org/std/thread/struct.LocalKey.html#platform-specific-behavior
+        thread::spawn(run).join().unwrap();
+    } else {
+        let exe = env::current_exe().unwrap();
+        let out = process::Command::new(exe)
+            .env("YOU_ARE_TESTING_NOW", "1")
+            .env("RUST_LOG", "debug")
+            .output()
+            .unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
+        if !out.status.success() {
+            println!("test failed: {}", out.status);
+            println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap());
+            println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap());
+            process::exit(1);
+        }
+    }
+}
diff --git a/tests/regexp_filter.rs b/tests/regexp_filter.rs
new file mode 100644
index 0000000..40178ba
--- /dev/null
+++ b/tests/regexp_filter.rs
@@ -0,0 +1,57 @@
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+
+use std::env;
+use std::process;
+use std::str;
+
+fn main() {
+    if env::var("LOG_REGEXP_TEST").ok() == Some(String::from("1")) {
+        child_main();
+    } else {
+        parent_main()
+    }
+}
+
+fn child_main() {
+    env_logger::init();
+    info!("XYZ Message");
+}
+
+fn run_child(rust_log: String) -> bool {
+    let exe = env::current_exe().unwrap();
+    let out = process::Command::new(exe)
+        .env("LOG_REGEXP_TEST", "1")
+        .env("RUST_LOG", rust_log)
+        .output()
+        .unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
+    str::from_utf8(out.stderr.as_ref())
+        .unwrap()
+        .contains("XYZ Message")
+}
+
+fn assert_message_printed(rust_log: &str) {
+    if !run_child(rust_log.to_string()) {
+        panic!("RUST_LOG={} should allow the test log message", rust_log)
+    }
+}
+
+fn assert_message_not_printed(rust_log: &str) {
+    if run_child(rust_log.to_string()) {
+        panic!(
+            "RUST_LOG={} should not allow the test log message",
+            rust_log
+        )
+    }
+}
+
+fn parent_main() {
+    // test normal log severity levels
+    assert_message_printed("info");
+    assert_message_not_printed("warn");
+
+    // test of regular expression filters
+    assert_message_printed("info/XYZ");
+    assert_message_not_printed("info/XXX");
+}