From 7b9088dd5f6221200967f75ff78b08c9c75a4273 Mon Sep 17 00:00:00 2001 From: samrg472 Date: Mon, 17 Aug 2020 19:44:33 -0700 Subject: [PATCH 1/6] Impl TestWriter for correct capturing of logs by cargo test --- tracing-subscriber/src/fmt/mod.rs | 11 ++++++++++- tracing-subscriber/src/fmt/writer.rs | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index bb58e7415c..590157f47f 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -143,7 +143,7 @@ use crate::{ pub use self::{ format::{format, FormatEvent, FormatFields}, time::time, - writer::MakeWriter, + writer::{MakeWriter, TestWriter}, }; /// A `Subscriber` that logs formatted representations of `tracing` events. @@ -873,6 +873,15 @@ impl SubscriberBuilder { inner: self.inner.with_writer(make_writer), } } + + /// Prints text using the standard library's macro `print!`. This writer allows stdout logs to + /// be correctly captured by commands such as `cargo test`. + pub fn with_test_writer(self) -> SubscriberBuilder { + SubscriberBuilder { + filter: self.filter, + inner: self.inner.with_writer(TestWriter), + } + } } /// Install a global tracing subscriber that listens for events and diff --git a/tracing-subscriber/src/fmt/writer.rs b/tracing-subscriber/src/fmt/writer.rs index c0817da4bf..4f61eede07 100644 --- a/tracing-subscriber/src/fmt/writer.rs +++ b/tracing-subscriber/src/fmt/writer.rs @@ -54,6 +54,31 @@ where } } +/// Prints text using the standard library's macro `print!`. This writer allows stdout logs to be +/// correctly captured by commands such as `cargo test`. +#[derive(Debug)] +pub struct TestWriter; + +impl io::Write for TestWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + let out_str = String::from_utf8_lossy(buf); + print!("{}", out_str); + Ok(out_str.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl MakeWriter for TestWriter { + type Writer = Self; + + fn make_writer(&self) -> Self::Writer { + Self + } +} + #[cfg(test)] mod test { use super::MakeWriter; From 9bad1acfdea648ae7935a6e3b4a0346cc1a9ada6 Mon Sep 17 00:00:00 2001 From: samrg472 Date: Tue, 18 Aug 2020 19:34:22 -0700 Subject: [PATCH 2/6] Update docs on TestWriter --- tracing-subscriber/src/fmt/mod.rs | 26 ++++++++++++++++++++++++-- tracing-subscriber/src/fmt/writer.rs | 19 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index 590157f47f..d54f413657 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -874,8 +874,30 @@ impl SubscriberBuilder { } } - /// Prints text using the standard library's macro `print!`. This writer allows stdout logs to - /// be correctly captured by commands such as `cargo test`. + /// Configures the subscriber to support [`libtest`'s output capturing][capturing] when used in + /// unit tests. + /// + /// See [`TestWriter`] for additional details. + /// + /// # Examples + /// + /// Using [`TestWriter`] to let `cargo test` capture test output. Note that we do not install it + /// globally as it may cause conflicts. + /// + /// ```rust + /// use tracing_subscriber::fmt; + /// use tracing::subscriber; + /// + /// subscriber::set_default( + /// fmt() + /// .with_test_writer() + /// .finish() + /// ); + /// ``` + /// + /// [capturing]: + /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output + /// [`TestWriter`]: writer/struct.TestWriter.html pub fn with_test_writer(self) -> SubscriberBuilder { SubscriberBuilder { filter: self.filter, diff --git a/tracing-subscriber/src/fmt/writer.rs b/tracing-subscriber/src/fmt/writer.rs index 4f61eede07..c2e2e73d6a 100644 --- a/tracing-subscriber/src/fmt/writer.rs +++ b/tracing-subscriber/src/fmt/writer.rs @@ -54,8 +54,23 @@ where } } -/// Prints text using the standard library's macro `print!`. This writer allows stdout logs to be -/// correctly captured by commands such as `cargo test`. +/// A writer intended to support [`libtest`'s output capturing][capturing] for use in unit tests. +/// +/// `TestWriter` is used by [`fmt::Subscriber`] or [`fmt::Layer`] to enable capturing support. +/// +/// `cargo test` can only capture output from the standard library's [`print!`] macro. See +/// [`libtest`'s output capturing][capturing] for more details about output capturing. +/// +/// Writing to [`io::stdout`] and [`io::stderr`] produces the same results as using +/// [`libtest`'s `--nocapture` option][nocapture] which may make the results look unreadable. +/// +/// [`fmt::Subscriber`]: ../struct.Subscriber.html +/// [`fmt::Layer`]: ../struct.Layer.html +/// [capturing]: https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output +/// [nocapture]: https://doc.rust-lang.org/cargo/commands/cargo-test.html +/// [`io::stdout`]: https://doc.rust-lang.org/std/io/fn.stdout.html +/// [`io::stderr`]: https://doc.rust-lang.org/std/io/fn.stderr.html +/// [`print!`]: https://doc.rust-lang.org/std/macro.print.html #[derive(Debug)] pub struct TestWriter; From 2645a67e54e94debcf476808c18f1add2c13d395 Mon Sep 17 00:00:00 2001 From: samrg472 Date: Tue, 18 Aug 2020 19:40:36 -0700 Subject: [PATCH 3/6] Impl with_test_writer on Layer --- tracing-subscriber/src/fmt/fmt_layer.rs | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tracing-subscriber/src/fmt/fmt_layer.rs b/tracing-subscriber/src/fmt/fmt_layer.rs index f17f3419d0..106c3f1a26 100644 --- a/tracing-subscriber/src/fmt/fmt_layer.rs +++ b/tracing-subscriber/src/fmt/fmt_layer.rs @@ -1,6 +1,6 @@ use crate::{ field::RecordFields, - fmt::{format, FormatEvent, FormatFields, MakeWriter}, + fmt::{format, FormatEvent, FormatFields, MakeWriter, TestWriter}, layer::{self, Context, Scope}, registry::{LookupSpan, SpanRef}, }; @@ -181,6 +181,38 @@ impl Layer { _inner: self._inner, } } + + /// Configures the subscriber to support [`libtest`'s output capturing][capturing] when used in + /// unit tests. + /// + /// See [`TestWriter`] for additional details. + /// + /// # Examples + /// + /// Using [`TestWriter`] to let `cargo test` capture test output: + /// + /// ```rust + /// use std::io; + /// use tracing_subscriber::fmt; + /// + /// let layer = fmt::layer() + /// .with_test_writer(); + /// # // this is necessary for type inference. + /// # use tracing_subscriber::Layer as _; + /// # let _ = layer.with_subscriber(tracing_subscriber::registry::Registry::default()); + /// ``` + /// [capturing]: + /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output + /// [`TestWriter`]: writer/struct.TestWriter.html + pub fn with_test_writer(self) -> Layer { + Layer { + fmt_fields: self.fmt_fields, + fmt_event: self.fmt_event, + fmt_span: self.fmt_span, + make_writer: TestWriter, + _inner: self._inner, + } + } } impl Layer, W> From 6d3f277c420f16793c6057a0ca09c91f7d7f637d Mon Sep 17 00:00:00 2001 From: samrg472 Date: Tue, 18 Aug 2020 19:44:06 -0700 Subject: [PATCH 4/6] Use buf.len() in the TestWriter impl In the event that any non-UTF8 bytes are passed into the write stream, the output may be incorrect if the out_str length is less than the buffer length. --- tracing-subscriber/src/fmt/writer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracing-subscriber/src/fmt/writer.rs b/tracing-subscriber/src/fmt/writer.rs index c2e2e73d6a..5501caf110 100644 --- a/tracing-subscriber/src/fmt/writer.rs +++ b/tracing-subscriber/src/fmt/writer.rs @@ -78,7 +78,7 @@ impl io::Write for TestWriter { fn write(&mut self, buf: &[u8]) -> io::Result { let out_str = String::from_utf8_lossy(buf); print!("{}", out_str); - Ok(out_str.len()) + Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { From 0f41dca688c7441691435e300eccd44dc2a60999 Mon Sep 17 00:00:00 2001 From: samrg472 Date: Tue, 18 Aug 2020 19:48:09 -0700 Subject: [PATCH 5/6] Prevent TestWriter from being directly constructed --- tracing-subscriber/src/fmt/fmt_layer.rs | 2 +- tracing-subscriber/src/fmt/mod.rs | 2 +- tracing-subscriber/src/fmt/writer.rs | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tracing-subscriber/src/fmt/fmt_layer.rs b/tracing-subscriber/src/fmt/fmt_layer.rs index 106c3f1a26..519dcfd3fb 100644 --- a/tracing-subscriber/src/fmt/fmt_layer.rs +++ b/tracing-subscriber/src/fmt/fmt_layer.rs @@ -209,7 +209,7 @@ impl Layer { fmt_fields: self.fmt_fields, fmt_event: self.fmt_event, fmt_span: self.fmt_span, - make_writer: TestWriter, + make_writer: TestWriter::default(), _inner: self._inner, } } diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index d54f413657..c3f256d69c 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -901,7 +901,7 @@ impl SubscriberBuilder { pub fn with_test_writer(self) -> SubscriberBuilder { SubscriberBuilder { filter: self.filter, - inner: self.inner.with_writer(TestWriter), + inner: self.inner.with_writer(TestWriter::default()), } } } diff --git a/tracing-subscriber/src/fmt/writer.rs b/tracing-subscriber/src/fmt/writer.rs index 5501caf110..d43b47be63 100644 --- a/tracing-subscriber/src/fmt/writer.rs +++ b/tracing-subscriber/src/fmt/writer.rs @@ -71,8 +71,10 @@ where /// [`io::stdout`]: https://doc.rust-lang.org/std/io/fn.stdout.html /// [`io::stderr`]: https://doc.rust-lang.org/std/io/fn.stderr.html /// [`print!`]: https://doc.rust-lang.org/std/macro.print.html -#[derive(Debug)] -pub struct TestWriter; +#[derive(Default, Debug)] +pub struct TestWriter { + _p: (), +} impl io::Write for TestWriter { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -90,7 +92,7 @@ impl MakeWriter for TestWriter { type Writer = Self; fn make_writer(&self) -> Self::Writer { - Self + Self::default() } } From c560ebe504d03c3723ebc985b1f64320315f224c Mon Sep 17 00:00:00 2001 From: samrg472 Date: Wed, 19 Aug 2020 10:05:23 -0700 Subject: [PATCH 6/6] Impl new function on TestWriter --- tracing-subscriber/src/fmt/writer.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tracing-subscriber/src/fmt/writer.rs b/tracing-subscriber/src/fmt/writer.rs index d43b47be63..2b93726a32 100644 --- a/tracing-subscriber/src/fmt/writer.rs +++ b/tracing-subscriber/src/fmt/writer.rs @@ -76,6 +76,13 @@ pub struct TestWriter { _p: (), } +impl TestWriter { + /// Returns a new `TestWriter` with the default configuration. + pub fn new() -> Self { + Self::default() + } +} + impl io::Write for TestWriter { fn write(&mut self, buf: &[u8]) -> io::Result { let out_str = String::from_utf8_lossy(buf);