diff options
author | Joel Galenson <jgalenson@google.com> | 2021-06-21 12:29:46 -0700 |
---|---|---|
committer | Joel Galenson <jgalenson@google.com> | 2021-06-21 12:29:46 -0700 |
commit | e816d481c6fc26a82653566ce1fc18f9a9b16b2f (patch) | |
tree | 73c098bb25bbbce3eda1f3b034d3738e974d04ea | |
parent | bb5bcec0556f46b259cce862224f5f4bb65c9b2e (diff) | |
download | env_logger-e816d481c6fc26a82653566ce1fc18f9a9b16b2f.tar.gz |
Upgrade rust/crates/env_logger to 0.8.4
Test: make
Change-Id: I84192922a0e39dd63dbf6a0cd48f751fd66d4264
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | Cargo.toml.orig | 2 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | TEST_MAPPING | 45 | ||||
-rw-r--r-- | src/filter/mod.rs | 25 | ||||
-rw-r--r-- | src/fmt/writer/mod.rs | 99 | ||||
-rw-r--r-- | src/fmt/writer/termcolor/extern_impl.rs | 74 | ||||
-rw-r--r-- | src/fmt/writer/termcolor/shim_impl.rs | 32 | ||||
-rw-r--r-- | src/lib.rs | 21 |
11 files changed, 229 insertions, 85 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 8b186b2..8469382 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "67adcba945148ef3bc1a867832f1422779d626cc" + "sha1": "13cafce572362582f57964eae6cb4a41f52fd04a" } } @@ -13,7 +13,7 @@ [package] edition = "2018" name = "env_logger" -version = "0.8.3" +version = "0.8.4" 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..3a3e176 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.8.4" authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" @@ -7,13 +7,13 @@ third_party { } 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.8.4.crate" } - version: "0.8.3" + version: "0.8.4" license_type: NOTICE last_upgrade_date { year: 2021 - month: 2 - day: 11 + month: 6 + day: 21 } } @@ -21,7 +21,7 @@ It must be added along with `log` to the project dependencies: ```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 @@ Tests can use the `env_logger` crate to see log messages generated during that t log = "0.4.0" [dev-dependencies] -env_logger = "0.8.3" +env_logger = "0.8.4" ``` ```rust diff --git a/TEST_MAPPING b/TEST_MAPPING index 15e6776..5958510 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -2,31 +2,64 @@ { "presubmit": [ { - "name": "keystore2_test" + "name": "android_logger_device_test_src_lib" }, { - "name": "env_logger_device_test_tests_regexp_filter" + "name": "android_logger_device_test_tests_config_log_level" + }, + { + "name": "android_logger_device_test_tests_default_init" + }, + { + "name": "android_logger_device_test_tests_multiple_init" + }, + { + "name": "doh_unit_test" }, { "name": "env_logger_device_test_src_lib" }, { + "name": "env_logger_device_test_tests_init-twice-retains-filter" + }, + { "name": "env_logger_device_test_tests_log-in-log" }, { - "name": "env_logger_device_test_tests_init-twice-retains-filter" + "name": "env_logger_device_test_tests_log_tls_dtors" }, { - "name": "libsqlite3-sys_device_test_src_lib" + "name": "env_logger_device_test_tests_regexp_filter" }, { - "name": "android_logger_device_test_src_lib" + "name": "keystore2_selinux_concurrency_test" }, { "name": "keystore2_selinux_test" }, { - "name": "env_logger_device_test_tests_log_tls_dtors" + "name": "keystore2_test" + }, + { + "name": "libsqlite3-sys_device_test_src_lib" + }, + { + "name": "logger_device_test_config_log_level" + }, + { + "name": "logger_device_test_default_init" + }, + { + "name": "logger_device_test_env_log_level" + }, + { + "name": "logger_device_test_multiple_init" + }, + { + "name": "logger_device_unit_tests" + }, + { + "name": "vpnprofilestore_test" } ] } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 8f7787f..7ef3f39 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 @@ pub struct Filter { /// /// [`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 @@ impl Builder { /// 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 @@ impl Builder { /// 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 @@ impl Builder { self.filter = filter; for directive in directives { - self.directives.push(directive); + self.directives.insert(directive.name, directive.level); } self } @@ -231,16 +229,23 @@ impl Builder { 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::replace(&mut self.directives, HashMap::new()); + 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 @@ impl Builder { } Filter { - directives: mem::replace(&mut self.directives, Vec::new()), + directives: mem::replace(&mut directives, Vec::new()), filter: mem::replace(&mut self.filter, None), } } 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 @@ mod termcolor; 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 Default for Target { } } +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 @@ impl Writer { 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 @@ impl Writer { /// 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 @@ impl Builder { /// 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 @@ impl Builder { 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 @@ impl Builder { 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 Default for Builder { } } -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::cell::RefCell; 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 @@ impl Formatter { 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 @@ impl Buffer { 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 @@ impl Buffer { 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 @@ impl Style { /// }); /// ``` 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 @@ impl Style { /// }); /// ``` 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 @@ pub enum Color { } 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 @@ 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, + 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 @@ impl BufferWriter { 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(()) @@ -708,7 +708,10 @@ impl Builder { /// 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 +1280,20 @@ mod tests { 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); + } } |