aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-06-21 12:29:46 -0700
committerJoel Galenson <jgalenson@google.com>2021-06-21 12:29:46 -0700
commite816d481c6fc26a82653566ce1fc18f9a9b16b2f (patch)
tree73c098bb25bbbce3eda1f3b034d3738e974d04ea
parentbb5bcec0556f46b259cce862224f5f4bb65c9b2e (diff)
downloadenv_logger-e816d481c6fc26a82653566ce1fc18f9a9b16b2f.tar.gz
Upgrade rust/crates/env_logger to 0.8.4
Test: make Change-Id: I84192922a0e39dd63dbf6a0cd48f751fd66d4264
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Cargo.toml2
-rw-r--r--Cargo.toml.orig2
-rw-r--r--METADATA8
-rw-r--r--README.md4
-rw-r--r--TEST_MAPPING45
-rw-r--r--src/filter/mod.rs25
-rw-r--r--src/fmt/writer/mod.rs99
-rw-r--r--src/fmt/writer/termcolor/extern_impl.rs74
-rw-r--r--src/fmt/writer/termcolor/shim_impl.rs32
-rw-r--r--src/lib.rs21
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"
}
}
diff --git a/Cargo.toml b/Cargo.toml
index bd952f8..56361f9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/METADATA b/METADATA
index b1e7cb0..2bcd175 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/env_logger/env_logger-0.8.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
}
}
diff --git a/README.md b/README.md
index 329d1be..4e84e8f 100644
--- a/README.md
+++ b/README.md
@@ -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(())
diff --git a/src/lib.rs b/src/lib.rs
index 31ea7c3..6a77266 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
+ }
}