From cf8e3251e1164d9240e2cf28825425d0db38ce87 Mon Sep 17 00:00:00 2001 From: Norberto Lopes Date: Tue, 18 Dec 2018 13:38:19 +0000 Subject: [PATCH 01/18] Fix path for rust-lang favicon --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 355b687f..8d17ed96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -209,8 +209,8 @@ //! [`Env`]: struct.Env.html //! [`fmt`]: fmt/index.html -#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "http://www.rust-lang.org/favicon.ico", +#![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.6.0")] #![cfg_attr(test, deny(warnings))] From 86e4ac9cae36c41413cdbb587321d1e8223f4da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 26 Jan 2019 02:50:02 +0100 Subject: [PATCH 02/18] filter: Don't print to stdout the warnings due to an invalid spec. This makes programs that rely on the output of other programs not work properly in these cases. stderr is more appropriate for such things. Indeed, if you `export RUST_LOG="xxx=xxx"` before building this crate for the first time, the build fails :) See https://github.com/rust-lang/rust-bindgen/issues/1502. --- src/filter/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 65f413dd..a0fe6a25 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -306,8 +306,8 @@ fn parse_spec(spec: &str) -> (Vec, Option) { let mods = parts.next(); let filter = parts.next(); if parts.next().is_some() { - println!("warning: invalid logging spec '{}', \ - ignoring it (too many '/'s)", spec); + eprintln!("warning: invalid logging spec '{}', \ + ignoring it (too many '/'s)", spec); return (dirs, None); } mods.map(|m| { for s in m.split(',') { @@ -327,15 +327,15 @@ fn parse_spec(spec: &str) -> (Vec, Option) { match part1.parse() { Ok(num) => (num, Some(part0)), _ => { - println!("warning: invalid logging spec '{}', \ - ignoring it", part1); + eprintln!("warning: invalid logging spec '{}', \ + ignoring it", part1); continue } } }, _ => { - println!("warning: invalid logging spec '{}', \ - ignoring it", s); + eprintln!("warning: invalid logging spec '{}', \ + ignoring it", s); continue } }; @@ -349,7 +349,7 @@ fn parse_spec(spec: &str) -> (Vec, Option) { match inner::Filter::new(filter) { Ok(re) => Some(re), Err(e) => { - println!("warning: invalid regex filter - {}", e); + eprintln!("warning: invalid regex filter - {}", e); None } } From 8fa62401ceec3a7571565fb3437a7cf4b906f9ee Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 4 Mar 2019 09:51:59 +1000 Subject: [PATCH 03/18] Support capturing for cargo test (#127) * allow logs to be captured for cargo test --- README.md | 12 +++- src/fmt/writer/mod.rs | 22 ++++--- src/fmt/writer/termcolor/extern_impl.rs | 79 ++++++++++++++++++++----- src/fmt/writer/termcolor/shim_impl.rs | 4 +- src/lib.rs | 78 +++++++++++++++++++++--- tests/init-twice-retains-filter.rs | 2 +- 6 files changed, 159 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 496c5491..437dd66f 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Tests can use the `env_logger` crate to see log messages generated during that t log = "0.4.0" [dev-dependencies] -env_logger = { version = "0.6.0", default-features = false } +env_logger = "0.6.0" ``` ```rust @@ -69,16 +69,22 @@ mod tests { use super::*; extern crate env_logger; + fn init() { + let _ = env_logger::builder().is_test(true).try_init(); + } + #[test] fn it_adds_one() { - let _ = env_logger::try_init(); + init(); + info!("can log from the test too"); assert_eq!(3, add_one(2)); } #[test] fn it_handles_negative_numbers() { - let _ = env_logger::try_init(); + init(); + info!("logging from another test"); assert_eq!(-7, add_one(-8)); } diff --git a/src/fmt/writer/mod.rs b/src/fmt/writer/mod.rs index d628187e..d84e4146 100644 --- a/src/fmt/writer/mod.rs +++ b/src/fmt/writer/mod.rs @@ -70,21 +70,23 @@ impl Writer { pub(crate) struct Builder { target: Target, write_style: WriteStyle, + is_test: bool, built: bool, } impl Builder { /// Initialize the writer builder with defaults. - pub fn new() -> Self { + 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 fn target(&mut self, target: Target) -> &mut Self { + pub(crate) fn target(&mut self, target: Target) -> &mut Self { self.target = target; self } @@ -94,18 +96,24 @@ impl Builder { /// See the [Disabling colors] section for more details. /// /// [Disabling colors]: ../index.html#disabling-colors - pub fn parse(&mut self, write_style: &str) -> &mut Self { + 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 fn write_style(&mut self, write_style: WriteStyle) -> &mut Self { + 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 fn build(&mut self) -> Writer { + pub(crate) fn build(&mut self) -> Writer { assert!(!self.built, "attempt to re-use consumed builder"); self.built = true; @@ -124,8 +132,8 @@ impl Builder { }; let writer = match self.target { - Target::Stderr => BufferWriter::stderr(color_choice), - Target::Stdout => BufferWriter::stdout(color_choice), + Target::Stderr => BufferWriter::stderr(self.is_test, color_choice), + Target::Stdout => BufferWriter::stdout(self.is_test, color_choice), }; Writer { diff --git a/src/fmt/writer/termcolor/extern_impl.rs b/src/fmt/writer/termcolor/extern_impl.rs index 236e163b..0c2d1387 100644 --- a/src/fmt/writer/termcolor/extern_impl.rs +++ b/src/fmt/writer/termcolor/extern_impl.rs @@ -8,7 +8,7 @@ use log::Level; use termcolor::{self, ColorChoice, ColorSpec, WriteColor}; use ::WriteStyle; -use ::fmt::Formatter; +use ::fmt::{Formatter, Target}; pub(in ::fmt::writer) mod glob { pub use super::*; @@ -69,51 +69,98 @@ impl Formatter { } } -pub(in ::fmt::writer) struct BufferWriter(termcolor::BufferWriter); -pub(in ::fmt) struct Buffer(termcolor::Buffer); +pub(in ::fmt::writer) struct BufferWriter { + inner: termcolor::BufferWriter, + test_target: Option, +} + +pub(in ::fmt) struct Buffer { + inner: termcolor::Buffer, + test_target: Option, +} impl BufferWriter { - pub(in ::fmt::writer) fn stderr(write_style: WriteStyle) -> Self { - BufferWriter(termcolor::BufferWriter::stderr(write_style.into_color_choice())) + pub(in ::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 ::fmt::writer) fn stdout(write_style: WriteStyle) -> Self { - BufferWriter(termcolor::BufferWriter::stdout(write_style.into_color_choice())) + pub(in ::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 ::fmt::writer) fn buffer(&self) -> Buffer { - Buffer(self.0.buffer()) + Buffer { + inner: self.inner.buffer(), + test_target: self.test_target, + } } pub(in ::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> { - self.0.print(&buf.0) + 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 ::fmt) fn clear(&mut self) { - self.0.clear() + self.inner.clear() } pub(in ::fmt) fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) + self.inner.write(buf) } pub(in ::fmt) fn flush(&mut self) -> io::Result<()> { - self.0.flush() + self.inner.flush() } - #[cfg(test)] pub(in ::fmt) fn bytes(&self) -> &[u8] { - self.0.as_slice() + self.inner.as_slice() } fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { - self.0.set_color(spec) + // 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<()> { - self.0.reset() + // Ignore styles for test captured logs because they can't be printed + if self.test_target.is_none() { + self.inner.reset() + } else { + Ok(()) + } } } diff --git a/src/fmt/writer/termcolor/shim_impl.rs b/src/fmt/writer/termcolor/shim_impl.rs index b785dec0..fb473590 100644 --- a/src/fmt/writer/termcolor/shim_impl.rs +++ b/src/fmt/writer/termcolor/shim_impl.rs @@ -13,13 +13,13 @@ pub(in ::fmt::writer) struct BufferWriter { pub(in ::fmt) struct Buffer(Vec); impl BufferWriter { - pub(in ::fmt::writer) fn stderr(_: WriteStyle) -> Self { + pub(in ::fmt::writer) fn stderr(_is_test: bool, _write_style: WriteStyle) -> Self { BufferWriter { target: Target::Stderr, } } - pub(in ::fmt::writer) fn stdout(_: WriteStyle) -> Self { + pub(in ::fmt::writer) fn stdout(_is_test: bool, _write_style: WriteStyle) -> Self { BufferWriter { target: Target::Stdout, } diff --git a/src/lib.rs b/src/lib.rs index 8d17ed96..5a5a77c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,6 +139,33 @@ //! * `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; +//! # extern crate env_logger; +//! # fn main() {} +//! #[cfg(test)] +//! mod tests { +//! fn init() { +//! let _ = env_logger::builder().is_test(true).try_init(); +//! } +//! +//! #[test] +//! fn it_works() { +//! 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 //! @@ -157,9 +184,7 @@ //! The following example excludes the timestamp from the log output: //! //! ``` -//! use env_logger::Builder; -//! -//! Builder::from_default_env() +//! env_logger::builder() //! .default_format_timestamp(false) //! .init(); //! ``` @@ -180,9 +205,8 @@ //! //! ``` //! use std::io::Write; -//! use env_logger::Builder; //! -//! Builder::from_default_env() +//! env_logger::builder() //! .format(|buf, record| { //! writeln!(buf, "{}: {}", record.level(), record.args()) //! }) @@ -199,13 +223,14 @@ //! isn't set: //! //! ``` -//! use env_logger::{Builder, Env}; +//! use env_logger::Env; //! -//! Builder::from_env(Env::default().default_filter_or("warn")).init(); +//! 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 @@ -404,7 +429,7 @@ impl Builder { let env = env.into(); if let Some(s) = env.get_filter() { - builder.parse(&s); + builder.parse_filters(&s); } if let Some(s) = env.get_write_style() { @@ -579,7 +604,16 @@ impl Builder { /// environment variable. /// /// See the module documentation for more details. + #[deprecated(since = "0.6.0", note = "use `parse_filters` instead.")] pub fn parse(&mut self, filters: &str) -> &mut Self { + self.parse_filters(filters) + } + + /// 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 } @@ -630,7 +664,16 @@ impl Builder { /// /// See the module documentation for more details. pub fn parse_write_style(&mut self, write_style: &str) -> &mut Self { - self.writer.parse(write_style); + 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 } @@ -1068,6 +1111,23 @@ where 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> +{ + Builder::from_env(env) +} + #[cfg(test)] mod tests { use super::*; diff --git a/tests/init-twice-retains-filter.rs b/tests/init-twice-retains-filter.rs index 6ab08e99..c1256ef6 100644 --- a/tests/init-twice-retains-filter.rs +++ b/tests/init-twice-retains-filter.rs @@ -15,7 +15,7 @@ fn main() { // Init again using a different max level // This shouldn't clobber the level that was previously set env_logger::Builder::new() - .parse("info") + .parse_filters("info") .try_init() .unwrap_err(); From 2ae080e74da728d77f2e0408c734f245bb04904a Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 7 Mar 2019 13:44:27 +1000 Subject: [PATCH 04/18] prepare for 0.6.1 release (#128) --- Cargo.toml | 2 +- README.md | 4 ++-- src/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a7a3a0db..4da57985 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "env_logger" -version = "0.6.0" # remember to update html_root_url +version = "0.6.1" # remember to update html_root_url authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" diff --git a/README.md b/README.md index 437dd66f..d824f00c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ It must be added along with `log` to the project dependencies: ```toml [dependencies] log = "0.4.0" -env_logger = "0.6.0" +env_logger = "0.6.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. @@ -52,7 +52,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.6.0" +env_logger = "0.6.1" ``` ```rust diff --git a/src/lib.rs b/src/lib.rs index 5a5a77c3..185b4dc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -236,7 +236,7 @@ #![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.6.0")] + html_root_url = "https://docs.rs/env_logger/0.6.1")] #![cfg_attr(test, deny(warnings))] // When compiled for the rustc compiler itself we want to make sure that this is @@ -604,7 +604,7 @@ impl Builder { /// environment variable. /// /// See the module documentation for more details. - #[deprecated(since = "0.6.0", note = "use `parse_filters` instead.")] + #[deprecated(since = "0.6.1", note = "use `parse_filters` instead.")] pub fn parse(&mut self, filters: &str) -> &mut Self { self.parse_filters(filters) } From 33473f8a5164295b450ee951d6d3969773170659 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Mon, 11 Mar 2019 21:18:58 -0400 Subject: [PATCH 05/18] Redirect people to GitHub Releases for changes closes #119 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f849eeff --- /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 From 36a7256cd215afe1623f30d76364772b3fec2227 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 27 May 2019 09:06:34 +1000 Subject: [PATCH 06/18] Fix up test init example --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 185b4dc3..ad1fbce4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,6 +157,8 @@ //! //! #[test] //! fn it_works() { +//! init(); +//! //! info!("This record will be captured by `cargo test`"); //! //! assert_eq!(2, 1 + 1); From 89bcabf621071cbb33395122a3c68b4405f9ebc8 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 27 May 2019 10:26:38 +1000 Subject: [PATCH 07/18] Add some more examples for configuring env_logger (#133) --- README.md | 4 +++- examples/default.rs | 3 +++ examples/filters_from_code.rs | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 examples/filters_from_code.rs diff --git a/README.md b/README.md index d824f00c..9dafbc8e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ $ 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: @@ -147,4 +149,4 @@ builder.init(); 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. \ No newline at end of file +If you want to capture or interpret the output of `env_logger` programmatically then you should use a custom format. diff --git a/examples/default.rs b/examples/default.rs index 5d799fe0..302e38a2 100644 --- a/examples/default.rs +++ b/examples/default.rs @@ -22,6 +22,9 @@ extern crate env_logger; 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"); diff --git a/examples/filters_from_code.rs b/examples/filters_from_code.rs new file mode 100644 index 00000000..4bc00075 --- /dev/null +++ b/examples/filters_from_code.rs @@ -0,0 +1,21 @@ +/*! +Specify logging filters in code instead of using an environment variable. +*/ + +#[macro_use] +extern crate log; +extern crate env_logger; + +use env_logger::Env; + +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"); +} From 729c4a43cb1259a3f9a5f798da6c20fa4aa09cae Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 1 Jul 2019 08:56:12 +1000 Subject: [PATCH 08/18] fix up the build on nightly compilers (#135) --- examples/filters_from_code.rs | 2 -- src/fmt/mod.rs | 4 +++- src/lib.rs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/filters_from_code.rs b/examples/filters_from_code.rs index 4bc00075..ef5b9691 100644 --- a/examples/filters_from_code.rs +++ b/examples/filters_from_code.rs @@ -6,8 +6,6 @@ Specify logging filters in code instead of using an environment variable. extern crate log; extern crate env_logger; -use env_logger::Env; - fn main() { env_logger::builder() .filter_level(log::LevelFilter::Trace) diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index 635995e2..3f3d4975 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -117,6 +117,7 @@ pub(crate) struct Builder { pub default_format_timestamp_nanos: bool, pub default_format_module_path: bool, pub default_format_level: bool, + #[allow(unknown_lints, bare_trait_objects)] pub custom_format: Option io::Result<()> + Sync + Send>>, built: bool, } @@ -140,6 +141,7 @@ impl Builder { /// 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 io::Result<()> + Sync + Send> { assert!(!self.built, "attempt to re-use consumed builder"); @@ -353,4 +355,4 @@ mod tests { assert_eq!("log message\n", written); } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index ad1fbce4..52bda751 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -322,6 +322,7 @@ struct Var<'a> { pub struct Logger { writer: Writer, filter: Filter, + #[allow(unknown_lints, bare_trait_objects)] format: Box io::Result<()> + Sync + Send>, } From b598a2c96ff04da967fa2a0f8af0de6683b50a01 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 1 Jul 2019 09:17:09 +1000 Subject: [PATCH 09/18] prepare for 0.6.2 release (#136) --- Cargo.toml | 4 ++-- README.md | 4 ++-- src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4da57985..2cb1587c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "env_logger" -version = "0.6.1" # remember to update html_root_url +version = "0.6.2" # remember to update html_root_url authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" @@ -38,4 +38,4 @@ name = "init-twice-retains-filter" harness = false [features] -default = ["termcolor", "atty", "humantime", "regex"] \ No newline at end of file +default = ["termcolor", "atty", "humantime", "regex"] diff --git a/README.md b/README.md index 9dafbc8e..8dc92f12 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ It must be added along with `log` to the project dependencies: ```toml [dependencies] log = "0.4.0" -env_logger = "0.6.1" +env_logger = "0.6.2" ``` `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. @@ -54,7 +54,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.6.1" +env_logger = "0.6.2" ``` ```rust diff --git a/src/lib.rs b/src/lib.rs index 52bda751..37c43229 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,7 +238,7 @@ #![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.6.1")] + html_root_url = "https://docs.rs/env_logger/0.6.2")] #![cfg_attr(test, deny(warnings))] // When compiled for the rustc compiler itself we want to make sure that this is From efe01e0295b58e4e46a6706bc04c1aba802b7b3a Mon Sep 17 00:00:00 2001 From: Marco Cameriero Date: Tue, 16 Jul 2019 01:06:48 +0200 Subject: [PATCH 10/18] Indentation for multiline log messages (#134) --- src/fmt/mod.rs | 124 +++++++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 7 +++ 2 files changed, 127 insertions(+), 4 deletions(-) diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index 3f3d4975..76f5e0c1 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -117,6 +117,7 @@ pub(crate) struct Builder { pub default_format_timestamp_nanos: bool, pub default_format_module_path: bool, pub default_format_level: bool, + pub default_format_indent: Option, #[allow(unknown_lints, bare_trait_objects)] pub custom_format: Option io::Result<()> + Sync + Send>>, built: bool, @@ -129,6 +130,7 @@ impl Default for Builder { default_format_timestamp_nanos: false, default_format_module_path: true, default_format_level: true, + default_format_indent: Some(4), custom_format: None, built: false, } @@ -161,6 +163,7 @@ impl Builder { module_path: built.default_format_module_path, level: built.default_format_level, written_header_value: false, + indent: built.default_format_indent, buf, }; @@ -184,6 +187,7 @@ struct DefaultFormat<'a> { level: bool, timestamp_nanos: bool, written_header_value: bool, + indent: Option, buf: &'a mut Formatter, } @@ -289,7 +293,54 @@ impl<'a> DefaultFormat<'a> { } fn write_args(&mut self, record: &Record) -> io::Result<()> { - writeln!(self.buf, "{}", record.args()) + 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 { + 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(()) + } + + } } } @@ -303,7 +354,7 @@ mod tests { let buf = fmt.buf.buf.clone(); let record = Record::builder() - .args(format_args!("log message")) + .args(format_args!("log\nmessage")) .level(Level::Info) .file(Some("test.rs")) .line(Some(144)) @@ -330,10 +381,11 @@ mod tests { module_path: true, level: true, written_header_value: false, + indent: None, buf: &mut f, }); - assert_eq!("[INFO test::path] log message\n", written); + assert_eq!("[INFO test::path] log\nmessage\n", written); } #[test] @@ -350,9 +402,73 @@ mod tests { module_path: false, level: false, written_header_value: false, + indent: None, + buf: &mut f, + }); + + assert_eq!("log\nmessage\n", written); + } + + #[test] + fn default_format_indent_spaces() { + let writer = writer::Builder::new() + .write_style(WriteStyle::Never) + .build(); + + let mut f = Formatter::new(&writer); + + let written = write(DefaultFormat { + timestamp: false, + timestamp_nanos: false, + 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 default_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: false, + timestamp_nanos: false, + 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 default_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: false, + timestamp_nanos: false, + module_path: false, + level: false, + written_header_value: false, + indent: Some(4), buf: &mut f, }); - assert_eq!("log message\n", written); + assert_eq!("log\n message\n", written); } } diff --git a/src/lib.rs b/src/lib.rs index 37c43229..fd9bc5d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -529,6 +529,13 @@ impl Builder { self } + /// Configures the amount of spaces to use to indent multiline log records. + /// A value of `None` disables any kind of indentation. + pub fn default_format_indent(&mut self, indent: Option) -> &mut Self { + self.format.default_format_indent = indent; + self + } + /// Adds a directive to the filter for a specific module. /// /// # Examples From 6ccfb4ce05e138e637a23163ff4df6f278b67bfb Mon Sep 17 00:00:00 2001 From: Ossi Herrala Date: Tue, 10 Sep 2019 00:58:14 +0300 Subject: [PATCH 11/18] Bump minimum rust version up to 1.28.0. This is the oldest version regex 1.3 crate supports. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a6e0741..efa73da2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: rust sudo: false rust: - - 1.24.1 + - 1.28.0 - stable - beta - nightly From 92a5b2dfa56d6926c97f07919aed857c39ac571e Mon Sep 17 00:00:00 2001 From: Ossi Herrala Date: Tue, 10 Sep 2019 00:30:09 +0300 Subject: [PATCH 12/18] Add more timestamp precisions --- Cargo.toml | 2 +- src/fmt/humantime/extern_impl.rs | 67 ++++++++++++++++++++++++++---- src/fmt/mod.rs | 71 +++++++++++++++++--------------- src/lib.rs | 24 +++++++++-- 4 files changed, 120 insertions(+), 44 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2cb1587c..421d35ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ members = [ log = { version = "0.4", features = ["std"] } regex = { version = "1.0.3", optional = true } termcolor = { version = "1.0.2", optional = true } -humantime = { version = "1.1", optional = true } +humantime = { version = "1.3", optional = true } atty = { version = "0.2.5", optional = true } [[test]] diff --git a/src/fmt/humantime/extern_impl.rs b/src/fmt/humantime/extern_impl.rs index 596a2819..1d667a97 100644 --- a/src/fmt/humantime/extern_impl.rs +++ b/src/fmt/humantime/extern_impl.rs @@ -1,9 +1,12 @@ use std::fmt; use std::time::SystemTime; -use humantime::{format_rfc3339_nanos, format_rfc3339_seconds}; +use humantime::{ + format_rfc3339_micros, format_rfc3339_millis, + format_rfc3339_nanos, format_rfc3339_seconds, +}; -use ::fmt::Formatter; +use ::fmt::{Formatter, TimestampPrecision}; pub(in ::fmt) mod glob { pub use super::*; @@ -30,10 +33,50 @@ impl Formatter { /// /// [`Timestamp`]: struct.Timestamp.html pub fn timestamp(&self) -> Timestamp { - Timestamp(SystemTime::now()) + 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, + } } /// Get a [`PreciseTimestamp`] for the current date and time in UTC with nanos. + #[deprecated = "Use timestamp_nanos() instead"] pub fn precise_timestamp(&self) -> PreciseTimestamp { PreciseTimestamp(SystemTime::now()) } @@ -46,7 +89,10 @@ impl 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(SystemTime); +pub struct Timestamp { + time: SystemTime, + precision: TimestampPrecision, +} /// An [RFC3339] formatted timestamp with nanos. /// @@ -72,8 +118,15 @@ impl fmt::Debug for Timestamp { } impl fmt::Display for Timestamp { - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { - format_rfc3339_seconds(self.0).fmt(f) + 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) } } @@ -81,4 +134,4 @@ impl fmt::Display for PreciseTimestamp { fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { format_rfc3339_nanos(self.0).fmt(f) } -} \ No newline at end of file +} diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index 76f5e0c1..3cbbee6e 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -112,9 +112,25 @@ impl fmt::Debug for Formatter { } } +/// 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, +} + pub(crate) struct Builder { - pub default_format_timestamp: bool, - pub default_format_timestamp_nanos: bool, + pub default_format_timestamp: Option, pub default_format_module_path: bool, pub default_format_level: bool, pub default_format_indent: Option, @@ -126,8 +142,7 @@ pub(crate) struct Builder { impl Default for Builder { fn default() -> Self { Builder { - default_format_timestamp: true, - default_format_timestamp_nanos: false, + default_format_timestamp: Some(TimestampPrecision::Seconds), default_format_module_path: true, default_format_level: true, default_format_indent: Some(4), @@ -139,7 +154,7 @@ impl Default for Builder { 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. @@ -159,7 +174,6 @@ impl Builder { Box::new(move |buf, record| { let fmt = DefaultFormat { timestamp: built.default_format_timestamp, - timestamp_nanos: built.default_format_timestamp_nanos, module_path: built.default_format_module_path, level: built.default_format_level, written_header_value: false, @@ -179,13 +193,12 @@ type SubtleStyle = StyledValue<'static, &'static str>; type SubtleStyle = &'static str; /// The default format. -/// +/// /// This format needs to work with any combination of crate features. struct DefaultFormat<'a> { - timestamp: bool, + timestamp: Option, module_path: bool, level: bool, - timestamp_nanos: bool, written_header_value: bool, indent: Option, buf: &'a mut Formatter, @@ -251,22 +264,19 @@ impl<'a> DefaultFormat<'a> { fn write_timestamp(&mut self) -> io::Result<()> { #[cfg(feature = "humantime")] { - if !self.timestamp { - return Ok(()) - } - - if self.timestamp_nanos { - let ts_nanos = self.buf.precise_timestamp(); - self.write_header_value(ts_nanos) - } else { - let ts = self.buf.timestamp(); - self.write_header_value(ts) - } + use fmt::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"))] { - let _ = self.timestamp; - let _ = self.timestamp_nanos; Ok(()) } } @@ -294,7 +304,7 @@ impl<'a> DefaultFormat<'a> { fn write_args(&mut self, record: &Record) -> io::Result<()> { match self.indent { - + // Fast path for no indentation None => writeln!(self.buf, "{}", record.args()), @@ -376,8 +386,7 @@ mod tests { let mut f = Formatter::new(&writer); let written = write(DefaultFormat { - timestamp: false, - timestamp_nanos: false, + timestamp: None, module_path: true, level: true, written_header_value: false, @@ -397,8 +406,7 @@ mod tests { let mut f = Formatter::new(&writer); let written = write(DefaultFormat { - timestamp: false, - timestamp_nanos: false, + timestamp: None, module_path: false, level: false, written_header_value: false, @@ -418,8 +426,7 @@ mod tests { let mut f = Formatter::new(&writer); let written = write(DefaultFormat { - timestamp: false, - timestamp_nanos: false, + timestamp: None, module_path: true, level: true, written_header_value: false, @@ -439,8 +446,7 @@ mod tests { let mut f = Formatter::new(&writer); let written = write(DefaultFormat { - timestamp: false, - timestamp_nanos: false, + timestamp: None, module_path: true, level: true, written_header_value: false, @@ -460,8 +466,7 @@ mod tests { let mut f = Formatter::new(&writer); let written = write(DefaultFormat { - timestamp: false, - timestamp_nanos: false, + timestamp: None, module_path: false, level: false, written_header_value: false, diff --git a/src/lib.rs b/src/lib.rs index fd9bc5d2..d3667b87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -272,6 +272,8 @@ use self::filter::Filter; use self::fmt::Formatter; use self::fmt::writer::{self, Writer}; +pub use self::fmt::TimestampPrecision as Timestamp; + /// The default name for the environment variable to read filters from. pub const DEFAULT_FILTER_ENV: &'static str = "RUST_LOG"; @@ -518,14 +520,24 @@ impl Builder { } /// Whether or not to write the timestamp in the default format. + #[deprecated = "Use format_timestamp() instead"] pub fn default_format_timestamp(&mut self, write: bool) -> &mut Self { - self.format.default_format_timestamp = write; + if write { + self.format_timestamp(Some(Timestamp::Seconds)); + } else { + self.format_timestamp(None); + } self } - /// Whether or not to write the timestamp with nanos. + /// Whether or not to write the timestamp with nanosecond precision. + #[deprecated = "Use format_timestamp() instead"] pub fn default_format_timestamp_nanos(&mut self, write: bool) -> &mut Self { - self.format.default_format_timestamp_nanos = write; + // The old logic included two booleans: One for timestamp on/off and one + // for nanosecond precision. Mimic it here for compatibility. + if write && self.format.default_format_timestamp.is_some() { + self.format.default_format_timestamp = Some(fmt::TimestampPrecision::Nanos); + } self } @@ -536,6 +548,12 @@ impl Builder { self } + /// Configures if timestamp should be included and in what precision. + pub fn format_timestamp(&mut self, timestamp: Option) -> &mut Self { + self.format.default_format_timestamp = timestamp; + self + } + /// Adds a directive to the filter for a specific module. /// /// # Examples From 95cd4ed266be75d64bdf05c459c44bba5d759e30 Mon Sep 17 00:00:00 2001 From: Ossi Herrala Date: Tue, 10 Sep 2019 00:43:40 +0300 Subject: [PATCH 13/18] Trick the compiler to think we are using timestamp --- src/fmt/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index 3cbbee6e..b6a305b9 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -277,6 +277,9 @@ impl<'a> DefaultFormat<'a> { } #[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(()) } } From 7105e63885e2e325f3eceddcfe0ae6ae95e1ee0f Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 23 Sep 2019 13:34:54 +1000 Subject: [PATCH 14/18] make breaking changes to timestamp API --- examples/custom_default_format.rs | 2 +- src/lib.rs | 48 ++++++++++++++----------------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/examples/custom_default_format.rs b/examples/custom_default_format.rs index d1a45b60..180f198b 100644 --- a/examples/custom_default_format.rs +++ b/examples/custom_default_format.rs @@ -32,7 +32,7 @@ fn init_logger() { builder .default_format_level(false) - .default_format_timestamp_nanos(true); + .default_format_timestamp_nanos(); builder.init(); } diff --git a/src/lib.rs b/src/lib.rs index d3667b87..a02c5842 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -269,11 +269,9 @@ pub mod fmt; pub use self::fmt::glob::*; use self::filter::Filter; -use self::fmt::Formatter; +use self::fmt::{Formatter, TimestampPrecision}; use self::fmt::writer::{self, Writer}; -pub use self::fmt::TimestampPrecision as Timestamp; - /// The default name for the environment variable to read filters from. pub const DEFAULT_FILTER_ENV: &'static str = "RUST_LOG"; @@ -519,28 +517,6 @@ impl Builder { self } - /// Whether or not to write the timestamp in the default format. - #[deprecated = "Use format_timestamp() instead"] - pub fn default_format_timestamp(&mut self, write: bool) -> &mut Self { - if write { - self.format_timestamp(Some(Timestamp::Seconds)); - } else { - self.format_timestamp(None); - } - self - } - - /// Whether or not to write the timestamp with nanosecond precision. - #[deprecated = "Use format_timestamp() instead"] - pub fn default_format_timestamp_nanos(&mut self, write: bool) -> &mut Self { - // The old logic included two booleans: One for timestamp on/off and one - // for nanosecond precision. Mimic it here for compatibility. - if write && self.format.default_format_timestamp.is_some() { - self.format.default_format_timestamp = Some(fmt::TimestampPrecision::Nanos); - } - self - } - /// Configures the amount of spaces to use to indent multiline log records. /// A value of `None` disables any kind of indentation. pub fn default_format_indent(&mut self, indent: Option) -> &mut Self { @@ -549,11 +525,31 @@ impl Builder { } /// Configures if timestamp should be included and in what precision. - pub fn format_timestamp(&mut self, timestamp: Option) -> &mut Self { + pub fn default_format_timestamp(&mut self, timestamp: Option) -> &mut Self { self.format.default_format_timestamp = timestamp; self } + /// Configures the timestamp to use second precision. + pub fn default_format_timestamp_secs(&mut self) -> &mut Self { + self.default_format_timestamp(Some(TimestampPrecision::Seconds)) + } + + /// Configures the timestamp to use millisecond precision. + pub fn default_format_timestamp_millis(&mut self) -> &mut Self { + self.default_format_timestamp(Some(TimestampPrecision::Millis)) + } + + /// Configures the timestamp to use microsecond precision. + pub fn default_format_timestamp_micros(&mut self) -> &mut Self { + self.default_format_timestamp(Some(TimestampPrecision::Micros)) + } + + /// Configures the timestamp to use nanosecond precision. + pub fn default_format_timestamp_nanos(&mut self) -> &mut Self { + self.default_format_timestamp(Some(TimestampPrecision::Nanos)) + } + /// Adds a directive to the filter for a specific module. /// /// # Examples From 8209524a2898b8367b369437e7de2dd48a14edb4 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 23 Sep 2019 15:13:00 +1000 Subject: [PATCH 15/18] update to 2018 edition --- Cargo.toml | 1 + README.md | 2 - ci/Cargo.toml | 1 + ci/src/main.rs | 14 +- ci/src/permute.rs | 5 +- ci/src/task.rs | 18 +- examples/custom_default_format.rs | 7 +- examples/custom_format.rs | 61 +++-- examples/custom_logger.rs | 8 +- examples/default.rs | 1 - examples/direct_logger.rs | 7 +- examples/filters_from_code.rs | 1 - src/filter/mod.rs | 221 ++++++++++------- src/filter/regex.rs | 2 +- src/filter/string.rs | 4 +- src/fmt/humantime/extern_impl.rs | 29 +-- src/fmt/humantime/mod.rs | 2 +- src/fmt/humantime/shim_impl.rs | 4 +- src/fmt/mod.rs | 121 +++++----- src/fmt/writer/atty.rs | 10 +- src/fmt/writer/mod.rs | 33 ++- src/fmt/writer/termcolor/extern_impl.rs | 58 +++-- src/fmt/writer/termcolor/mod.rs | 2 +- src/fmt/writer/termcolor/shim_impl.rs | 28 +-- src/lib.rs | 303 +++++++++++------------- tests/init-twice-retains-filter.rs | 8 +- tests/log-in-log.rs | 9 +- tests/regexp_filter.rs | 14 +- 28 files changed, 478 insertions(+), 496 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 421d35ff..936ed7fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "env_logger" +edition = "2018" version = "0.6.2" # remember to update html_root_url authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" diff --git a/README.md b/README.md index 8dc92f12..5a30794b 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ env_logger = "0.6.2" ```rust #[macro_use] extern crate log; -extern crate env_logger; fn main() { env_logger::init(); @@ -69,7 +68,6 @@ fn add_one(num: i32) -> i32 { #[cfg(test)] mod tests { use super::*; - extern crate env_logger; fn init() { let _ = env_logger::builder().is_test(true).try_init(); diff --git a/ci/Cargo.toml b/ci/Cargo.toml index 01cd779a..87258b6b 100644 --- a/ci/Cargo.toml +++ b/ci/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "ci" +edition = "2018" version = "0.0.0" authors = ["The Rust Project Developers"] publish = false diff --git a/ci/src/main.rs b/ci/src/main.rs index 7464599b..d3619ca1 100644 --- a/ci/src/main.rs +++ b/ci/src/main.rs @@ -1,13 +1,8 @@ -mod task; mod permute; +mod task; fn main() { - let features = [ - "termcolor", - "humantime", - "atty", - "regex", - ]; + let features = ["termcolor", "humantime", "atty", "regex"]; // Run a default build if !task::test(Default::default()) { @@ -25,12 +20,13 @@ fn main() { // Run a set of permutations let failed = permute::all(&features) .into_iter() - .filter(|features| + .filter(|features| { !task::test(task::TestArgs { features: features.clone(), default_features: false, lib_only: true, - })) + }) + }) .collect::>(); if failed.len() > 0 { diff --git a/ci/src/permute.rs b/ci/src/permute.rs index b78a2ec4..059d0864 100644 --- a/ci/src/permute.rs +++ b/ci/src/permute.rs @@ -1,6 +1,9 @@ use std::collections::BTreeSet; -pub fn all(input: &[T]) -> BTreeSet> where T: Ord + Eq + Clone { +pub fn all(input: &[T]) -> BTreeSet> +where + T: Ord + Eq + Clone, +{ let mut permutations = BTreeSet::new(); if input.len() == 0 { diff --git a/ci/src/task.rs b/ci/src/task.rs index aebc77f3..2b6fab91 100644 --- a/ci/src/task.rs +++ b/ci/src/task.rs @@ -1,8 +1,5 @@ use std::collections::BTreeSet; -use std::process::{ - Command, - Stdio, -}; +use std::process::{Command, Stdio}; pub type Feature = &'static str; @@ -45,7 +42,7 @@ pub fn test(args: TestArgs) -> bool { let features = args.features_string(); let mut command = Command::new("cargo"); - + command .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) @@ -65,13 +62,14 @@ pub fn test(args: TestArgs) -> bool { } println!("running {:?}", command); - - let status = command - .status() - .expect("Failed to execute command"); + + let status = command.status().expect("Failed to execute command"); if !status.success() { - eprintln!("test execution failed for features: {}", features.as_ref().map(AsRef::as_ref).unwrap_or("")); + eprintln!( + "test execution failed for features: {}", + features.as_ref().map(AsRef::as_ref).unwrap_or("") + ); false } else { true diff --git a/examples/custom_default_format.rs b/examples/custom_default_format.rs index 180f198b..43979247 100644 --- a/examples/custom_default_format.rs +++ b/examples/custom_default_format.rs @@ -19,9 +19,8 @@ If you want to control the logging output completely, see the `custom_logger` ex #[macro_use] extern crate log; -extern crate env_logger; -use env_logger::{Env, Builder}; +use env_logger::{Builder, Env}; fn init_logger() { let env = Env::default() @@ -30,9 +29,7 @@ fn init_logger() { let mut builder = Builder::from_env(env); - builder - .default_format_level(false) - .default_format_timestamp_nanos(); + builder.format_level(false).format_timestamp_nanos(); builder.init(); } diff --git a/examples/custom_format.rs b/examples/custom_format.rs index c4563f50..df5a8e5b 100644 --- a/examples/custom_format.rs +++ b/examples/custom_format.rs @@ -17,38 +17,37 @@ $ export MY_LOG_STYLE=never If you want to control the logging output completely, see the `custom_logger` example. */ -#[macro_use] -extern crate log; -extern crate env_logger; - -use std::io::Write; - -use env_logger::{Env, Builder, fmt}; - -fn init_logger() { - let env = Env::default() - .filter("MY_LOG_LEVEL") - .write_style("MY_LOG_STYLE"); - - let mut builder = Builder::from_env(env); - - // Use a different format for writing log records - // The colors are only available when the `termcolor` dependency is (which it is by default) - #[cfg(feature = "termcolor")] - builder.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())) - }); - - builder.init(); -} - +#[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(); - info!("a log from `MyLogger`"); + 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 index 792c9c8e..85de45b2 100644 --- a/examples/custom_logger.rs +++ b/examples/custom_logger.rs @@ -12,12 +12,12 @@ If you only want to change the way logs are formatted, look at the `custom_forma #[macro_use] extern crate log; -extern crate env_logger; + use env_logger::filter::Filter; use log::{Log, Metadata, Record, SetLoggerError}; struct MyLogger { - inner: Filter + inner: Filter, } impl MyLogger { @@ -26,7 +26,7 @@ impl MyLogger { let mut builder = Builder::from_env("MY_LOG_LEVEL"); MyLogger { - inner: builder.build() + inner: builder.build(), } } @@ -50,7 +50,7 @@ impl Log for MyLogger { } } - fn flush(&self) { } + fn flush(&self) {} } fn main() { diff --git a/examples/default.rs b/examples/default.rs index 302e38a2..67bb0307 100644 --- a/examples/default.rs +++ b/examples/default.rs @@ -17,7 +17,6 @@ $ export MY_LOG_STYLE=never #[macro_use] extern crate log; -extern crate env_logger; use env_logger::Env; diff --git a/examples/direct_logger.rs b/examples/direct_logger.rs index 410230bc..4ba023fa 100644 --- a/examples/direct_logger.rs +++ b/examples/direct_logger.rs @@ -4,9 +4,6 @@ Using `env_logger::Logger` and the `log::Log` trait directly. This example doesn't rely on environment variables, or having a static logger installed. */ -extern crate log; -extern crate env_logger; - fn record() -> log::Record<'static> { let error_metadata = log::MetadataBuilder::new() .target("myApp") @@ -34,7 +31,7 @@ fn main() { .filter(None, log::LevelFilter::Error) .write_style(env_logger::WriteStyle::Never) .build(); - + stylish_logger.log(&record()); unstylish_logger.log(&record()); -} \ No newline at end of file +} diff --git a/examples/filters_from_code.rs b/examples/filters_from_code.rs index ef5b9691..4137c918 100644 --- a/examples/filters_from_code.rs +++ b/examples/filters_from_code.rs @@ -4,7 +4,6 @@ Specify logging filters in code instead of using an environment variable. #[macro_use] extern crate log; -extern crate env_logger; fn main() { env_logger::builder() diff --git a/src/filter/mod.rs b/src/filter/mod.rs index a0fe6a25..a994f4dc 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -1,15 +1,15 @@ //! 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 +//! 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 +//! 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. //! //! ``` @@ -54,15 +54,15 @@ //! } //! # 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::mem; use std::fmt; -use log::{Level, LevelFilter, Record, Metadata}; +use std::mem; #[cfg(feature = "regex")] #[path = "regex.rs"] @@ -73,11 +73,11 @@ mod inner; 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, @@ -85,10 +85,10 @@ pub struct 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 /// /// ``` @@ -111,7 +111,7 @@ pub struct Filter { /// let filter = builder.build(); /// } /// ``` -/// +/// /// [`Filter`]: struct.Filter.html pub struct Builder { directives: Vec, @@ -148,7 +148,8 @@ impl Filter { /// } /// ``` pub fn filter(&self) -> LevelFilter { - self.directives.iter() + self.directives + .iter() .map(|d| d.level) .max() .unwrap_or(LevelFilter::Off) @@ -213,9 +214,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 { + pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self { self.directives.push(Directive { name: module.map(|s| s.to_string()), level, @@ -226,7 +225,7 @@ impl Builder { /// 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); @@ -274,7 +273,7 @@ impl Default for Builder { } impl fmt::Debug for Filter { - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Filter") .field("filter", &self.filter) .field("directives", &self.directives) @@ -283,16 +282,14 @@ impl fmt::Debug for Filter { } impl fmt::Debug for Builder { - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.built { - f.debug_struct("Filter") - .field("built", &true) - .finish() + f.debug_struct("Filter").field("built", &true).finish() } else { f.debug_struct("Filter") - .field("filter", &self.filter) - .field("directives", &self.directives) - .finish() + .field("filter", &self.filter) + .field("directives", &self.directives) + .finish() } } } @@ -306,68 +303,75 @@ fn parse_spec(spec: &str) -> (Vec, Option) { let mods = parts.next(); let filter = parts.next(); if parts.next().is_some() { - eprintln!("warning: invalid logging spec '{}', \ - ignoring it (too many '/'s)", spec); + 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)), - } + mods.map(|m| { + for s in m.split(',') { + if s.len() == 0 { + continue; } - (Some(part0), Some(""), None) => (LevelFilter::max(), Some(part0)), - (Some(part0), Some(part1), None) => { - match part1.parse() { - Ok(num) => (num, Some(part0)), + 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", part1); - continue + eprintln!( + "warning: invalid logging spec '{}', \ + ignoring it", + s + ); + 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 - } + }; + 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 - } + Some(ref name) if !target.starts_with(&**name) => {} + Some(..) | None => return level <= directive.level, } } false @@ -377,7 +381,7 @@ fn enabled(directives: &[Directive], level: Level, target: &str) -> bool { mod tests { use log::{Level, LevelFilter}; - use super::{Builder, Filter, Directive, parse_spec, enabled}; + use super::{enabled, parse_spec, Builder, Directive, Filter}; fn make_logger_filter(dirs: Vec) -> Filter { let mut logger = Builder::new().build(); @@ -395,10 +399,10 @@ mod tests { #[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(); + .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")); } @@ -415,12 +419,12 @@ mod tests { let logger = make_logger_filter(vec![ Directive { name: Some("crate2".to_string()), - level: LevelFilter::Info + level: LevelFilter::Info, }, Directive { name: Some("crate1::mod1".to_string()), - level: LevelFilter::Warn - } + level: LevelFilter::Warn, + }, ]); assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1")); assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1")); @@ -431,8 +435,14 @@ mod tests { #[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 } + 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")); } @@ -440,8 +450,14 @@ mod tests { #[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 } + 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")); } @@ -449,9 +465,18 @@ mod tests { #[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 } + 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")); @@ -460,8 +485,14 @@ mod tests { #[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 } + 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")); @@ -470,8 +501,14 @@ mod tests { #[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 } + 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")); diff --git a/src/filter/regex.rs b/src/filter/regex.rs index a0426541..fb21528a 100644 --- a/src/filter/regex.rs +++ b/src/filter/regex.rs @@ -11,7 +11,7 @@ pub struct Filter { impl Filter { pub fn new(spec: &str) -> Result { - match Regex::new(spec){ + match Regex::new(spec) { Ok(r) => Ok(Filter { inner: r }), Err(e) => Err(e.to_string()), } diff --git a/src/filter/string.rs b/src/filter/string.rs index 96d7ecca..ea476e42 100644 --- a/src/filter/string.rs +++ b/src/filter/string.rs @@ -7,7 +7,9 @@ pub struct Filter { impl Filter { pub fn new(spec: &str) -> Result { - Ok(Filter { inner: spec.to_string() }) + Ok(Filter { + inner: spec.to_string(), + }) } pub fn is_match(&self, s: &str) -> bool { diff --git a/src/fmt/humantime/extern_impl.rs b/src/fmt/humantime/extern_impl.rs index 1d667a97..19dec1b6 100644 --- a/src/fmt/humantime/extern_impl.rs +++ b/src/fmt/humantime/extern_impl.rs @@ -2,13 +2,12 @@ use std::fmt; use std::time::SystemTime; use humantime::{ - format_rfc3339_micros, format_rfc3339_millis, - format_rfc3339_nanos, format_rfc3339_seconds, + format_rfc3339_micros, format_rfc3339_millis, format_rfc3339_nanos, format_rfc3339_seconds, }; -use ::fmt::{Formatter, TimestampPrecision}; +use crate::fmt::{Formatter, TimestampPrecision}; -pub(in ::fmt) mod glob { +pub(in crate::fmt) mod glob { pub use super::*; } @@ -74,12 +73,6 @@ impl Formatter { precision: TimestampPrecision::Nanos, } } - - /// Get a [`PreciseTimestamp`] for the current date and time in UTC with nanos. - #[deprecated = "Use timestamp_nanos() instead"] - pub fn precise_timestamp(&self) -> PreciseTimestamp { - PreciseTimestamp(SystemTime::now()) - } } /// An [RFC3339] formatted timestamp. @@ -94,12 +87,6 @@ pub struct Timestamp { precision: TimestampPrecision, } -/// An [RFC3339] formatted timestamp with nanos. -/// -/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt -#[derive(Debug)] -pub struct PreciseTimestamp(SystemTime); - impl fmt::Debug for Timestamp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { /// A `Debug` wrapper for `Timestamp` that uses the `Display` implementation. @@ -112,8 +99,8 @@ impl fmt::Debug for Timestamp { } f.debug_tuple("Timestamp") - .field(&TimestampValue(&self)) - .finish() + .field(&TimestampValue(&self)) + .finish() } } @@ -129,9 +116,3 @@ impl fmt::Display for Timestamp { formatter(self.time).fmt(f) } } - -impl fmt::Display for PreciseTimestamp { - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { - format_rfc3339_nanos(self.0).fmt(f) - } -} diff --git a/src/fmt/humantime/mod.rs b/src/fmt/humantime/mod.rs index c4f7599c..ac23ae24 100644 --- a/src/fmt/humantime/mod.rs +++ b/src/fmt/humantime/mod.rs @@ -8,4 +8,4 @@ Its public API is available when the `humantime` crate is available. #[cfg_attr(not(feature = "humantime"), path = "shim_impl.rs")] mod imp; -pub(in ::fmt) use self::imp::*; +pub(in crate::fmt) use self::imp::*; diff --git a/src/fmt/humantime/shim_impl.rs b/src/fmt/humantime/shim_impl.rs index 0f753400..906bf9e4 100644 --- a/src/fmt/humantime/shim_impl.rs +++ b/src/fmt/humantime/shim_impl.rs @@ -2,6 +2,4 @@ Timestamps aren't available when we don't have a `humantime` dependency. */ -pub(in ::fmt) mod glob { - -} +pub(in crate::fmt) mod glob {} diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index b6a305b9..e699e214 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -29,24 +29,48 @@ //! [`Builder::format`]: ../struct.Builder.html#method.format //! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html -use std::io::prelude::*; -use std::{io, fmt, mem}; -use std::rc::Rc; use std::cell::RefCell; use std::fmt::Display; +use std::io::prelude::*; +use std::rc::Rc; +use std::{fmt, io, mem}; use log::Record; -pub(crate) mod writer; mod humantime; +pub(crate) mod writer; pub use self::humantime::glob::*; pub use self::writer::glob::*; -use self::writer::{Writer, Buffer}; +use self::writer::{Buffer, Writer}; pub(crate) mod glob { - pub use super::{Target, WriteStyle}; + 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. @@ -107,33 +131,16 @@ impl Write for Formatter { } impl fmt::Debug for Formatter { - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Formatter").finish() } } -/// 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, -} - pub(crate) struct Builder { - pub default_format_timestamp: Option, - pub default_format_module_path: bool, - pub default_format_level: bool, - pub default_format_indent: Option, + pub format_timestamp: Option, + pub format_module_path: bool, + pub format_level: bool, + pub format_indent: Option, #[allow(unknown_lints, bare_trait_objects)] pub custom_format: Option io::Result<()> + Sync + Send>>, built: bool, @@ -142,10 +149,10 @@ pub(crate) struct Builder { impl Default for Builder { fn default() -> Self { Builder { - default_format_timestamp: Some(TimestampPrecision::Seconds), - default_format_module_path: true, - default_format_level: true, - default_format_indent: Some(4), + format_timestamp: Some(Default::default()), + format_module_path: true, + format_level: true, + format_indent: Some(4), custom_format: None, built: false, } @@ -162,22 +169,24 @@ impl Builder { pub fn build(&mut self) -> Box io::Result<()> + Sync + Send> { assert!(!self.built, "attempt to re-use consumed builder"); - let built = mem::replace(self, Builder { - built: true, - ..Default::default() - }); + let built = mem::replace( + self, + Builder { + built: true, + ..Default::default() + }, + ); if let Some(fmt) = built.custom_format { fmt - } - else { + } else { Box::new(move |buf, record| { let fmt = DefaultFormat { - timestamp: built.default_format_timestamp, - module_path: built.default_format_module_path, - level: built.default_format_level, + timestamp: built.format_timestamp, + module_path: built.format_module_path, + level: built.format_level, written_header_value: false, - indent: built.default_format_indent, + indent: built.format_indent, buf, }; @@ -217,7 +226,8 @@ impl<'a> DefaultFormat<'a> { fn subtle_style(&self, text: &'static str) -> SubtleStyle { #[cfg(feature = "termcolor")] { - self.buf.style() + self.buf + .style() .set_color(Color::Black) .set_intense(true) .into_value(text) @@ -244,7 +254,7 @@ impl<'a> DefaultFormat<'a> { fn write_level(&mut self, record: &Record) -> io::Result<()> { if !self.level { - return Ok(()) + return Ok(()); } let level = { @@ -264,7 +274,7 @@ impl<'a> DefaultFormat<'a> { fn write_timestamp(&mut self) -> io::Result<()> { #[cfg(feature = "humantime")] { - use fmt::TimestampPrecision::*; + use self::TimestampPrecision::*; let ts = match self.timestamp { None => return Ok(()), Some(Seconds) => self.buf.timestamp_seconds(), @@ -286,7 +296,7 @@ impl<'a> DefaultFormat<'a> { fn write_module_path(&mut self, record: &Record) -> io::Result<()> { if !self.module_path { - return Ok(()) + return Ok(()); } if let Some(module_path) = record.module_path() { @@ -307,20 +317,18 @@ impl<'a> DefaultFormat<'a> { 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 + indent_count: usize, } - impl<'a, 'b> Write for IndentWrapper<'a, 'b> { + impl<'a, 'b> Write for IndentWrapper<'a, 'b> { fn write(&mut self, buf: &[u8]) -> io::Result { let mut first = true; for chunk in buf.split(|&x| x == b'\n') { @@ -343,7 +351,7 @@ impl<'a> DefaultFormat<'a> { { let mut wrapper = IndentWrapper { fmt: self, - indent_count + indent_count, }; write!(wrapper, "{}", record.args())?; } @@ -352,7 +360,6 @@ impl<'a> DefaultFormat<'a> { Ok(()) } - } } } @@ -381,7 +388,7 @@ mod tests { } #[test] - fn default_format_with_header() { + fn format_with_header() { let writer = writer::Builder::new() .write_style(WriteStyle::Never) .build(); @@ -401,7 +408,7 @@ mod tests { } #[test] - fn default_format_no_header() { + fn format_no_header() { let writer = writer::Builder::new() .write_style(WriteStyle::Never) .build(); @@ -421,7 +428,7 @@ mod tests { } #[test] - fn default_format_indent_spaces() { + fn format_indent_spaces() { let writer = writer::Builder::new() .write_style(WriteStyle::Never) .build(); @@ -441,7 +448,7 @@ mod tests { } #[test] - fn default_format_indent_zero_spaces() { + fn format_indent_zero_spaces() { let writer = writer::Builder::new() .write_style(WriteStyle::Never) .build(); @@ -461,7 +468,7 @@ mod tests { } #[test] - fn default_format_indent_spaces_no_header() { + fn format_indent_spaces_no_header() { let writer = writer::Builder::new() .write_style(WriteStyle::Never) .build(); diff --git a/src/fmt/writer/atty.rs b/src/fmt/writer/atty.rs index c441cf08..f6718413 100644 --- a/src/fmt/writer/atty.rs +++ b/src/fmt/writer/atty.rs @@ -11,24 +11,24 @@ from being printed. mod imp { use atty; - pub(in ::fmt) fn is_stdout() -> bool { + pub(in crate::fmt) fn is_stdout() -> bool { atty::is(atty::Stream::Stdout) } - pub(in ::fmt) fn is_stderr() -> bool { + pub(in crate::fmt) fn is_stderr() -> bool { atty::is(atty::Stream::Stderr) } } #[cfg(not(feature = "atty"))] mod imp { - pub(in ::fmt) fn is_stdout() -> bool { + pub(in crate::fmt) fn is_stdout() -> bool { false } - pub(in ::fmt) fn is_stderr() -> bool { + pub(in crate::fmt) fn is_stderr() -> bool { false } } -pub(in ::fmt) use self::imp::*; +pub(in crate::fmt) use self::imp::*; diff --git a/src/fmt/writer/mod.rs b/src/fmt/writer/mod.rs index d84e4146..6ee63a39 100644 --- a/src/fmt/writer/mod.rs +++ b/src/fmt/writer/mod.rs @@ -1,16 +1,16 @@ -mod termcolor; mod atty; +mod termcolor; -use std::{fmt, io}; +use self::atty::{is_stderr, is_stdout}; use self::termcolor::BufferWriter; -use self::atty::{is_stdout, is_stderr}; +use std::{fmt, io}; -pub(in ::fmt) mod glob { +pub(in crate::fmt) mod glob { pub use super::termcolor::glob::*; pub use super::*; } -pub(in ::fmt) use self::termcolor::Buffer; +pub(in crate::fmt) use self::termcolor::Buffer; /// Log target, either `stdout` or `stderr`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -55,11 +55,11 @@ impl Writer { self.write_style } - pub(in ::fmt) fn buffer(&self) -> Buffer { + pub(in crate::fmt) fn buffer(&self) -> Buffer { self.inner.buffer() } - pub(in ::fmt) fn print(&self, buf: &Buffer) -> io::Result<()> { + pub(in crate::fmt) fn print(&self, buf: &Buffer) -> io::Result<()> { self.inner.print(buf) } } @@ -127,7 +127,7 @@ impl Builder { } else { WriteStyle::Never } - }, + } color_choice => color_choice, }; @@ -150,16 +150,16 @@ impl Default for Builder { } impl fmt::Debug for Builder { - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Logger") - .field("target", &self.target) - .field("write_style", &self.write_style) - .finish() + .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 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Writer").finish() } } @@ -192,12 +192,7 @@ mod tests { #[test] fn parse_write_style_invalid() { - let inputs = vec![ - "", - "true", - "false", - "NEVER!!" - ]; + 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 index 0c2d1387..2d38e375 100644 --- a/src/fmt/writer/termcolor/extern_impl.rs +++ b/src/fmt/writer/termcolor/extern_impl.rs @@ -1,16 +1,15 @@ use std::borrow::Cow; +use std::cell::RefCell; use std::fmt; use std::io::{self, Write}; -use std::cell::RefCell; use std::rc::Rc; use log::Level; use termcolor::{self, ColorChoice, ColorSpec, WriteColor}; -use ::WriteStyle; -use ::fmt::{Formatter, Target}; +use crate::fmt::{Formatter, Target, WriteStyle}; -pub(in ::fmt::writer) mod glob { +pub(in crate::fmt::writer) mod glob { pub use super::*; } @@ -47,7 +46,7 @@ impl Formatter { } /// 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(); @@ -62,54 +61,46 @@ impl Formatter { } /// 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 ::fmt::writer) struct BufferWriter { +pub(in crate::fmt::writer) struct BufferWriter { inner: termcolor::BufferWriter, test_target: Option, } -pub(in ::fmt) struct Buffer { +pub(in crate::fmt) struct Buffer { inner: termcolor::Buffer, test_target: Option, } impl BufferWriter { - pub(in ::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self { + 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(Target::Stderr) } else { None }, } } - pub(in ::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self { + 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(Target::Stdout) } else { None }, } } - pub(in ::fmt::writer) fn buffer(&self) -> Buffer { + pub(in crate::fmt::writer) fn buffer(&self) -> Buffer { Buffer { inner: self.inner.buffer(), test_target: self.test_target, } } - pub(in ::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> { + 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. @@ -129,19 +120,19 @@ impl BufferWriter { } impl Buffer { - pub(in ::fmt) fn clear(&mut self) { + pub(in crate::fmt) fn clear(&mut self) { self.inner.clear() } - pub(in ::fmt) fn write(&mut self, buf: &[u8]) -> io::Result { + pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } - pub(in ::fmt) fn flush(&mut self) -> io::Result<()> { + pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> { self.inner.flush() } - pub(in ::fmt) fn bytes(&self) -> &[u8] { + pub(in crate::fmt) fn bytes(&self) -> &[u8] { self.inner.as_slice() } @@ -374,7 +365,7 @@ impl Style { pub fn value(&self, value: T) -> StyledValue { StyledValue { style: Cow::Borrowed(self), - value + value, } } @@ -382,7 +373,7 @@ impl Style { pub(crate) fn into_value(&mut self, value: T) -> StyledValue<'static, T> { StyledValue { style: Cow::Owned(self.clone()), - value + value, } } } @@ -392,7 +383,11 @@ impl<'a, T> StyledValue<'a, T> { where F: FnOnce() -> fmt::Result, { - self.style.buf.borrow_mut().set_color(&self.style.spec).map_err(|_| fmt::Error)?; + 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(); @@ -403,7 +398,7 @@ impl<'a, T> StyledValue<'a, T> { } impl fmt::Debug for Style { - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Style").field("spec", &self.spec).finish() } } @@ -429,7 +424,8 @@ impl_styled_value_fmt!( fmt::UpperHex, fmt::LowerHex, fmt::UpperExp, - fmt::LowerExp); + fmt::LowerExp +); // The `Color` type is copied from https://github.com/BurntSushi/ripgrep/tree/master/termcolor diff --git a/src/fmt/writer/termcolor/mod.rs b/src/fmt/writer/termcolor/mod.rs index df0f7859..f3e6768c 100644 --- a/src/fmt/writer/termcolor/mod.rs +++ b/src/fmt/writer/termcolor/mod.rs @@ -9,4 +9,4 @@ The terminal printing is shimmed when the `termcolor` crate is not available. #[cfg_attr(not(feature = "termcolor"), path = "shim_impl.rs")] mod imp; -pub(in ::fmt) use self::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 index fb473590..563f8ad4 100644 --- a/src/fmt/writer/termcolor/shim_impl.rs +++ b/src/fmt/writer/termcolor/shim_impl.rs @@ -1,35 +1,33 @@ use std::io; -use fmt::{WriteStyle, Target}; +use crate::fmt::{Target, WriteStyle}; -pub(in ::fmt::writer) mod glob { - -} +pub(in crate::fmt::writer) mod glob {} -pub(in ::fmt::writer) struct BufferWriter { +pub(in crate::fmt::writer) struct BufferWriter { target: Target, } -pub(in ::fmt) struct Buffer(Vec); +pub(in crate::fmt) struct Buffer(Vec); impl BufferWriter { - pub(in ::fmt::writer) fn stderr(_is_test: bool, _write_style: WriteStyle) -> Self { + pub(in crate::fmt::writer) fn stderr(_is_test: bool, _write_style: WriteStyle) -> Self { BufferWriter { target: Target::Stderr, } } - pub(in ::fmt::writer) fn stdout(_is_test: bool, _write_style: WriteStyle) -> Self { + pub(in crate::fmt::writer) fn stdout(_is_test: bool, _write_style: WriteStyle) -> Self { BufferWriter { target: Target::Stdout, } } - pub(in ::fmt::writer) fn buffer(&self) -> Buffer { + pub(in crate::fmt::writer) fn buffer(&self) -> Buffer { Buffer(Vec::new()) } - pub(in ::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> { + 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` @@ -45,21 +43,21 @@ impl BufferWriter { } impl Buffer { - pub(in ::fmt) fn clear(&mut self) { + pub(in crate::fmt) fn clear(&mut self) { self.0.clear(); } - pub(in ::fmt) fn write(&mut self, buf: &[u8]) -> io::Result { + pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result { self.0.extend(buf); Ok(buf.len()) } - pub(in ::fmt) fn flush(&mut self) -> io::Result<()> { + pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> { Ok(()) } #[cfg(test)] - pub(in ::fmt) fn bytes(&self) -> &[u8] { + pub(in crate::fmt) fn bytes(&self) -> &[u8] { &self.0 } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index a02c5842..abc1d51b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,6 @@ //! //! ``` //! #[macro_use] extern crate log; -//! extern crate env_logger; //! //! use log::Level; //! @@ -139,33 +138,32 @@ //! * `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; -//! # extern crate env_logger; //! # 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. //! @@ -179,32 +177,32 @@ //! * `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() -//! .default_format_timestamp(false) +//! .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 +//! +//! 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 +//! +//! 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; //! @@ -214,54 +212,43 @@ //! }) //! .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.6.2")] +#![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.6.2" +)] #![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)] -extern crate log; +use std::{borrow::Cow, cell::RefCell, env, io}; -#[cfg(feature = "termcolor")] -extern crate termcolor; -#[cfg(feature = "humantime")] -extern crate humantime; -#[cfg(feature = "atty")] -extern crate atty; - -use std::{env, io}; -use std::borrow::Cow; -use std::cell::RefCell; - -use log::{Log, LevelFilter, Record, SetLoggerError, Metadata}; +use log::{LevelFilter, Log, Metadata, Record, SetLoggerError}; pub mod filter; pub mod fmt; @@ -269,8 +256,8 @@ pub mod fmt; pub use self::fmt::glob::*; use self::filter::Filter; -use self::fmt::{Formatter, TimestampPrecision}; 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"; @@ -334,9 +321,7 @@ pub struct Logger { /// # Examples /// /// ``` -/// #[macro_use] -/// extern crate log; -/// extern crate env_logger; +/// #[macro_use] extern crate log; /// /// use std::env; /// use std::io::Write; @@ -364,30 +349,28 @@ pub struct Builder { 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: - /// + /// /// ``` - /// # extern crate log; - /// # extern crate env_logger; /// # 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 @@ -402,13 +385,13 @@ impl Builder { /// 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(); /// ``` @@ -426,7 +409,7 @@ impl Builder { /// ``` pub fn from_env<'a, E>(env: E) -> Self where - E: Into> + E: Into>, { let mut builder = Builder::new(); let env = env.into(); @@ -443,18 +426,18 @@ impl 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(); /// ``` @@ -473,17 +456,17 @@ impl Builder { /// `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())); /// ``` /// @@ -491,63 +474,64 @@ impl Builder { /// [`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(&mut self, format: F) -> &mut Self - where F: Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send + 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.custom_format = None; + self.format = Default::default(); self } /// Whether or not to write the level in the default format. - pub fn default_format_level(&mut self, write: bool) -> &mut Self { - self.format.default_format_level = write; + 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 default_format_module_path(&mut self, write: bool) -> &mut Self { - self.format.default_format_module_path = write; + 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 default_format_indent(&mut self, indent: Option) -> &mut Self { - self.format.default_format_indent = indent; + pub fn format_indent(&mut self, indent: Option) -> &mut Self { + self.format.format_indent = indent; self } /// Configures if timestamp should be included and in what precision. - pub fn default_format_timestamp(&mut self, timestamp: Option) -> &mut Self { - self.format.default_format_timestamp = timestamp; + pub fn format_timestamp(&mut self, timestamp: Option) -> &mut Self { + self.format.format_timestamp = timestamp; self } /// Configures the timestamp to use second precision. - pub fn default_format_timestamp_secs(&mut self) -> &mut Self { - self.default_format_timestamp(Some(TimestampPrecision::Seconds)) + 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 default_format_timestamp_millis(&mut self) -> &mut Self { - self.default_format_timestamp(Some(TimestampPrecision::Millis)) + 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 default_format_timestamp_micros(&mut self) -> &mut Self { - self.default_format_timestamp(Some(TimestampPrecision::Micros)) + 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 default_format_timestamp_nanos(&mut self) -> &mut Self { - self.default_format_timestamp(Some(TimestampPrecision::Nanos)) + 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. @@ -557,8 +541,6 @@ impl Builder { /// Only include messages for warning and above for logs in `path::to::module`: /// /// ``` - /// # extern crate log; - /// # extern crate env_logger; /// # fn main() { /// use log::LevelFilter; /// use env_logger::Builder; @@ -580,8 +562,6 @@ impl Builder { /// Only include messages for warning and above for logs in `path::to::module`: /// /// ``` - /// # extern crate log; - /// # extern crate env_logger; /// # fn main() { /// use log::LevelFilter; /// use env_logger::Builder; @@ -600,39 +580,26 @@ 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. - /// + /// /// # Examples - /// + /// /// Only include messages for warning and above for logs in `path::to::module`: - /// + /// /// ``` - /// # extern crate log; - /// # extern crate env_logger; /// # 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 { + 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. - #[deprecated(since = "0.6.1", note = "use `parse_filters` instead.")] - pub fn parse(&mut self, filters: &str) -> &mut Self { - self.parse_filters(filters) - } - /// Parses the directives string in the same form as the `RUST_LOG` /// environment variable. /// @@ -645,16 +612,16 @@ impl Builder { /// 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 { @@ -666,16 +633,16 @@ impl Builder { /// /// 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 { @@ -693,7 +660,7 @@ impl Builder { } /// 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 { @@ -733,7 +700,8 @@ impl Builder { /// 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"); + self.try_init() + .expect("Builder::init should not be called after logger initialized"); } /// Build an env logger. @@ -780,8 +748,8 @@ impl Logger { /// let logger = Logger::from_env(env); /// ``` pub fn from_env<'a, E>(env: E) -> Self - where - E: Into> + where + E: Into>, { Builder::from_env(env).build() } @@ -861,14 +829,15 @@ impl Log for Logger { if formatter.write_style() != self.writer.write_style() { *formatter = Formatter::new(&self.writer) } - }, - ref mut tl_buf => *tl_buf = Some(Formatter::new(&self.writer)) + } + ref mut tl_buf => *tl_buf = Some(Formatter::new(&self.writer)), } // The format is guaranteed to be `Some` by this point let mut formatter = tl_buf.as_mut().unwrap(); - let _ = (self.format)(&mut formatter, record).and_then(|_| formatter.print(&self.writer)); + let _ = (self.format)(&mut formatter, record) + .and_then(|_| formatter.print(&self.writer)); // Always clear the buffer afterwards formatter.clear(); @@ -888,7 +857,7 @@ impl<'a> Env<'a> { /// Specify an environment variable to read the filter from. pub fn filter(mut self, filter_env: E) -> Self where - E: Into> + E: Into>, { self.filter = Var::new(filter_env); @@ -909,7 +878,7 @@ impl<'a> Env<'a> { } /// 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(mut self, default: V) -> Self where @@ -927,7 +896,7 @@ impl<'a> Env<'a> { /// Specify an environment variable to read the style from. pub fn write_style(mut self, write_style_env: E) -> Self where - E: Into> + E: Into>, { self.write_style = Var::new(write_style_env); @@ -938,9 +907,9 @@ impl<'a> Env<'a> { /// /// If the variable is not set, the default value will be used. pub fn write_style_or(mut self, write_style_env: E, default: V) -> Self - where - E: Into>, - V: Into>, + where + E: Into>, + V: Into>, { self.write_style = Var::new_with_default(write_style_env, default); @@ -951,8 +920,8 @@ impl<'a> Env<'a> { /// /// If the variable is not set, the default value will be used. pub fn default_write_style_or(mut self, default: V) -> Self - where - V: Into>, + where + V: Into>, { self.write_style = Var::new_with_default(DEFAULT_WRITE_STYLE_ENV, default); @@ -966,8 +935,8 @@ impl<'a> Env<'a> { impl<'a> Var<'a> { fn new(name: E) -> Self - where - E: Into>, + where + E: Into>, { Var { name: name.into(), @@ -989,15 +958,13 @@ impl<'a> Var<'a> { fn get(&self) -> Option { env::var(&*self.name) .ok() - .or_else(|| self.default - .to_owned() - .map(|v| v.into_owned())) + .or_else(|| self.default.to_owned().map(|v| v.into_owned())) } } impl<'a, T> From for Env<'a> where - T: Into> + T: Into>, { fn from(filter_env: T) -> Self { Env::default().filter(filter_env.into()) @@ -1014,28 +981,26 @@ impl<'a> Default for Env<'a> { } mod std_fmt_impls { - use std::fmt; use super::*; + use std::fmt; - impl fmt::Debug for Logger{ - fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + 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 { + 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() + f.debug_struct("Logger").field("built", &true).finish() } else { f.debug_struct("Logger") - .field("filter", &self.filter) - .field("writer", &self.writer) - .finish() + .field("filter", &self.filter) + .field("writer", &self.writer) + .finish() } } } @@ -1098,7 +1063,7 @@ pub fn init() { /// library has already initialized a global logger. pub fn try_init_from_env<'a, E>(env: E) -> Result<(), SetLoggerError> where - E: Into> + E: Into>, { let mut builder = Builder::from_env(env); @@ -1130,24 +1095,25 @@ where /// library has already initialized a global logger. pub fn init_from_env<'a, E>(env: E) where - E: Into> + E: Into>, { - try_init_from_env(env).expect("env_logger::init_from_env should not be called after logger initialized"); + 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> + E: Into>, { Builder::from_env(env) } @@ -1169,7 +1135,10 @@ mod tests { 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"); + 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()); } @@ -1178,7 +1147,8 @@ mod tests { 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"); + 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()); } @@ -1187,7 +1157,10 @@ mod tests { 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"); + 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 index c1256ef6..673da3fd 100644 --- a/tests/init-twice-retains-filter.rs +++ b/tests/init-twice-retains-filter.rs @@ -1,8 +1,8 @@ -extern crate log; extern crate env_logger; +extern crate log; -use std::process; use std::env; +use std::process; use std::str; fn main() { @@ -20,7 +20,7 @@ fn main() { .unwrap_err(); assert_eq!(log::LevelFilter::Debug, log::max_level()); - return + return; } let exe = env::current_exe().unwrap(); @@ -30,7 +30,7 @@ fn main() { .output() .unwrap_or_else(|e| panic!("Unable to start child process: {}", e)); if out.status.success() { - return + return; } println!("test failed: {}", out.status); diff --git a/tests/log-in-log.rs b/tests/log-in-log.rs index 6b2c47e7..89517ff3 100644 --- a/tests/log-in-log.rs +++ b/tests/log-in-log.rs @@ -1,9 +1,10 @@ -#[macro_use] extern crate log; +#[macro_use] +extern crate log; extern crate env_logger; -use std::process; -use std::fmt; use std::env; +use std::fmt; +use std::process; use std::str; struct Foo; @@ -28,7 +29,7 @@ fn main() { .output() .unwrap_or_else(|e| panic!("Unable to start child process: {}", e)); if out.status.success() { - return + return; } println!("test failed: {}", out.status); diff --git a/tests/regexp_filter.rs b/tests/regexp_filter.rs index d23e9223..40178bac 100644 --- a/tests/regexp_filter.rs +++ b/tests/regexp_filter.rs @@ -1,8 +1,9 @@ -#[macro_use] extern crate log; +#[macro_use] +extern crate log; extern crate env_logger; -use std::process; use std::env; +use std::process; use std::str; fn main() { @@ -25,7 +26,9 @@ fn run_child(rust_log: String) -> bool { .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") + str::from_utf8(out.stderr.as_ref()) + .unwrap() + .contains("XYZ Message") } fn assert_message_printed(rust_log: &str) { @@ -36,7 +39,10 @@ fn assert_message_printed(rust_log: &str) { 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) + panic!( + "RUST_LOG={} should not allow the test log message", + rust_log + ) } } From dc65e48bae6e13c302451d58e2002f1354d5db01 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Tue, 24 Sep 2019 09:56:34 +1000 Subject: [PATCH 16/18] bump msrv to 1.31.0 for editions --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index efa73da2..af8f18d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: rust sudo: false rust: - - 1.28.0 + - 1.31.0 - stable - beta - nightly From ef10fa512ab253ca86cbb9f8f95731b64aadf323 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Tue, 24 Sep 2019 10:01:57 +1000 Subject: [PATCH 17/18] use specific log version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 936ed7fa..dc150c6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ members = [ ] [dependencies] -log = { version = "0.4", features = ["std"] } +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 } From 058655eb6875414debae568c0346038eca83c1fe Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Tue, 24 Sep 2019 10:12:19 +1000 Subject: [PATCH 18/18] prepare for 0.7.0 release --- Cargo.toml | 2 +- README.md | 4 ++-- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dc150c6f..d0407187 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "env_logger" edition = "2018" -version = "0.6.2" # remember to update html_root_url +version = "0.7.0" # remember to update html_root_url authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" diff --git a/README.md b/README.md index 5a30794b..9a739fd6 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ It must be added along with `log` to the project dependencies: ```toml [dependencies] log = "0.4.0" -env_logger = "0.6.2" +env_logger = "0.7.0" ``` `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. @@ -53,7 +53,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.6.2" +env_logger = "0.7.0" ``` ```rust diff --git a/src/lib.rs b/src/lib.rs index abc1d51b..3679745c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -237,7 +237,7 @@ #![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.6.2" + html_root_url = "https://docs.rs/env_logger/0.7.0" )] #![cfg_attr(test, deny(warnings))] // When compiled for the rustc compiler itself we want to make sure that this is