summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/src/fmt/writer.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:12:43 +0000
commitcf94bdc0742c13e2a0cac864c478b8626b266e1b (patch)
tree044670aa50cc5e2b4229aa0b6b3df6676730c0a6 /vendor/tracing-subscriber/src/fmt/writer.rs
parentAdding debian version 1.65.0+dfsg1-2. (diff)
downloadrustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.tar.xz
rustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.zip
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tracing-subscriber/src/fmt/writer.rs')
-rw-r--r--vendor/tracing-subscriber/src/fmt/writer.rs1464
1 files changed, 0 insertions, 1464 deletions
diff --git a/vendor/tracing-subscriber/src/fmt/writer.rs b/vendor/tracing-subscriber/src/fmt/writer.rs
deleted file mode 100644
index 4aacd6d54..000000000
--- a/vendor/tracing-subscriber/src/fmt/writer.rs
+++ /dev/null
@@ -1,1464 +0,0 @@
-//! Abstractions for creating [`io::Write`] instances.
-//!
-//! [`io::Write`]: std::io::Write
-use std::{
- fmt,
- io::{self, Write},
- sync::{Arc, Mutex, MutexGuard},
-};
-use tracing_core::Metadata;
-
-/// A type that can create [`io::Write`] instances.
-///
-/// `MakeWriter` is used by [`fmt::Layer`] or [`fmt::Subscriber`] to print
-/// formatted text representations of [`Event`]s.
-///
-/// This trait is already implemented for function pointers and
-/// immutably-borrowing closures that return an instance of [`io::Write`], such
-/// as [`io::stdout`] and [`io::stderr`]. Additionally, it is implemented for
-/// [`std::sync::Mutex`][mutex] when the tyoe inside the mutex implements
-/// [`io::Write`].
-///
-/// # Examples
-///
-/// The simplest usage is to pass in a named function that returns a writer. For
-/// example, to log all events to stderr, we could write:
-/// ```
-/// let subscriber = tracing_subscriber::fmt()
-/// .with_writer(std::io::stderr)
-/// .finish();
-/// # drop(subscriber);
-/// ```
-///
-/// Any function that returns a writer can be used:
-///
-/// ```
-/// fn make_my_great_writer() -> impl std::io::Write {
-/// // ...
-/// # std::io::stdout()
-/// }
-///
-/// let subscriber = tracing_subscriber::fmt()
-/// .with_writer(make_my_great_writer)
-/// .finish();
-/// # drop(subscriber);
-/// ```
-///
-/// A closure can be used to introduce arbitrary logic into how the writer is
-/// created. Consider the (admittedly rather silly) example of sending every 5th
-/// event to stderr, and all other events to stdout:
-///
-/// ```
-/// use std::io;
-/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
-///
-/// let n = AtomicUsize::new(0);
-/// let subscriber = tracing_subscriber::fmt()
-/// .with_writer(move || -> Box<dyn io::Write> {
-/// if n.fetch_add(1, Relaxed) % 5 == 0 {
-/// Box::new(io::stderr())
-/// } else {
-/// Box::new(io::stdout())
-/// }
-/// })
-/// .finish();
-/// # drop(subscriber);
-/// ```
-///
-/// A single instance of a type implementing [`io::Write`] may be used as a
-/// `MakeWriter` by wrapping it in a [`Mutex`][mutex]. For example, we could
-/// write to a file like so:
-///
-/// ```
-/// use std::{fs::File, sync::Mutex};
-///
-/// # fn docs() -> Result<(), Box<dyn std::error::Error>> {
-/// let log_file = File::create("my_cool_trace.log")?;
-/// let subscriber = tracing_subscriber::fmt()
-/// .with_writer(Mutex::new(log_file))
-/// .finish();
-/// # drop(subscriber);
-/// # Ok(())
-/// # }
-/// ```
-///
-/// [`io::Write`]: std::io::Write
-/// [`fmt::Layer`]: crate::fmt::Layer
-/// [`fmt::Subscriber`]: crate::fmt::Subscriber
-/// [`Event`]: tracing_core::event::Event
-/// [`io::stdout`]: std::io::stdout()
-/// [`io::stderr`]: std::io::stderr()
-/// [mutex]: std::sync::Mutex
-/// [`MakeWriter::make_writer_for`]: MakeWriter::make_writer_for
-/// [`Metadata`]: tracing_core::Metadata
-/// [levels]: tracing_core::Level
-/// [targets]: tracing_core::Metadata::target
-pub trait MakeWriter<'a> {
- /// The concrete [`io::Write`] implementation returned by [`make_writer`].
- ///
- /// [`io::Write`]: std::io::Write
- /// [`make_writer`]: MakeWriter::make_writer
- type Writer: io::Write;
-
- /// Returns an instance of [`Writer`].
- ///
- /// # Implementer notes
- ///
- /// [`fmt::Layer`] or [`fmt::Subscriber`] will call this method each time an event is recorded. Ensure any state
- /// that must be saved across writes is not lost when the [`Writer`] instance is dropped. If
- /// creating a [`io::Write`] instance is expensive, be sure to cache it when implementing
- /// [`MakeWriter`] to improve performance.
- ///
- /// [`Writer`]: MakeWriter::Writer
- /// [`fmt::Layer`]: crate::fmt::Layer
- /// [`fmt::Subscriber`]: crate::fmt::Subscriber
- /// [`io::Write`]: std::io::Write
- fn make_writer(&'a self) -> Self::Writer;
-
- /// Returns a [`Writer`] for writing data from the span or event described
- /// by the provided [`Metadata`].
- ///
- /// By default, this calls [`self.make_writer()`][make_writer], ignoring
- /// the provided metadata, but implementations can override this to provide
- /// metadata-specific behaviors.
- ///
- /// This method allows `MakeWriter` implementations to implement different
- /// behaviors based on the span or event being written. The `MakeWriter`
- /// type might return different writers based on the provided metadata, or
- /// might write some values to the writer before or after providing it to
- /// the caller.
- ///
- /// For example, we might want to write data from spans and events at the
- /// [`ERROR`] and [`WARN`] levels to `stderr`, and data from spans or events
- /// at lower levels to stdout:
- ///
- /// ```
- /// use std::io::{self, Stdout, Stderr, StdoutLock, StderrLock};
- /// use tracing_subscriber::fmt::writer::MakeWriter;
- /// use tracing_core::{Metadata, Level};
- ///
- /// pub struct MyMakeWriter {
- /// stdout: Stdout,
- /// stderr: Stderr,
- /// }
- ///
- /// /// A lock on either stdout or stderr, depending on the verbosity level
- /// /// of the event being written.
- /// pub enum StdioLock<'a> {
- /// Stdout(StdoutLock<'a>),
- /// Stderr(StderrLock<'a>),
- /// }
- ///
- /// impl<'a> io::Write for StdioLock<'a> {
- /// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- /// match self {
- /// StdioLock::Stdout(lock) => lock.write(buf),
- /// StdioLock::Stderr(lock) => lock.write(buf),
- /// }
- /// }
- ///
- /// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
- /// // ...
- /// # match self {
- /// # StdioLock::Stdout(lock) => lock.write_all(buf),
- /// # StdioLock::Stderr(lock) => lock.write_all(buf),
- /// # }
- /// }
- ///
- /// fn flush(&mut self) -> io::Result<()> {
- /// // ...
- /// # match self {
- /// # StdioLock::Stdout(lock) => lock.flush(),
- /// # StdioLock::Stderr(lock) => lock.flush(),
- /// # }
- /// }
- /// }
- ///
- /// impl<'a> MakeWriter<'a> for MyMakeWriter {
- /// type Writer = StdioLock<'a>;
- ///
- /// fn make_writer(&'a self) -> Self::Writer {
- /// // We must have an implementation of `make_writer` that makes
- /// // a "default" writer without any configuring metadata. Let's
- /// // just return stdout in that case.
- /// StdioLock::Stdout(self.stdout.lock())
- /// }
- ///
- /// fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- /// // Here's where we can implement our special behavior. We'll
- /// // check if the metadata's verbosity level is WARN or ERROR,
- /// // and return stderr in that case.
- /// if meta.level() <= &Level::WARN {
- /// return StdioLock::Stderr(self.stderr.lock());
- /// }
- ///
- /// // Otherwise, we'll return stdout.
- /// StdioLock::Stdout(self.stdout.lock())
- /// }
- /// }
- /// ```
- ///
- /// [`Writer`]: MakeWriter::Writer
- /// [`Metadata`]: tracing_core::Metadata
- /// [make_writer]: MakeWriter::make_writer
- /// [`WARN`]: tracing_core::Level::WARN
- /// [`ERROR`]: tracing_core::Level::ERROR
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- let _ = meta;
- self.make_writer()
- }
-}
-
-/// Extension trait adding combinators for working with types implementing
-/// [`MakeWriter`].
-///
-/// This is not intended to be implemented directly for user-defined
-/// [`MakeWriter`]s; instead, it should be imported when the desired methods are
-/// used.
-pub trait MakeWriterExt<'a>: MakeWriter<'a> {
- /// Wraps `self` and returns a [`MakeWriter`] that will only write output
- /// for events at or below the provided verbosity [`Level`]. For instance,
- /// `Level::TRACE` is considered to be _more verbose` than `Level::INFO`.
- ///
- /// Events whose level is more verbose than `level` will be ignored, and no
- /// output will be written.
- ///
- /// # Examples
- ///
- /// ```
- /// use tracing::Level;
- /// use tracing_subscriber::fmt::writer::MakeWriterExt;
- ///
- /// // Construct a writer that outputs events to `stderr` only if the span or
- /// // event's level is >= WARN (WARN and ERROR).
- /// let mk_writer = std::io::stderr.with_max_level(Level::WARN);
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// ```
- ///
- /// Writing the `ERROR` and `WARN` levels to `stderr`, and everything else
- /// to `stdout`:
- ///
- /// ```
- /// # use tracing::Level;
- /// # use tracing_subscriber::fmt::writer::MakeWriterExt;
- ///
- /// let mk_writer = std::io::stderr
- /// .with_max_level(Level::WARN)
- /// .or_else(std::io::stdout);
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// ```
- ///
- /// Writing the `ERROR` level to `stderr`, the `INFO` and `WARN` levels to
- /// `stdout`, and the `INFO` and DEBUG` levels to a file:
- ///
- /// ```
- /// # use tracing::Level;
- /// # use tracing_subscriber::fmt::writer::MakeWriterExt;
- /// use std::{sync::Arc, fs::File};
- /// # // don't actually create the file when running the tests.
- /// # fn docs() -> std::io::Result<()> {
- /// let debug_log = Arc::new(File::create("debug.log")?);
- ///
- /// let mk_writer = std::io::stderr
- /// .with_max_level(Level::ERROR)
- /// .or_else(std::io::stdout
- /// .with_max_level(Level::INFO)
- /// .and(debug_log.with_max_level(Level::DEBUG))
- /// );
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// # Ok(()) }
- /// ```
- ///
- /// [`Level`]: tracing_core::Level
- /// [`io::Write`]: std::io::Write
- fn with_max_level(self, level: tracing_core::Level) -> WithMaxLevel<Self>
- where
- Self: Sized,
- {
- WithMaxLevel::new(self, level)
- }
-
- /// Wraps `self` and returns a [`MakeWriter`] that will only write output
- /// for events at or above the provided verbosity [`Level`].
- ///
- /// Events whose level is less verbose than `level` will be ignored, and no
- /// output will be written.
- ///
- /// # Examples
- ///
- /// ```
- /// use tracing::Level;
- /// use tracing_subscriber::fmt::writer::MakeWriterExt;
- ///
- /// // Construct a writer that outputs events to `stdout` only if the span or
- /// // event's level is <= DEBUG (DEBUG and TRACE).
- /// let mk_writer = std::io::stdout.with_min_level(Level::DEBUG);
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// ```
- /// This can be combined with [`MakeWriterExt::with_max_level`] to write
- /// only within a range of levels:
- ///
- /// ```
- /// # use tracing::Level;
- /// # use tracing_subscriber::fmt::writer::MakeWriterExt;
- /// // Only write the `DEBUG` and `INFO` levels to stdout.
- /// let mk_writer = std::io::stdout
- /// .with_max_level(Level::DEBUG)
- /// .with_min_level(Level::INFO)
- /// // Write the `WARN` and `ERROR` levels to stderr.
- /// .and(std::io::stderr.with_min_level(Level::WARN));
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// ```
- /// [`Level`]: tracing_core::Level
- /// [`io::Write`]: std::io::Write
- fn with_min_level(self, level: tracing_core::Level) -> WithMinLevel<Self>
- where
- Self: Sized,
- {
- WithMinLevel::new(self, level)
- }
-
- /// Wraps `self` with a predicate that takes a span or event's [`Metadata`]
- /// and returns a `bool`. The returned [`MakeWriter`]'s
- /// [`MakeWriter::make_writer_for`][mwf] method will check the predicate to
- /// determine if a writer should be produced for a given span or event.
- ///
- /// If the predicate returns `false`, the wrapped [`MakeWriter`]'s
- /// [`make_writer_for`][mwf] will return [`OptionalWriter::none`][own].
- /// Otherwise, it calls the wrapped [`MakeWriter`]'s
- /// [`make_writer_for`][mwf] method, and returns the produced writer.
- ///
- /// This can be used to filter an output based on arbitrary [`Metadata`]
- /// parameters.
- ///
- /// # Examples
- ///
- /// Writing events with a specific target to an HTTP access log, and other
- /// events to stdout:
- ///
- /// ```
- /// use tracing_subscriber::fmt::writer::MakeWriterExt;
- /// use std::{sync::Arc, fs::File};
- /// # // don't actually create the file when running the tests.
- /// # fn docs() -> std::io::Result<()> {
- /// let access_log = Arc::new(File::create("access.log")?);
- ///
- /// let mk_writer = access_log
- /// // Only write events with the target "http::access_log" to the
- /// // access log file.
- /// .with_filter(|meta| meta.target() == "http::access_log")
- /// // Write events with all other targets to stdout.
- /// .or_else(std::io::stdout);
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// # Ok(())
- /// # }
- /// ```
- ///
- /// Conditionally enabling or disabling a log file:
- /// ```
- /// use tracing_subscriber::fmt::writer::MakeWriterExt;
- /// use std::{
- /// sync::{Arc, atomic::{AtomicBool, Ordering}},
- /// fs::File,
- /// };
- ///
- /// static DEBUG_LOG_ENABLED: AtomicBool = AtomicBool::new(false);
- ///
- /// # // don't actually create the file when running the tests.
- /// # fn docs() -> std::io::Result<()> {
- /// // Create the debug log file
- /// let debug_file = Arc::new(File::create("debug.log")?)
- /// // Enable the debug log only if the flag is enabled.
- /// .with_filter(|_| DEBUG_LOG_ENABLED.load(Ordering::Acquire));
- ///
- /// // Always write to stdout
- /// let mk_writer = std::io::stdout
- /// // Write to the debug file if it's enabled
- /// .and(debug_file);
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- ///
- /// // ...
- ///
- /// // Later, we can toggle on or off the debug log file.
- /// DEBUG_LOG_ENABLED.store(true, Ordering::Release);
- /// # Ok(())
- /// # }
- /// ```
- ///
- /// [`Metadata`]: tracing_core::Metadata
- /// [mwf]: MakeWriter::make_writer_for
- /// [own]: EitherWriter::none
- fn with_filter<F>(self, filter: F) -> WithFilter<Self, F>
- where
- Self: Sized,
- F: Fn(&Metadata<'_>) -> bool,
- {
- WithFilter::new(self, filter)
- }
-
- /// Combines `self` with another type implementing [`MakeWriter`], returning
- /// a new [`MakeWriter`] that produces [writers] that write to *both*
- /// outputs.
- ///
- /// If writing to either writer returns an error, the returned writer will
- /// return that error. However, both writers will still be written to before
- /// the error is returned, so it is possible for one writer to fail while
- /// the other is written to successfully.
- ///
- /// # Examples
- ///
- /// ```
- /// use tracing_subscriber::fmt::writer::MakeWriterExt;
- ///
- /// // Construct a writer that outputs events to `stdout` *and* `stderr`.
- /// let mk_writer = std::io::stdout.and(std::io::stderr);
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// ```
- ///
- /// `and` can be used in conjunction with filtering combinators. For
- /// example, if we want to write to a number of outputs depending on the
- /// level of an event, we could write:
- ///
- /// ```
- /// use tracing::Level;
- /// # use tracing_subscriber::fmt::writer::MakeWriterExt;
- /// use std::{sync::Arc, fs::File};
- /// # // don't actually create the file when running the tests.
- /// # fn docs() -> std::io::Result<()> {
- /// let debug_log = Arc::new(File::create("debug.log")?);
- ///
- /// // Write everything to the debug log.
- /// let mk_writer = debug_log
- /// // Write the `ERROR` and `WARN` levels to stderr.
- /// .and(std::io::stderr.with_max_level(Level::WARN))
- /// // Write `INFO` to `stdout`.
- /// .and(std::io::stdout
- /// .with_max_level(Level::INFO)
- /// .with_min_level(Level::INFO)
- /// );
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// # Ok(()) }
- /// ```
- ///
- /// [writers]: std::io::Write
- fn and<B>(self, other: B) -> Tee<Self, B>
- where
- Self: Sized,
- B: MakeWriter<'a> + Sized,
- {
- Tee::new(self, other)
- }
-
- /// Combines `self` with another type implementing [`MakeWriter`], returning
- /// a new [`MakeWriter`] that calls `other`'s [`make_writer`] if `self`'s
- /// `make_writer` returns [`OptionalWriter::none`][own].
- ///
- /// # Examples
- ///
- /// ```
- /// use tracing::Level;
- /// use tracing_subscriber::fmt::writer::MakeWriterExt;
- ///
- /// // Produces a writer that writes to `stderr` if the level is >= WARN,
- /// // or returns `OptionalWriter::none()` otherwise.
- /// let stderr = std::io::stderr.with_max_level(Level::WARN);
- ///
- /// // If the `stderr` `MakeWriter` is disabled by the max level filter,
- /// // write to stdout instead:
- /// let mk_writer = stderr.or_else(std::io::stdout);
- ///
- /// tracing_subscriber::fmt().with_writer(mk_writer).init();
- /// ```
- ///
- /// [`make_writer`]: MakeWriter::make_writer
- /// [own]: EitherWriter::none
- fn or_else<W, B>(self, other: B) -> OrElse<Self, B>
- where
- Self: MakeWriter<'a, Writer = OptionalWriter<W>> + Sized,
- B: MakeWriter<'a> + Sized,
- W: Write,
- {
- OrElse::new(self, other)
- }
-}
-
-/// 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`]: super::Subscriber
-/// [`fmt::Layer`]: super::Layer
-/// [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`]: std::io::stdout
-/// [`io::stderr`]: std::io::stderr
-/// [`print!`]: std::print!
-#[derive(Default, Debug)]
-pub struct TestWriter {
- _p: (),
-}
-
-/// A writer that erases the specific [`io::Write`] and [`MakeWriter`] types being used.
-///
-/// This is useful in cases where the concrete type of the writer cannot be known
-/// until runtime.
-///
-/// # Examples
-///
-/// A function that returns a [`Subscriber`] that will write to either stdout or stderr:
-///
-/// ```rust
-/// # use tracing::Subscriber;
-/// # use tracing_subscriber::fmt::writer::BoxMakeWriter;
-///
-/// fn dynamic_writer(use_stderr: bool) -> impl Subscriber {
-/// let writer = if use_stderr {
-/// BoxMakeWriter::new(std::io::stderr)
-/// } else {
-/// BoxMakeWriter::new(std::io::stdout)
-/// };
-///
-/// tracing_subscriber::fmt().with_writer(writer).finish()
-/// }
-/// ```
-///
-/// [`Subscriber`]: tracing::Subscriber
-/// [`io::Write`]: std::io::Write
-pub struct BoxMakeWriter {
- inner: Box<dyn for<'a> MakeWriter<'a, Writer = Box<dyn Write + 'a>> + Send + Sync>,
- name: &'static str,
-}
-
-/// A [writer] that is one of two types implementing [`io::Write`][writer].
-///
-/// This may be used by [`MakeWriter`] implementations that may conditionally
-/// return one of two writers.
-///
-/// [writer]: std::io::Write
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum EitherWriter<A, B> {
- /// A writer of type `A`.
- A(A),
- /// A writer of type `B`.
- B(B),
-}
-
-/// A [writer] which may or may not be enabled.
-///
-/// This may be used by [`MakeWriter`] implementations that wish to
-/// conditionally enable or disable the returned writer based on a span or
-/// event's [`Metadata`].
-///
-/// [writer]: std::io::Write
-pub type OptionalWriter<T> = EitherWriter<T, std::io::Sink>;
-
-/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
-/// and events with metadata at or below a specified verbosity [`Level`].
-///
-/// This is returned by the [`MakeWriterExt::with_max_level`] method. See the
-/// method documentation for details.
-///
-/// [writer]: std::io::Write
-/// [`Level`]: tracing_core::Level
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct WithMaxLevel<M> {
- make: M,
- level: tracing_core::Level,
-}
-
-/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
-/// and events with metadata at or above a specified verbosity [`Level`].
-///
-/// This is returned by the [`MakeWriterExt::with_min_level`] method. See the
-/// method documentation for details.
-///
-/// [writer]: std::io::Write
-/// [`Level`]: tracing_core::Level
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct WithMinLevel<M> {
- make: M,
- level: tracing_core::Level,
-}
-
-/// A [`MakeWriter`] combinator that wraps a [`MakeWriter`] with a predicate for
-/// span and event [`Metadata`], so that the [`MakeWriter::make_writer_for`]
-/// method returns [`OptionalWriter::some`][ows] when the predicate returns `true`,
-/// and [`OptionalWriter::none`][own] when the predicate returns `false`.
-///
-/// This is returned by the [`MakeWriterExt::with_filter`] method. See the
-/// method documentation for details.
-///
-/// [`Metadata`]: tracing_core::Metadata
-/// [ows]: EitherWriter::some
-/// [own]: EitherWriter::none
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct WithFilter<M, F> {
- make: M,
- filter: F,
-}
-
-/// Combines a [`MakeWriter`] that returns an [`OptionalWriter`] with another
-/// [`MakeWriter`], so that the second [`MakeWriter`] is used when the first
-/// [`MakeWriter`] returns [`OptionalWriter::none`][own].
-///
-/// This is returned by the [`MakeWriterExt::or_else] method. See the
-/// method documentation for details.
-///
-/// [own]: EitherWriter::none
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct OrElse<A, B> {
- inner: A,
- or_else: B,
-}
-
-/// Combines two types implementing [`MakeWriter`] (or [`std::io::Write`]) to
-/// produce a writer that writes to both [`MakeWriter`]'s returned writers.
-///
-/// This is returned by the [`MakeWriterExt::and`] method. See the method
-/// documentation for details.
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct Tee<A, B> {
- a: A,
- b: B,
-}
-
-/// A type implementing [`io::Write`] for a [`MutexGuard`] where the type
-/// inside the [`Mutex`] implements [`io::Write`].
-///
-/// This is used by the [`MakeWriter`] implementation for [`Mutex`], because
-/// [`MutexGuard`] itself will not implement [`io::Write`] — instead, it
-/// _dereferences_ to a type implementing [`io::Write`]. Because [`MakeWriter`]
-/// requires the `Writer` type to implement [`io::Write`], it's necessary to add
-/// a newtype that forwards the trait implementation.
-///
-/// [`io::Write`]: std::io::Write
-/// [`MutexGuard`]: std::sync::MutexGuard
-/// [`Mutex`]: std::sync::Mutex
-#[derive(Debug)]
-pub struct MutexGuardWriter<'a, W>(MutexGuard<'a, W>);
-
-/// Implements [`std::io::Write`] for an [`Arc`]<W> where `&W: Write`.
-///
-/// This is an implementation detail of the [`MakeWriter`] impl for [`Arc`].
-#[derive(Clone, Debug)]
-pub struct ArcWriter<W>(Arc<W>);
-
-/// A bridge between `fmt::Write` and `io::Write`.
-///
-/// This is used by the timestamp formatting implementation for the `time`
-/// crate and by the JSON formatter. In both cases, this is needed because
-/// `tracing-subscriber`'s `FormatEvent`/`FormatTime` traits expect a
-/// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s
-/// `format_into` methods expect an `io::Write`.
-#[cfg(any(feature = "json", feature = "time"))]
-pub(in crate::fmt) struct WriteAdaptor<'a> {
- fmt_write: &'a mut dyn fmt::Write,
-}
-
-impl<'a, F, W> MakeWriter<'a> for F
-where
- F: Fn() -> W,
- W: io::Write,
-{
- type Writer = W;
-
- fn make_writer(&'a self) -> Self::Writer {
- (self)()
- }
-}
-
-impl<'a, W> MakeWriter<'a> for Arc<W>
-where
- &'a W: io::Write + 'a,
-{
- type Writer = &'a W;
- fn make_writer(&'a self) -> Self::Writer {
- &*self
- }
-}
-
-impl<'a> MakeWriter<'a> for std::fs::File {
- type Writer = &'a std::fs::File;
- fn make_writer(&'a self) -> Self::Writer {
- self
- }
-}
-
-// === impl TestWriter ===
-
-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<usize> {
- let out_str = String::from_utf8_lossy(buf);
- print!("{}", out_str);
- Ok(buf.len())
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-impl<'a> MakeWriter<'a> for TestWriter {
- type Writer = Self;
-
- fn make_writer(&'a self) -> Self::Writer {
- Self::default()
- }
-}
-
-// === impl BoxMakeWriter ===
-
-impl BoxMakeWriter {
- /// Constructs a `BoxMakeWriter` wrapping a type implementing [`MakeWriter`].
- ///
- pub fn new<M>(make_writer: M) -> Self
- where
- M: for<'a> MakeWriter<'a> + Send + Sync + 'static,
- {
- Self {
- inner: Box::new(Boxed(make_writer)),
- name: std::any::type_name::<M>(),
- }
- }
-}
-
-impl fmt::Debug for BoxMakeWriter {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("BoxMakeWriter")
- .field(&format_args!("<{}>", self.name))
- .finish()
- }
-}
-
-impl<'a> MakeWriter<'a> for BoxMakeWriter {
- type Writer = Box<dyn Write + 'a>;
-
- #[inline]
- fn make_writer(&'a self) -> Self::Writer {
- self.inner.make_writer()
- }
-
- #[inline]
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- self.inner.make_writer_for(meta)
- }
-}
-
-struct Boxed<M>(M);
-
-impl<'a, M> MakeWriter<'a> for Boxed<M>
-where
- M: MakeWriter<'a>,
-{
- type Writer = Box<dyn Write + 'a>;
-
- fn make_writer(&'a self) -> Self::Writer {
- let w = self.0.make_writer();
- Box::new(w)
- }
-
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- let w = self.0.make_writer_for(meta);
- Box::new(w)
- }
-}
-
-// === impl Mutex/MutexGuardWriter ===
-
-impl<'a, W> MakeWriter<'a> for Mutex<W>
-where
- W: io::Write + 'a,
-{
- type Writer = MutexGuardWriter<'a, W>;
-
- fn make_writer(&'a self) -> Self::Writer {
- MutexGuardWriter(self.lock().expect("lock poisoned"))
- }
-}
-
-impl<'a, W> io::Write for MutexGuardWriter<'a, W>
-where
- W: io::Write,
-{
- #[inline]
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.0.write(buf)
- }
-
- #[inline]
- fn flush(&mut self) -> io::Result<()> {
- self.0.flush()
- }
-
- #[inline]
- fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
- self.0.write_vectored(bufs)
- }
-
- #[inline]
- fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
- self.0.write_all(buf)
- }
-
- #[inline]
- fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
- self.0.write_fmt(fmt)
- }
-}
-
-// === impl EitherWriter ===
-
-impl<A, B> io::Write for EitherWriter<A, B>
-where
- A: io::Write,
- B: io::Write,
-{
- #[inline]
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match self {
- EitherWriter::A(a) => a.write(buf),
- EitherWriter::B(b) => b.write(buf),
- }
- }
-
- #[inline]
- fn flush(&mut self) -> io::Result<()> {
- match self {
- EitherWriter::A(a) => a.flush(),
- EitherWriter::B(b) => b.flush(),
- }
- }
-
- #[inline]
- fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
- match self {
- EitherWriter::A(a) => a.write_vectored(bufs),
- EitherWriter::B(b) => b.write_vectored(bufs),
- }
- }
-
- #[inline]
- fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
- match self {
- EitherWriter::A(a) => a.write_all(buf),
- EitherWriter::B(b) => b.write_all(buf),
- }
- }
-
- #[inline]
- fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
- match self {
- EitherWriter::A(a) => a.write_fmt(fmt),
- EitherWriter::B(b) => b.write_fmt(fmt),
- }
- }
-}
-
-impl<T> OptionalWriter<T> {
- /// Returns a [disabled writer].
- ///
- /// Any bytes written to the returned writer are discarded.
- ///
- /// This is equivalent to returning [`Option::None`].
- ///
- /// [disabled writer]: std::io::sink
- #[inline]
- pub fn none() -> Self {
- EitherWriter::B(std::io::sink())
- }
-
- /// Returns an enabled writer of type `T`.
- ///
- /// This is equivalent to returning [`Option::Some`].
- #[inline]
- pub fn some(t: T) -> Self {
- EitherWriter::A(t)
- }
-}
-
-impl<T> From<Option<T>> for OptionalWriter<T> {
- #[inline]
- fn from(opt: Option<T>) -> Self {
- match opt {
- Some(writer) => Self::some(writer),
- None => Self::none(),
- }
- }
-}
-
-// === impl WithMaxLevel ===
-
-impl<M> WithMaxLevel<M> {
- /// Wraps the provided [`MakeWriter`] with a maximum [`Level`], so that it
- /// returns [`OptionalWriter::none`] for spans and events whose level is
- /// more verbose than the maximum level.
- ///
- /// See [`MakeWriterExt::with_max_level`] for details.
- ///
- /// [`Level`]: tracing_core::Level
- pub fn new(make: M, level: tracing_core::Level) -> Self {
- Self { make, level }
- }
-}
-
-impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMaxLevel<M> {
- type Writer = OptionalWriter<M::Writer>;
-
- #[inline]
- fn make_writer(&'a self) -> Self::Writer {
- // If we don't know the level, assume it's disabled.
- OptionalWriter::none()
- }
-
- #[inline]
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- if meta.level() <= &self.level {
- return OptionalWriter::some(self.make.make_writer_for(meta));
- }
- OptionalWriter::none()
- }
-}
-
-// === impl WithMinLevel ===
-
-impl<M> WithMinLevel<M> {
- /// Wraps the provided [`MakeWriter`] with a minimum [`Level`], so that it
- /// returns [`OptionalWriter::none`] for spans and events whose level is
- /// less verbose than the maximum level.
- ///
- /// See [`MakeWriterExt::with_min_level`] for details.
- ///
- /// [`Level`]: tracing_core::Level
- pub fn new(make: M, level: tracing_core::Level) -> Self {
- Self { make, level }
- }
-}
-
-impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMinLevel<M> {
- type Writer = OptionalWriter<M::Writer>;
-
- #[inline]
- fn make_writer(&'a self) -> Self::Writer {
- // If we don't know the level, assume it's disabled.
- OptionalWriter::none()
- }
-
- #[inline]
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- if meta.level() >= &self.level {
- return OptionalWriter::some(self.make.make_writer_for(meta));
- }
- OptionalWriter::none()
- }
-}
-
-// ==== impl WithFilter ===
-
-impl<M, F> WithFilter<M, F> {
- /// Wraps `make` with the provided `filter`, returning a [`MakeWriter`] that
- /// will call `make.make_writer_for()` when `filter` returns `true` for a
- /// span or event's [`Metadata`], and returns a [`sink`] otherwise.
- ///
- /// See [`MakeWriterExt::with_filter`] for details.
- ///
- /// [`Metadata`]: tracing_core::Metadata
- /// [`sink`]: std::io::sink
- pub fn new(make: M, filter: F) -> Self
- where
- F: Fn(&Metadata<'_>) -> bool,
- {
- Self { make, filter }
- }
-}
-
-impl<'a, M, F> MakeWriter<'a> for WithFilter<M, F>
-where
- M: MakeWriter<'a>,
- F: Fn(&Metadata<'_>) -> bool,
-{
- type Writer = OptionalWriter<M::Writer>;
-
- #[inline]
- fn make_writer(&'a self) -> Self::Writer {
- OptionalWriter::some(self.make.make_writer())
- }
-
- #[inline]
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- if (self.filter)(meta) {
- OptionalWriter::some(self.make.make_writer_for(meta))
- } else {
- OptionalWriter::none()
- }
- }
-}
-
-// === impl Tee ===
-
-impl<A, B> Tee<A, B> {
- /// Combines two types implementing [`MakeWriter`], returning
- /// a new [`MakeWriter`] that produces [writers] that write to *both*
- /// outputs.
- ///
- /// See the documentation for [`MakeWriterExt::and`] for details.
- ///
- /// [writers]: std::io::Write
- pub fn new(a: A, b: B) -> Self {
- Self { a, b }
- }
-}
-
-impl<'a, A, B> MakeWriter<'a> for Tee<A, B>
-where
- A: MakeWriter<'a>,
- B: MakeWriter<'a>,
-{
- type Writer = Tee<A::Writer, B::Writer>;
-
- #[inline]
- fn make_writer(&'a self) -> Self::Writer {
- Tee::new(self.a.make_writer(), self.b.make_writer())
- }
-
- #[inline]
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- Tee::new(self.a.make_writer_for(meta), self.b.make_writer_for(meta))
- }
-}
-
-macro_rules! impl_tee {
- ($self_:ident.$f:ident($($arg:ident),*)) => {
- {
- let res_a = $self_.a.$f($($arg),*);
- let res_b = $self_.b.$f($($arg),*);
- (res_a?, res_b?)
- }
- }
-}
-
-impl<A, B> io::Write for Tee<A, B>
-where
- A: io::Write,
- B: io::Write,
-{
- #[inline]
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let (a, b) = impl_tee!(self.write(buf));
- Ok(std::cmp::max(a, b))
- }
-
- #[inline]
- fn flush(&mut self) -> io::Result<()> {
- impl_tee!(self.flush());
- Ok(())
- }
-
- #[inline]
- fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
- let (a, b) = impl_tee!(self.write_vectored(bufs));
- Ok(std::cmp::max(a, b))
- }
-
- #[inline]
- fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
- impl_tee!(self.write_all(buf));
- Ok(())
- }
-
- #[inline]
- fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
- impl_tee!(self.write_fmt(fmt));
- Ok(())
- }
-}
-
-// === impl OrElse ===
-
-impl<A, B> OrElse<A, B> {
- /// Combines
- pub fn new<'a, W>(inner: A, or_else: B) -> Self
- where
- A: MakeWriter<'a, Writer = OptionalWriter<W>>,
- B: MakeWriter<'a>,
- W: Write,
- {
- Self { inner, or_else }
- }
-}
-
-impl<'a, A, B, W> MakeWriter<'a> for OrElse<A, B>
-where
- A: MakeWriter<'a, Writer = OptionalWriter<W>>,
- B: MakeWriter<'a>,
- W: io::Write,
-{
- type Writer = EitherWriter<W, B::Writer>;
-
- #[inline]
- fn make_writer(&'a self) -> Self::Writer {
- match self.inner.make_writer() {
- EitherWriter::A(writer) => EitherWriter::A(writer),
- EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer()),
- }
- }
-
- #[inline]
- fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
- match self.inner.make_writer_for(meta) {
- EitherWriter::A(writer) => EitherWriter::A(writer),
- EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer_for(meta)),
- }
- }
-}
-
-// === impl ArcWriter ===
-
-impl<W> io::Write for ArcWriter<W>
-where
- for<'a> &'a W: io::Write,
-{
- #[inline]
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- (&*self.0).write(buf)
- }
-
- #[inline]
- fn flush(&mut self) -> io::Result<()> {
- (&*self.0).flush()
- }
-
- #[inline]
- fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
- (&*self.0).write_vectored(bufs)
- }
-
- #[inline]
- fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
- (&*self.0).write_all(buf)
- }
-
- #[inline]
- fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
- (&*self.0).write_fmt(fmt)
- }
-}
-
-// === impl WriteAdaptor ===
-
-#[cfg(any(feature = "json", feature = "time"))]
-impl<'a> WriteAdaptor<'a> {
- pub(in crate::fmt) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self {
- Self { fmt_write }
- }
-}
-#[cfg(any(feature = "json", feature = "time"))]
-impl<'a> io::Write for WriteAdaptor<'a> {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let s =
- std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
-
- self.fmt_write
- .write_str(s)
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
-
- Ok(s.as_bytes().len())
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-#[cfg(any(feature = "json", feature = "time"))]
-impl<'a> fmt::Debug for WriteAdaptor<'a> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad("WriteAdaptor { .. }")
- }
-}
-// === blanket impls ===
-
-impl<'a, M> MakeWriterExt<'a> for M where M: MakeWriter<'a> {}
-#[cfg(test)]
-mod test {
- use super::*;
- use crate::fmt::format::Format;
- use crate::fmt::test::{MockMakeWriter, MockWriter};
- use crate::fmt::Subscriber;
- use std::sync::atomic::{AtomicBool, Ordering};
- use std::sync::{Arc, Mutex};
- use tracing::{debug, error, info, trace, warn, Level};
- use tracing_core::dispatcher::{self, Dispatch};
-
- fn test_writer<T>(make_writer: T, msg: &str, buf: &Mutex<Vec<u8>>)
- where
- T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,
- {
- let subscriber = {
- #[cfg(feature = "ansi")]
- let f = Format::default().without_time().with_ansi(false);
- #[cfg(not(feature = "ansi"))]
- let f = Format::default().without_time();
- Subscriber::builder()
- .event_format(f)
- .with_writer(make_writer)
- .finish()
- };
- let dispatch = Dispatch::from(subscriber);
-
- dispatcher::with_default(&dispatch, || {
- error!("{}", msg);
- });
-
- let expected = format!("ERROR {}: {}\n", module_path!(), msg);
- let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
- assert!(actual.contains(expected.as_str()));
- }
-
- fn has_lines(buf: &Mutex<Vec<u8>>, msgs: &[(tracing::Level, &str)]) {
- let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
- let mut expected_lines = msgs.iter();
- for line in actual.lines() {
- let line = dbg!(line).trim();
- let (level, msg) = expected_lines
- .next()
- .unwrap_or_else(|| panic!("expected no more lines, but got: {:?}", line));
- let expected = format!("{} {}: {}", level, module_path!(), msg);
- assert_eq!(line, expected.as_str());
- }
- }
-
- #[test]
- fn custom_writer_closure() {
- let buf = Arc::new(Mutex::new(Vec::new()));
- let buf2 = buf.clone();
- let make_writer = move || MockWriter::new(buf2.clone());
- let msg = "my custom writer closure error";
- test_writer(make_writer, msg, &buf);
- }
-
- #[test]
- fn custom_writer_struct() {
- let buf = Arc::new(Mutex::new(Vec::new()));
- let make_writer = MockMakeWriter::new(buf.clone());
- let msg = "my custom writer struct error";
- test_writer(make_writer, msg, &buf);
- }
-
- #[test]
- fn custom_writer_mutex() {
- let buf = Arc::new(Mutex::new(Vec::new()));
- let writer = MockWriter::new(buf.clone());
- let make_writer = Mutex::new(writer);
- let msg = "my mutex writer error";
- test_writer(make_writer, msg, &buf);
- }
-
- #[test]
- fn combinators_level_filters() {
- let info_buf = Arc::new(Mutex::new(Vec::new()));
- let info = MockMakeWriter::new(info_buf.clone());
-
- let debug_buf = Arc::new(Mutex::new(Vec::new()));
- let debug = MockMakeWriter::new(debug_buf.clone());
-
- let warn_buf = Arc::new(Mutex::new(Vec::new()));
- let warn = MockMakeWriter::new(warn_buf.clone());
-
- let err_buf = Arc::new(Mutex::new(Vec::new()));
- let err = MockMakeWriter::new(err_buf.clone());
-
- let make_writer = info
- .with_max_level(Level::INFO)
- .and(debug.with_max_level(Level::DEBUG))
- .and(warn.with_max_level(Level::WARN))
- .and(err.with_max_level(Level::ERROR));
-
- let c = {
- #[cfg(feature = "ansi")]
- let f = Format::default().without_time().with_ansi(false);
- #[cfg(not(feature = "ansi"))]
- let f = Format::default().without_time();
- Subscriber::builder()
- .event_format(f)
- .with_writer(make_writer)
- .with_max_level(Level::TRACE)
- .finish()
- };
-
- let _s = tracing::subscriber::set_default(c);
-
- trace!("trace");
- debug!("debug");
- info!("info");
- warn!("warn");
- error!("error");
-
- let all_lines = [
- (Level::TRACE, "trace"),
- (Level::DEBUG, "debug"),
- (Level::INFO, "info"),
- (Level::WARN, "warn"),
- (Level::ERROR, "error"),
- ];
-
- println!("max level debug");
- has_lines(&debug_buf, &all_lines[1..]);
-
- println!("max level info");
- has_lines(&info_buf, &all_lines[2..]);
-
- println!("max level warn");
- has_lines(&warn_buf, &all_lines[3..]);
-
- println!("max level error");
- has_lines(&err_buf, &all_lines[4..]);
- }
-
- #[test]
- fn combinators_or_else() {
- let some_buf = Arc::new(Mutex::new(Vec::new()));
- let some = MockMakeWriter::new(some_buf.clone());
-
- let or_else_buf = Arc::new(Mutex::new(Vec::new()));
- let or_else = MockMakeWriter::new(or_else_buf.clone());
-
- let return_some = AtomicBool::new(true);
- let make_writer = move || {
- if return_some.swap(false, Ordering::Relaxed) {
- OptionalWriter::some(some.make_writer())
- } else {
- OptionalWriter::none()
- }
- };
- let make_writer = make_writer.or_else(or_else);
- let c = {
- #[cfg(feature = "ansi")]
- let f = Format::default().without_time().with_ansi(false);
- #[cfg(not(feature = "ansi"))]
- let f = Format::default().without_time();
- Subscriber::builder()
- .event_format(f)
- .with_writer(make_writer)
- .with_max_level(Level::TRACE)
- .finish()
- };
-
- let _s = tracing::subscriber::set_default(c);
- info!("hello");
- info!("world");
- info!("goodbye");
-
- has_lines(&some_buf, &[(Level::INFO, "hello")]);
- has_lines(
- &or_else_buf,
- &[(Level::INFO, "world"), (Level::INFO, "goodbye")],
- );
- }
-
- #[test]
- fn combinators_or_else_chain() {
- let info_buf = Arc::new(Mutex::new(Vec::new()));
- let info = MockMakeWriter::new(info_buf.clone());
-
- let debug_buf = Arc::new(Mutex::new(Vec::new()));
- let debug = MockMakeWriter::new(debug_buf.clone());
-
- let warn_buf = Arc::new(Mutex::new(Vec::new()));
- let warn = MockMakeWriter::new(warn_buf.clone());
-
- let err_buf = Arc::new(Mutex::new(Vec::new()));
- let err = MockMakeWriter::new(err_buf.clone());
-
- let make_writer = err.with_max_level(Level::ERROR).or_else(
- warn.with_max_level(Level::WARN).or_else(
- info.with_max_level(Level::INFO)
- .or_else(debug.with_max_level(Level::DEBUG)),
- ),
- );
-
- let c = {
- #[cfg(feature = "ansi")]
- let f = Format::default().without_time().with_ansi(false);
- #[cfg(not(feature = "ansi"))]
- let f = Format::default().without_time();
- Subscriber::builder()
- .event_format(f)
- .with_writer(make_writer)
- .with_max_level(Level::TRACE)
- .finish()
- };
-
- let _s = tracing::subscriber::set_default(c);
-
- trace!("trace");
- debug!("debug");
- info!("info");
- warn!("warn");
- error!("error");
-
- println!("max level debug");
- has_lines(&debug_buf, &[(Level::DEBUG, "debug")]);
-
- println!("max level info");
- has_lines(&info_buf, &[(Level::INFO, "info")]);
-
- println!("max level warn");
- has_lines(&warn_buf, &[(Level::WARN, "warn")]);
-
- println!("max level error");
- has_lines(&err_buf, &[(Level::ERROR, "error")]);
- }
-
- #[test]
- fn combinators_and() {
- let a_buf = Arc::new(Mutex::new(Vec::new()));
- let a = MockMakeWriter::new(a_buf.clone());
-
- let b_buf = Arc::new(Mutex::new(Vec::new()));
- let b = MockMakeWriter::new(b_buf.clone());
-
- let lines = &[(Level::INFO, "hello"), (Level::INFO, "world")];
-
- let make_writer = a.and(b);
- let c = {
- #[cfg(feature = "ansi")]
- let f = Format::default().without_time().with_ansi(false);
- #[cfg(not(feature = "ansi"))]
- let f = Format::default().without_time();
- Subscriber::builder()
- .event_format(f)
- .with_writer(make_writer)
- .with_max_level(Level::TRACE)
- .finish()
- };
-
- let _s = tracing::subscriber::set_default(c);
- info!("hello");
- info!("world");
-
- has_lines(&a_buf, &lines[..]);
- has_lines(&b_buf, &lines[..]);
- }
-}