Snap for 8564071 from 48a125a2ebdd03b00350bb00d56e6c2c660c56c0 to mainline-extservices-release

Change-Id: I3db212230e549a3b9b83b1c29e32c05ce5638c2e
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 8b186b2..b5ebece 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "67adcba945148ef3bc1a867832f1422779d626cc"
+    "sha1": "04856ac38baf422baebb40729cf51127a75b82ed"
   }
 }
diff --git a/Android.bp b/Android.bp
index fe94641..b08c70d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -37,34 +37,29 @@
     ],
 }
 
-rust_defaults {
-    name: "env_logger_defaults",
+rust_test {
+    name: "env_logger_test_src_lib",
+    host_supported: true,
     crate_name: "env_logger",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.9.0",
     srcs: ["src/lib.rs"],
     test_suites: ["general-tests"],
     auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
     edition: "2018",
     rustlibs: [
         "liblog_rust",
     ],
 }
 
-rust_test_host {
-    name: "env_logger_host_test_src_lib",
-    defaults: ["env_logger_defaults"],
-    test_options: {
-        unit_test: true,
-    },
-}
-
-rust_test {
-    name: "env_logger_device_test_src_lib",
-    defaults: ["env_logger_defaults"],
-}
-
 rust_defaults {
-    name: "env_logger_defaults_env_logger",
+    name: "env_logger_test_defaults",
     crate_name: "env_logger",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.9.0",
     test_suites: ["general-tests"],
     auto_gen_config: true,
     edition: "2018",
@@ -75,9 +70,10 @@
     ],
 }
 
-rust_test_host {
-    name: "env_logger_host_test_tests_init-twice-retains-filter",
-    defaults: ["env_logger_defaults_env_logger"],
+rust_test {
+    name: "env_logger_test_tests_init-twice-retains-filter",
+    defaults: ["env_logger_test_defaults"],
+    host_supported: true,
     srcs: ["tests/init-twice-retains-filter.rs"],
     test_options: {
         unit_test: true,
@@ -85,14 +81,9 @@
 }
 
 rust_test {
-    name: "env_logger_device_test_tests_init-twice-retains-filter",
-    defaults: ["env_logger_defaults_env_logger"],
-    srcs: ["tests/init-twice-retains-filter.rs"],
-}
-
-rust_test_host {
-    name: "env_logger_host_test_tests_log-in-log",
-    defaults: ["env_logger_defaults_env_logger"],
+    name: "env_logger_test_tests_log-in-log",
+    defaults: ["env_logger_test_defaults"],
+    host_supported: true,
     srcs: ["tests/log-in-log.rs"],
     test_options: {
         unit_test: true,
@@ -100,14 +91,9 @@
 }
 
 rust_test {
-    name: "env_logger_device_test_tests_log-in-log",
-    defaults: ["env_logger_defaults_env_logger"],
-    srcs: ["tests/log-in-log.rs"],
-}
-
-rust_test_host {
-    name: "env_logger_host_test_tests_log_tls_dtors",
-    defaults: ["env_logger_defaults_env_logger"],
+    name: "env_logger_test_tests_log_tls_dtors",
+    defaults: ["env_logger_test_defaults"],
+    host_supported: true,
     srcs: ["tests/log_tls_dtors.rs"],
     test_options: {
         unit_test: true,
@@ -115,30 +101,21 @@
 }
 
 rust_test {
-    name: "env_logger_device_test_tests_log_tls_dtors",
-    defaults: ["env_logger_defaults_env_logger"],
-    srcs: ["tests/log_tls_dtors.rs"],
-}
-
-rust_test_host {
-    name: "env_logger_host_test_tests_regexp_filter",
-    defaults: ["env_logger_defaults_env_logger"],
+    name: "env_logger_test_tests_regexp_filter",
+    defaults: ["env_logger_test_defaults"],
+    host_supported: true,
     srcs: ["tests/regexp_filter.rs"],
     test_options: {
         unit_test: true,
     },
 }
 
-rust_test {
-    name: "env_logger_device_test_tests_regexp_filter",
-    defaults: ["env_logger_defaults_env_logger"],
-    srcs: ["tests/regexp_filter.rs"],
-}
-
 rust_library {
     name: "libenv_logger",
     host_supported: true,
     crate_name: "env_logger",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.9.0",
     srcs: ["src/lib.rs"],
     edition: "2018",
     rustlibs: [
@@ -146,12 +123,12 @@
     ],
     apex_available: [
         "//apex_available:platform",
+        "com.android.bluetooth",
+        "com.android.compos",
         "com.android.resolv",
+        "com.android.uwb",
         "com.android.virt",
     ],
+    vendor_available: true,
     min_sdk_version: "29",
 }
-
-// dependent_library ["feature_list"]
-//   cfg-if-1.0.0
-//   log-0.4.14 "std"
diff --git a/Cargo.toml b/Cargo.toml
index bd952f8..b91eddb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 [package]
 edition = "2018"
 name = "env_logger"
-version = "0.8.3"
+version = "0.9.0"
 authors = ["The Rust Project Developers"]
 include = ["src/**/*", "tests", "LICENSE-*", "README.md", "CHANGELOG.md"]
 description = "A logging implementation for `log` which is configured via an environment\nvariable.\n"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 42fa5ae..29c77b3 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
 [package]
 name = "env_logger"
 edition = "2018"
-version = "0.8.3"
+version = "0.9.0"
 authors = ["The Rust Project Developers"]
 license = "MIT/Apache-2.0"
 readme = "README.md"
diff --git a/METADATA b/METADATA
index b1e7cb0..07f72fc 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/env_logger/env_logger-0.8.3.crate"
+    value: "https://static.crates.io/crates/env_logger/env_logger-0.9.0.crate"
   }
-  version: "0.8.3"
+  version: "0.9.0"
   license_type: NOTICE
   last_upgrade_date {
     year: 2021
-    month: 2
-    day: 11
+    month: 8
+    day: 9
   }
 }
diff --git a/README.md b/README.md
index 329d1be..4e84e8f 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
 ```toml
 [dependencies]
 log = "0.4.0"
-env_logger = "0.8.3"
+env_logger = "0.8.4"
 ```
 
 `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.
@@ -88,7 +88,7 @@
 log = "0.4.0"
 
 [dev-dependencies]
-env_logger = "0.8.3"
+env_logger = "0.8.4"
 ```
 
 ```rust
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 15e6776..0553d14 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,32 +1,132 @@
 // Generated by update_crate_tests.py for tests that depend on this crate.
 {
+  "imports": [
+    {
+      "path": "external/rust/crates/android_logger"
+    },
+    {
+      "path": "external/rust/crates/cast"
+    },
+    {
+      "path": "external/rust/crates/crc32fast"
+    },
+    {
+      "path": "external/rust/crates/libsqlite3-sys"
+    },
+    {
+      "path": "external/rust/crates/mio"
+    },
+    {
+      "path": "external/rust/crates/quickcheck"
+    },
+    {
+      "path": "external/rust/crates/regex"
+    }
+  ],
   "presubmit": [
     {
-      "name": "keystore2_test"
+      "name": "authfs_device_test_src_lib"
     },
     {
-      "name": "env_logger_device_test_tests_regexp_filter"
+      "name": "doh_unit_test"
     },
     {
-      "name": "env_logger_device_test_src_lib"
+      "name": "env_logger_test_src_lib"
     },
     {
-      "name": "env_logger_device_test_tests_log-in-log"
+      "name": "env_logger_test_tests_init-twice-retains-filter"
     },
     {
-      "name": "env_logger_device_test_tests_init-twice-retains-filter"
+      "name": "env_logger_test_tests_log-in-log"
     },
     {
-      "name": "libsqlite3-sys_device_test_src_lib"
+      "name": "env_logger_test_tests_log_tls_dtors"
     },
     {
-      "name": "android_logger_device_test_src_lib"
+      "name": "env_logger_test_tests_regexp_filter"
+    },
+    {
+      "name": "keystore2_selinux_concurrency_test"
     },
     {
       "name": "keystore2_selinux_test"
     },
     {
-      "name": "env_logger_device_test_tests_log_tls_dtors"
+      "name": "keystore2_test"
+    },
+    {
+      "name": "legacykeystore_test"
+    },
+    {
+      "name": "logger_device_unit_tests"
+    },
+    {
+      "name": "logger_test_config_log_level"
+    },
+    {
+      "name": "logger_test_default_init"
+    },
+    {
+      "name": "logger_test_env_log_level"
+    },
+    {
+      "name": "logger_test_multiple_init"
+    },
+    {
+      "name": "virtualizationservice_device_test"
+    }
+  ],
+  "presubmit-rust": [
+    {
+      "name": "authfs_device_test_src_lib"
+    },
+    {
+      "name": "doh_unit_test"
+    },
+    {
+      "name": "env_logger_test_src_lib"
+    },
+    {
+      "name": "env_logger_test_tests_init-twice-retains-filter"
+    },
+    {
+      "name": "env_logger_test_tests_log-in-log"
+    },
+    {
+      "name": "env_logger_test_tests_log_tls_dtors"
+    },
+    {
+      "name": "env_logger_test_tests_regexp_filter"
+    },
+    {
+      "name": "keystore2_selinux_concurrency_test"
+    },
+    {
+      "name": "keystore2_selinux_test"
+    },
+    {
+      "name": "keystore2_test"
+    },
+    {
+      "name": "legacykeystore_test"
+    },
+    {
+      "name": "logger_device_unit_tests"
+    },
+    {
+      "name": "logger_test_config_log_level"
+    },
+    {
+      "name": "logger_test_default_init"
+    },
+    {
+      "name": "logger_test_env_log_level"
+    },
+    {
+      "name": "logger_test_multiple_init"
+    },
+    {
+      "name": "virtualizationservice_device_test"
     }
   ]
 }
diff --git a/cargo2android.json b/cargo2android.json
index c10a6d8..98d8431 100644
--- a/cargo2android.json
+++ b/cargo2android.json
@@ -1,13 +1,17 @@
 {
   "apex-available": [
     "//apex_available:platform",
+    "com.android.bluetooth",
+    "com.android.compos",
     "com.android.resolv",
+    "com.android.uwb",
     "com.android.virt"
   ],
-  "min_sdk_version": "29",
   "dependencies": true,
   "device": true,
   "features": "",
+  "min-sdk-version": "29",
   "run": true,
-  "tests": true
+  "tests": true,
+  "vendor-available": true
 }
\ No newline at end of file
diff --git a/src/filter/mod.rs b/src/filter/mod.rs
index 8f7787f..9ebeab0 100644
--- a/src/filter/mod.rs
+++ b/src/filter/mod.rs
@@ -59,6 +59,7 @@
 //! [`Filter::matches`]: struct.Filter.html#method.matches
 
 use log::{Level, LevelFilter, Metadata, Record};
+use std::collections::HashMap;
 use std::env;
 use std::fmt;
 use std::mem;
@@ -107,7 +108,7 @@
 ///
 /// [`Filter`]: struct.Filter.html
 pub struct Builder {
-    directives: Vec<Directive>,
+    directives: HashMap<Option<String>, LevelFilter>,
     filter: Option<inner::Filter>,
     built: bool,
 }
@@ -171,7 +172,7 @@
     /// Initializes the filter builder with defaults.
     pub fn new() -> Builder {
         Builder {
-            directives: Vec::new(),
+            directives: HashMap::new(),
             filter: None,
             built: false,
         }
@@ -203,10 +204,7 @@
     /// 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.directives.insert(module.map(|s| s.to_string()), level);
         self
     }
 
@@ -221,7 +219,7 @@
         self.filter = filter;
 
         for directive in directives {
-            self.directives.push(directive);
+            self.directives.insert(directive.name, directive.level);
         }
         self
     }
@@ -231,16 +229,23 @@
         assert!(!self.built, "attempt to re-use consumed builder");
         self.built = true;
 
+        let mut directives = Vec::new();
         if self.directives.is_empty() {
             // Adds the default filter if none exist
-            self.directives.push(Directive {
+            directives.push(Directive {
                 name: None,
                 level: LevelFilter::Error,
             });
         } else {
+            // Consume map of directives.
+            let directives_map = mem::take(&mut self.directives);
+            directives = directives_map
+                .into_iter()
+                .map(|(name, level)| Directive { name, level })
+                .collect();
             // Sort the directives by length of their name, this allows a
             // little more efficient lookup at runtime.
-            self.directives.sort_by(|a, b| {
+            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)
@@ -248,7 +253,7 @@
         }
 
         Filter {
-            directives: mem::replace(&mut self.directives, Vec::new()),
+            directives: mem::take(&mut directives),
             filter: mem::replace(&mut self.filter, None),
         }
     }
diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs
index 3c4fee0..21e0957 100644
--- a/src/fmt/mod.rs
+++ b/src/fmt/mod.rs
@@ -141,6 +141,7 @@
 pub(crate) struct Builder {
     pub format_timestamp: Option<TimestampPrecision>,
     pub format_module_path: bool,
+    pub format_target: bool,
     pub format_level: bool,
     pub format_indent: Option<usize>,
     pub custom_format: Option<FormatFn>,
@@ -152,7 +153,8 @@
     fn default() -> Self {
         Builder {
             format_timestamp: Some(Default::default()),
-            format_module_path: true,
+            format_module_path: false,
+            format_target: true,
             format_level: true,
             format_indent: Some(4),
             custom_format: None,
@@ -186,6 +188,7 @@
                 let fmt = DefaultFormat {
                     timestamp: built.format_timestamp,
                     module_path: built.format_module_path,
+                    target: built.format_target,
                     level: built.format_level,
                     written_header_value: false,
                     indent: built.format_indent,
@@ -210,6 +213,7 @@
 struct DefaultFormat<'a> {
     timestamp: Option<TimestampPrecision>,
     module_path: bool,
+    target: bool,
     level: bool,
     written_header_value: bool,
     indent: Option<usize>,
@@ -222,6 +226,7 @@
         self.write_timestamp()?;
         self.write_level(record)?;
         self.write_module_path(record)?;
+        self.write_target(record)?;
         self.finish_header()?;
 
         self.write_args(record)
@@ -311,6 +316,17 @@
         }
     }
 
+    fn write_target(&mut self, record: &Record) -> io::Result<()> {
+        if !self.target {
+            return Ok(());
+        }
+
+        match record.target() {
+            "" => Ok(()),
+            target => self.write_header_value(target),
+        }
+    }
+
     fn finish_header(&mut self) -> io::Result<()> {
         if self.written_header_value {
             let close_brace = self.subtle_style("]");
@@ -381,23 +397,33 @@
 
     use log::{Level, Record};
 
-    fn write(fmt: DefaultFormat) -> String {
+    fn write_record(record: Record, 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")
     }
 
+    fn write_target<'a>(target: &'a str, fmt: DefaultFormat) -> String {
+        write_record(
+            Record::builder()
+                .args(format_args!("log\nmessage"))
+                .level(Level::Info)
+                .file(Some("test.rs"))
+                .line(Some(144))
+                .module_path(Some("test::path"))
+                .target(target)
+                .build(),
+            fmt,
+        )
+    }
+
+    fn write(fmt: DefaultFormat) -> String {
+        write_target("", fmt)
+    }
+
     #[test]
     fn format_with_header() {
         let writer = writer::Builder::new()
@@ -409,6 +435,7 @@
         let written = write(DefaultFormat {
             timestamp: None,
             module_path: true,
+            target: false,
             level: true,
             written_header_value: false,
             indent: None,
@@ -430,6 +457,7 @@
         let written = write(DefaultFormat {
             timestamp: None,
             module_path: false,
+            target: false,
             level: false,
             written_header_value: false,
             indent: None,
@@ -451,6 +479,7 @@
         let written = write(DefaultFormat {
             timestamp: None,
             module_path: true,
+            target: false,
             level: true,
             written_header_value: false,
             indent: Some(4),
@@ -472,6 +501,7 @@
         let written = write(DefaultFormat {
             timestamp: None,
             module_path: true,
+            target: false,
             level: true,
             written_header_value: false,
             indent: Some(0),
@@ -493,6 +523,7 @@
         let written = write(DefaultFormat {
             timestamp: None,
             module_path: false,
+            target: false,
             level: false,
             written_header_value: false,
             indent: Some(4),
@@ -514,6 +545,7 @@
         let written = write(DefaultFormat {
             timestamp: None,
             module_path: false,
+            target: false,
             level: false,
             written_header_value: false,
             indent: None,
@@ -535,6 +567,7 @@
         let written = write(DefaultFormat {
             timestamp: None,
             module_path: false,
+            target: false,
             level: false,
             written_header_value: false,
             indent: Some(4),
@@ -544,4 +577,76 @@
 
         assert_eq!("log\n\n    message\n\n", written);
     }
+
+    #[test]
+    fn format_target() {
+        let writer = writer::Builder::new()
+            .write_style(WriteStyle::Never)
+            .build();
+
+        let mut f = Formatter::new(&writer);
+
+        let written = write_target(
+            "target",
+            DefaultFormat {
+                timestamp: None,
+                module_path: true,
+                target: true,
+                level: true,
+                written_header_value: false,
+                indent: None,
+                suffix: "\n",
+                buf: &mut f,
+            },
+        );
+
+        assert_eq!("[INFO  test::path target] log\nmessage\n", written);
+    }
+
+    #[test]
+    fn format_empty_target() {
+        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,
+            target: true,
+            level: true,
+            written_header_value: false,
+            indent: None,
+            suffix: "\n",
+            buf: &mut f,
+        });
+
+        assert_eq!("[INFO  test::path] log\nmessage\n", written);
+    }
+
+    #[test]
+    fn format_no_target() {
+        let writer = writer::Builder::new()
+            .write_style(WriteStyle::Never)
+            .build();
+
+        let mut f = Formatter::new(&writer);
+
+        let written = write_target(
+            "target",
+            DefaultFormat {
+                timestamp: None,
+                module_path: true,
+                target: false,
+                level: true,
+                written_header_value: false,
+                indent: None,
+                suffix: "\n",
+                buf: &mut f,
+            },
+        );
+
+        assert_eq!("[INFO  test::path] log\nmessage\n", written);
+    }
 }
diff --git a/src/fmt/writer/mod.rs b/src/fmt/writer/mod.rs
index 6ee63a3..5bb5353 100644
--- a/src/fmt/writer/mod.rs
+++ b/src/fmt/writer/mod.rs
@@ -3,22 +3,24 @@
 
 use self::atty::{is_stderr, is_stdout};
 use self::termcolor::BufferWriter;
-use std::{fmt, io};
+use std::{fmt, io, mem, sync::Mutex};
 
-pub(in crate::fmt) mod glob {
+pub(super) mod glob {
     pub use super::termcolor::glob::*;
     pub use super::*;
 }
 
-pub(in crate::fmt) use self::termcolor::Buffer;
+pub(super) use self::termcolor::Buffer;
 
-/// Log target, either `stdout` or `stderr`.
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+/// Log target, either `stdout`, `stderr` or a custom pipe.
+#[non_exhaustive]
 pub enum Target {
     /// Logs will be sent to standard output.
     Stdout,
     /// Logs will be sent to standard error.
     Stderr,
+    /// Logs will be sent to a custom pipe.
+    Pipe(Box<dyn io::Write + Send + 'static>),
 }
 
 impl Default for Target {
@@ -27,6 +29,61 @@
     }
 }
 
+impl fmt::Debug for Target {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                Self::Stdout => "stdout",
+                Self::Stderr => "stderr",
+                Self::Pipe(_) => "pipe",
+            }
+        )
+    }
+}
+
+/// Log target, either `stdout`, `stderr` or a custom pipe.
+///
+/// Same as `Target`, except the pipe is wrapped in a mutex for interior mutability.
+pub(super) enum WritableTarget {
+    /// Logs will be sent to standard output.
+    Stdout,
+    /// Logs will be sent to standard error.
+    Stderr,
+    /// Logs will be sent to a custom pipe.
+    Pipe(Box<Mutex<dyn io::Write + Send + 'static>>),
+}
+
+impl From<Target> for WritableTarget {
+    fn from(target: Target) -> Self {
+        match target {
+            Target::Stdout => Self::Stdout,
+            Target::Stderr => Self::Stderr,
+            Target::Pipe(pipe) => Self::Pipe(Box::new(Mutex::new(pipe))),
+        }
+    }
+}
+
+impl Default for WritableTarget {
+    fn default() -> Self {
+        Self::from(Target::default())
+    }
+}
+
+impl fmt::Debug for WritableTarget {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                Self::Stdout => "stdout",
+                Self::Stderr => "stderr",
+                Self::Pipe(_) => "pipe",
+            }
+        )
+    }
+}
 /// Whether or not to print styles to the target.
 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
 pub enum WriteStyle {
@@ -55,11 +112,11 @@
         self.write_style
     }
 
-    pub(in crate::fmt) fn buffer(&self) -> Buffer {
+    pub(super) fn buffer(&self) -> Buffer {
         self.inner.buffer()
     }
 
-    pub(in crate::fmt) fn print(&self, buf: &Buffer) -> io::Result<()> {
+    pub(super) fn print(&self, buf: &Buffer) -> io::Result<()> {
         self.inner.print(buf)
     }
 }
@@ -67,8 +124,9 @@
 /// A builder for a terminal writer.
 ///
 /// The target and style choice can be configured before building.
+#[derive(Debug)]
 pub(crate) struct Builder {
-    target: Target,
+    target: WritableTarget,
     write_style: WriteStyle,
     is_test: bool,
     built: bool,
@@ -87,7 +145,7 @@
 
     /// Set the target to write to.
     pub(crate) fn target(&mut self, target: Target) -> &mut Self {
-        self.target = target;
+        self.target = target.into();
         self
     }
 
@@ -119,9 +177,10 @@
 
         let color_choice = match self.write_style {
             WriteStyle::Auto => {
-                if match self.target {
-                    Target::Stderr => is_stderr(),
-                    Target::Stdout => is_stdout(),
+                if match &self.target {
+                    WritableTarget::Stderr => is_stderr(),
+                    WritableTarget::Stdout => is_stdout(),
+                    WritableTarget::Pipe(_) => false,
                 } {
                     WriteStyle::Auto
                 } else {
@@ -131,9 +190,10 @@
             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),
+        let writer = match mem::take(&mut self.target) {
+            WritableTarget::Stderr => BufferWriter::stderr(self.is_test, color_choice),
+            WritableTarget::Stdout => BufferWriter::stdout(self.is_test, color_choice),
+            WritableTarget::Pipe(pipe) => BufferWriter::pipe(self.is_test, color_choice, pipe),
         };
 
         Writer {
@@ -149,15 +209,6 @@
     }
 }
 
-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()
diff --git a/src/fmt/writer/termcolor/extern_impl.rs b/src/fmt/writer/termcolor/extern_impl.rs
index 4324a45..11012fb 100644
--- a/src/fmt/writer/termcolor/extern_impl.rs
+++ b/src/fmt/writer/termcolor/extern_impl.rs
@@ -3,11 +3,12 @@
 use std::fmt;
 use std::io::{self, Write};
 use std::rc::Rc;
+use std::sync::Mutex;
 
 use log::Level;
 use termcolor::{self, ColorChoice, ColorSpec, WriteColor};
 
-use crate::fmt::{Formatter, Target, WriteStyle};
+use crate::fmt::{Formatter, WritableTarget, WriteStyle};
 
 pub(in crate::fmt::writer) mod glob {
     pub use super::*;
@@ -70,46 +71,71 @@
 
 pub(in crate::fmt::writer) struct BufferWriter {
     inner: termcolor::BufferWriter,
-    test_target: Option<Target>,
+    test_target: Option<WritableTarget>,
 }
 
 pub(in crate::fmt) struct Buffer {
     inner: termcolor::Buffer,
-    test_target: Option<Target>,
+    has_test_target: bool,
 }
 
 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 },
+            test_target: if is_test {
+                Some(WritableTarget::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 },
+            test_target: if is_test {
+                Some(WritableTarget::Stdout)
+            } else {
+                None
+            },
+        }
+    }
+
+    pub(in crate::fmt::writer) fn pipe(
+        is_test: bool,
+        write_style: WriteStyle,
+        pipe: Box<Mutex<dyn io::Write + Send + 'static>>,
+    ) -> Self {
+        BufferWriter {
+            // The inner Buffer is never printed from, but it is still needed to handle coloring and other formating
+            inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
+            test_target: if is_test {
+                Some(WritableTarget::Pipe(pipe))
+            } else {
+                None
+            },
         }
     }
 
     pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
         Buffer {
             inner: self.inner.buffer(),
-            test_target: self.test_target,
+            has_test_target: self.test_target.is_some(),
         }
     }
 
     pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
-        if let Some(target) = self.test_target {
+        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),
+                WritableTarget::Stderr => eprint!("{}", log),
+                WritableTarget::Stdout => print!("{}", log),
+                WritableTarget::Pipe(pipe) => write!(pipe.lock().unwrap(), "{}", log)?,
             }
 
             Ok(())
@@ -138,7 +164,7 @@
 
     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() {
+        if !self.has_test_target {
             self.inner.set_color(spec)
         } else {
             Ok(())
@@ -147,7 +173,7 @@
 
     fn reset(&mut self) -> io::Result<()> {
         // Ignore styles for test captured logs because they can't be printed
-        if self.test_target.is_none() {
+        if !self.has_test_target {
             self.inner.reset()
         } else {
             Ok(())
@@ -255,7 +281,7 @@
     /// });
     /// ```
     pub fn set_color(&mut self, color: Color) -> &mut Style {
-        self.spec.set_fg(color.into_termcolor());
+        self.spec.set_fg(Some(color.into_termcolor()));
         self
     }
 
@@ -334,7 +360,7 @@
     /// });
     /// ```
     pub fn set_bg(&mut self, color: Color) -> &mut Style {
-        self.spec.set_bg(color.into_termcolor());
+        self.spec.set_bg(Some(color.into_termcolor()));
         self
     }
 
@@ -467,18 +493,18 @@
 }
 
 impl Color {
-    fn into_termcolor(self) -> Option<termcolor::Color> {
+    fn into_termcolor(self) -> 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)),
+            Color::Black => termcolor::Color::Black,
+            Color::Blue => termcolor::Color::Blue,
+            Color::Green => termcolor::Color::Green,
+            Color::Red => termcolor::Color::Red,
+            Color::Cyan => termcolor::Color::Cyan,
+            Color::Magenta => termcolor::Color::Magenta,
+            Color::Yellow => termcolor::Color::Yellow,
+            Color::White => termcolor::Color::White,
+            Color::Ansi256(value) => termcolor::Color::Ansi256(value),
+            Color::Rgb(r, g, b) => termcolor::Color::Rgb(r, g, b),
         }
     }
 }
diff --git a/src/fmt/writer/termcolor/shim_impl.rs b/src/fmt/writer/termcolor/shim_impl.rs
index 563f8ad..bfc31d0 100644
--- a/src/fmt/writer/termcolor/shim_impl.rs
+++ b/src/fmt/writer/termcolor/shim_impl.rs
@@ -1,11 +1,11 @@
-use std::io;
+use std::{io, sync::Mutex};
 
-use crate::fmt::{Target, WriteStyle};
+use crate::fmt::{WritableTarget, WriteStyle};
 
 pub(in crate::fmt::writer) mod glob {}
 
 pub(in crate::fmt::writer) struct BufferWriter {
-    target: Target,
+    target: WritableTarget,
 }
 
 pub(in crate::fmt) struct Buffer(Vec<u8>);
@@ -13,13 +13,23 @@
 impl BufferWriter {
     pub(in crate::fmt::writer) fn stderr(_is_test: bool, _write_style: WriteStyle) -> Self {
         BufferWriter {
-            target: Target::Stderr,
+            target: WritableTarget::Stderr,
         }
     }
 
     pub(in crate::fmt::writer) fn stdout(_is_test: bool, _write_style: WriteStyle) -> Self {
         BufferWriter {
-            target: Target::Stdout,
+            target: WritableTarget::Stdout,
+        }
+    }
+
+    pub(in crate::fmt::writer) fn pipe(
+        _is_test: bool,
+        _write_style: WriteStyle,
+        pipe: Box<Mutex<dyn io::Write + Send + 'static>>,
+    ) -> Self {
+        BufferWriter {
+            target: WritableTarget::Pipe(pipe),
         }
     }
 
@@ -30,12 +40,12 @@
     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),
+        // This is so their output can be captured by `cargo test`.
+        match &self.target {
+            // Safety: If the target type is `Pipe`, `target_pipe` will always be non-empty.
+            WritableTarget::Pipe(pipe) => pipe.lock().unwrap().write_all(&buf.0)?,
+            WritableTarget::Stdout => print!("{}", String::from_utf8_lossy(&buf.0)),
+            WritableTarget::Stderr => eprint!("{}", String::from_utf8_lossy(&buf.0)),
         }
 
         Ok(())
diff --git a/src/lib.rs b/src/lib.rs
index 31ea7c3..8504108 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -97,28 +97,38 @@
 //! directives*. A logging directive is of the form:
 //!
 //! ```text
-//! path::to::module=level
+//! example::log::target=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 log target is typically equal to the path of the module the message
+//! in question originated from, though it can be overriden.
+//!
+//! The path is rooted in the name of the crate it was compiled for, so if
+//! your program is in a file called, for example, `hello.rs`, the path would
+//! simply be be `hello`.
+//!
+//! Furthermore, the the log can be filtered using prefix-search based on the
+//! specified log target. A value of, for example, `RUST_LOG=example`, would
+//! match all of the messages with targets:
+//!
+//! * `example`
+//! * `example::test`
+//! * `example::test::module::submodule`
+//! * `examples::and_more_examples`
 //!
 //! When providing the crate name or a module path, explicitly specifying the
-//! log level is optional. If omitted, all logging for the item (and its
-//! children) will be enabled.
+//! log level is optional. If omitted, all logging for the item will be
+//! enabled.
 //!
 //! The names of the log levels that may be specified correspond to the
 //! variations of the [`log::Level`][level-enum] enum from the `log`
 //! crate. They are:
 //!
-//!    * `error`
-//!    * `warn`
-//!    * `info`
-//!    * `debug`
-//!    * `trace`
+//! * `error`
+//! * `warn`
+//! * `info`
+//! * `debug`
+//! * `trace`
 //!
 //! There is also a pseudo logging level, `off`, which may be specified to
 //! disable all logging for a given module or for the entire application. As
@@ -260,7 +270,7 @@
 //! env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
 //! ```
 //!
-//! [gh-repo-examples]: https://github.com/env-logger-rs/env_logger/tree/master/examples
+//! [gh-repo-examples]: https://github.com/env-logger-rs/env_logger/tree/main/examples
 //! [level-enum]: https://docs.rs/log/latest/log/enum.Level.html
 //! [log-crate-url]: https://docs.rs/log/
 //! [`Builder`]: struct.Builder.html
@@ -598,6 +608,12 @@
         self
     }
 
+    /// Whether or not to write the target in the default format.
+    pub fn format_target(&mut self, write: bool) -> &mut Self {
+        self.format.format_target = 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 {
@@ -708,7 +724,10 @@
 
     /// Sets the target for the log output.
     ///
-    /// Env logger can log to either stdout or stderr. The default is stderr.
+    /// Env logger can log to either stdout, stderr or a custom pipe. The default is stderr.
+    ///
+    /// The custom pipe can be used to send the log messages to a custom sink (for example a file).
+    /// Do note that direct writes to a file can become a bottleneck due to IO operation times.
     ///
     /// # Examples
     ///
@@ -1277,4 +1296,20 @@
 
         assert_eq!(Some("from default".to_owned()), env.get_write_style());
     }
+
+    #[test]
+    fn builder_parse_env_overrides_existing_filters() {
+        env::set_var(
+            "builder_parse_default_env_overrides_existing_filters",
+            "debug",
+        );
+        let env = Env::new().filter("builder_parse_default_env_overrides_existing_filters");
+
+        let mut builder = Builder::new();
+        builder.filter_level(LevelFilter::Trace);
+        // Overrides global level to debug
+        builder.parse_env(env);
+
+        assert_eq!(builder.filter.build().filter(), LevelFilter::Debug);
+    }
 }