better_tracing/fmt/
writer.rs

1//! Abstractions for creating [`io::Write`] instances.
2//!
3//! [`io::Write`]: std::io::Write
4use std::{
5    fmt,
6    io::{self, Write},
7    sync::{Arc, Mutex, MutexGuard},
8};
9use tracing_core::Metadata;
10
11/// A type that can create [`io::Write`] instances.
12///
13/// `MakeWriter` is used by [`fmt::Layer`] or [`fmt::Subscriber`] to print
14/// formatted text representations of [`Event`]s.
15///
16/// This trait is already implemented for function pointers and
17/// immutably-borrowing closures that return an instance of [`io::Write`], such
18/// as [`io::stdout`] and [`io::stderr`]. Additionally, it is implemented for
19/// [`std::sync::Mutex`] when the type inside the mutex implements
20/// [`io::Write`].
21///
22/// # Examples
23///
24/// The simplest usage is to pass in a named function that returns a writer. For
25/// example, to log all events to stderr, we could write:
26/// ```
27/// let subscriber = better_tracing::fmt()
28///     .with_writer(std::io::stderr)
29///     .finish();
30/// # drop(subscriber);
31/// ```
32///
33/// Any function that returns a writer can be used:
34///
35/// ```
36/// fn make_my_great_writer() -> impl std::io::Write {
37///     // ...
38///     # std::io::stdout()
39/// }
40///
41/// let subscriber = better_tracing::fmt()
42///     .with_writer(make_my_great_writer)
43///     .finish();
44/// # drop(subscriber);
45/// ```
46///
47/// A closure can be used to introduce arbitrary logic into how the writer is
48/// created. Consider the (admittedly rather silly) example of sending every 5th
49/// event to stderr, and all other events to stdout:
50///
51/// ```
52/// use std::io;
53/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
54///
55/// let n = AtomicUsize::new(0);
56/// let subscriber = better_tracing::fmt()
57///     .with_writer(move || -> Box<dyn io::Write> {
58///         if n.fetch_add(1, Relaxed) % 5 == 0 {
59///             Box::new(io::stderr())
60///         } else {
61///             Box::new(io::stdout())
62///        }
63///     })
64///     .finish();
65/// # drop(subscriber);
66/// ```
67///
68/// A single instance of a type implementing [`io::Write`] may be used as a
69/// `MakeWriter` by wrapping it in a [`Mutex`]. For example, we could
70/// write to a file like so:
71///
72/// ```
73/// use std::{fs::File, sync::Mutex};
74///
75/// # fn docs() -> Result<(), Box<dyn std::error::Error>> {
76/// let log_file = File::create("my_cool_trace.log")?;
77/// let subscriber = better_tracing::fmt()
78///     .with_writer(Mutex::new(log_file))
79///     .finish();
80/// # drop(subscriber);
81/// # Ok(())
82/// # }
83/// ```
84///
85/// [`io::Write`]: std::io::Write
86/// [`fmt::Layer`]: crate::fmt::Layer
87/// [`fmt::Subscriber`]: crate::fmt::Subscriber
88/// [`Event`]: tracing_core::event::Event
89/// [`io::stdout`]: std::io::stdout()
90/// [`io::stderr`]: std::io::stderr()
91/// [`MakeWriter::make_writer_for`]: MakeWriter::make_writer_for
92/// [`Metadata`]: tracing_core::Metadata
93/// [levels]: tracing_core::Level
94/// [targets]: tracing_core::Metadata::target
95pub trait MakeWriter<'a> {
96    /// The concrete [`io::Write`] implementation returned by [`make_writer`].
97    ///
98    /// [`io::Write`]: std::io::Write
99    /// [`make_writer`]: MakeWriter::make_writer
100    type Writer: io::Write;
101
102    /// Returns an instance of [`Writer`].
103    ///
104    /// # Implementer notes
105    ///
106    /// [`fmt::Layer`] or [`fmt::Subscriber`] will call this method each time an event is recorded. Ensure any state
107    /// that must be saved across writes is not lost when the [`Writer`] instance is dropped. If
108    /// creating a [`io::Write`] instance is expensive, be sure to cache it when implementing
109    /// [`MakeWriter`] to improve performance.
110    ///
111    /// [`Writer`]: MakeWriter::Writer
112    /// [`fmt::Layer`]: crate::fmt::Layer
113    /// [`fmt::Subscriber`]: crate::fmt::Subscriber
114    /// [`io::Write`]: std::io::Write
115    fn make_writer(&'a self) -> Self::Writer;
116
117    /// Returns a [`Writer`] for writing data from the span or event described
118    /// by the provided [`Metadata`].
119    ///
120    /// By default, this calls [`self.make_writer()`][make_writer], ignoring
121    /// the provided metadata, but implementations can override this to provide
122    /// metadata-specific behaviors.
123    ///
124    /// This method allows `MakeWriter` implementations to implement different
125    /// behaviors based on the span or event being written. The `MakeWriter`
126    /// type might return different writers based on the provided metadata, or
127    /// might write some values to the writer before or after providing it to
128    /// the caller.
129    ///
130    /// For example, we might want to write data from spans and events at the
131    /// [`ERROR`] and [`WARN`] levels to `stderr`, and data from spans or events
132    /// at lower levels to stdout:
133    ///
134    /// ```
135    /// use std::io::{self, Stdout, Stderr, StdoutLock, StderrLock};
136    /// use better_tracing::fmt::writer::MakeWriter;
137    /// use tracing_core::{Metadata, Level};
138    ///
139    /// pub struct MyMakeWriter {
140    ///     stdout: Stdout,
141    ///     stderr: Stderr,
142    /// }
143    ///
144    /// /// A lock on either stdout or stderr, depending on the verbosity level
145    /// /// of the event being written.
146    /// pub enum StdioLock<'a> {
147    ///     Stdout(StdoutLock<'a>),
148    ///     Stderr(StderrLock<'a>),
149    /// }
150    ///
151    /// impl<'a> io::Write for StdioLock<'a> {
152    ///     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
153    ///         match self {
154    ///             StdioLock::Stdout(lock) => lock.write(buf),
155    ///             StdioLock::Stderr(lock) => lock.write(buf),
156    ///         }
157    ///     }
158    ///
159    ///     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
160    ///         // ...
161    ///         # match self {
162    ///         #     StdioLock::Stdout(lock) => lock.write_all(buf),
163    ///         #     StdioLock::Stderr(lock) => lock.write_all(buf),
164    ///         # }
165    ///     }
166    ///
167    ///     fn flush(&mut self) -> io::Result<()> {
168    ///         // ...
169    ///         # match self {
170    ///         #     StdioLock::Stdout(lock) => lock.flush(),
171    ///         #     StdioLock::Stderr(lock) => lock.flush(),
172    ///         # }
173    ///     }
174    /// }
175    ///
176    /// impl<'a> MakeWriter<'a> for MyMakeWriter {
177    ///     type Writer = StdioLock<'a>;
178    ///
179    ///     fn make_writer(&'a self) -> Self::Writer {
180    ///         // We must have an implementation of `make_writer` that makes
181    ///         // a "default" writer without any configuring metadata. Let's
182    ///         // just return stdout in that case.
183    ///         StdioLock::Stdout(self.stdout.lock())
184    ///     }
185    ///
186    ///     fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
187    ///         // Here's where we can implement our special behavior. We'll
188    ///         // check if the metadata's verbosity level is WARN or ERROR,
189    ///         // and return stderr in that case.
190    ///         if meta.level() <= &Level::WARN {
191    ///             return StdioLock::Stderr(self.stderr.lock());
192    ///         }
193    ///
194    ///         // Otherwise, we'll return stdout.
195    ///         StdioLock::Stdout(self.stdout.lock())
196    ///     }
197    /// }
198    /// ```
199    ///
200    /// [`Writer`]: MakeWriter::Writer
201    /// [`Metadata`]: tracing_core::Metadata
202    /// [make_writer]: MakeWriter::make_writer
203    /// [`WARN`]: tracing_core::Level::WARN
204    /// [`ERROR`]: tracing_core::Level::ERROR
205    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
206        let _ = meta;
207        self.make_writer()
208    }
209}
210
211/// Extension trait adding combinators for working with types implementing
212/// [`MakeWriter`].
213///
214/// This is not intended to be implemented directly for user-defined
215/// [`MakeWriter`]s; instead, it should be imported when the desired methods are
216/// used.
217pub trait MakeWriterExt<'a>: MakeWriter<'a> {
218    /// Wraps `self` and returns a [`MakeWriter`] that will only write output
219    /// for events at or below the provided verbosity [`Level`]. For instance,
220    /// `Level::TRACE` is considered to be _more verbose` than `Level::INFO`.
221    ///
222    /// Events whose level is more verbose than `level` will be ignored, and no
223    /// output will be written.
224    ///
225    /// # Examples
226    ///
227    /// ```
228    /// use tracing::Level;
229    /// use better_tracing::fmt::writer::MakeWriterExt;
230    ///
231    /// // Construct a writer that outputs events to `stderr` only if the span or
232    /// // event's level is <= WARN (WARN and ERROR).
233    /// let mk_writer = std::io::stderr.with_max_level(Level::WARN);
234    ///
235    /// better_tracing::fmt().with_writer(mk_writer).init();
236    /// ```
237    ///
238    /// Writing the `ERROR` and `WARN` levels to `stderr`, and everything else
239    /// to `stdout`:
240    ///
241    /// ```
242    /// # use tracing::Level;
243    /// # use better_tracing::fmt::writer::MakeWriterExt;
244    ///
245    /// let mk_writer = std::io::stderr
246    ///     .with_max_level(Level::WARN)
247    ///     .or_else(std::io::stdout);
248    ///
249    /// better_tracing::fmt().with_writer(mk_writer).init();
250    /// ```
251    ///
252    /// Writing the `ERROR` level to `stderr`, the `INFO` and `WARN` levels to
253    /// `stdout`, and the `INFO` and DEBUG` levels to a file:
254    ///
255    /// ```
256    /// # use tracing::Level;
257    /// # use better_tracing::fmt::writer::MakeWriterExt;
258    /// use std::{sync::Arc, fs::File};
259    /// # // don't actually create the file when running the tests.
260    /// # fn docs() -> std::io::Result<()> {
261    /// let debug_log = Arc::new(File::create("debug.log")?);
262    ///
263    /// let mk_writer = std::io::stderr
264    ///     .with_max_level(Level::ERROR)
265    ///     .or_else(std::io::stdout
266    ///         .with_max_level(Level::INFO)
267    ///         .and(debug_log.with_max_level(Level::DEBUG))
268    ///     );
269    ///
270    /// better_tracing::fmt().with_writer(mk_writer).init();
271    /// # Ok(()) }
272    /// ```
273    ///
274    /// [`Level`]: tracing_core::Level
275    /// [`io::Write`]: std::io::Write
276    fn with_max_level(self, level: tracing_core::Level) -> WithMaxLevel<Self>
277    where
278        Self: Sized,
279    {
280        WithMaxLevel::new(self, level)
281    }
282
283    /// Wraps `self` and returns a [`MakeWriter`] that will only write output
284    /// for events at or above the provided verbosity [`Level`].
285    ///
286    /// Events whose level is less verbose than `level` will be ignored, and no
287    /// output will be written.
288    ///
289    /// # Examples
290    ///
291    /// ```
292    /// use tracing::Level;
293    /// use better_tracing::fmt::writer::MakeWriterExt;
294    ///
295    /// // Construct a writer that outputs events to `stdout` only if the span or
296    /// // event's level is >= DEBUG (DEBUG and TRACE).
297    /// let mk_writer = std::io::stdout.with_min_level(Level::DEBUG);
298    ///
299    /// better_tracing::fmt().with_writer(mk_writer).init();
300    /// ```
301    /// This can be combined with [`MakeWriterExt::with_max_level`] to write
302    /// only within a range of levels:
303    ///
304    /// ```
305    /// # use tracing::Level;
306    /// # use better_tracing::fmt::writer::MakeWriterExt;
307    /// // Only write the `DEBUG` and `INFO` levels to stdout.
308    /// let mk_writer = std::io::stdout
309    ///     .with_max_level(Level::DEBUG)
310    ///     .with_min_level(Level::INFO)
311    ///     // Write the `WARN` and `ERROR` levels to stderr.
312    ///     .and(std::io::stderr.with_min_level(Level::WARN));
313    ///
314    /// better_tracing::fmt().with_writer(mk_writer).init();
315    /// ```
316    /// [`Level`]: tracing_core::Level
317    /// [`io::Write`]: std::io::Write
318    fn with_min_level(self, level: tracing_core::Level) -> WithMinLevel<Self>
319    where
320        Self: Sized,
321    {
322        WithMinLevel::new(self, level)
323    }
324
325    /// Wraps `self` with a predicate that takes a span or event's [`Metadata`]
326    /// and returns a `bool`. The returned [`MakeWriter`]'s
327    /// [`MakeWriter::make_writer_for`] method will check the predicate to
328    /// determine if  a writer should be produced for a given span or event.
329    ///
330    /// If the predicate returns `false`, the wrapped [`MakeWriter`]'s
331    /// [`make_writer_for`][mwf] will return [`OptionalWriter::none`][own].
332    /// Otherwise, it calls the wrapped [`MakeWriter`]'s
333    /// [`make_writer_for`][mwf] method, and returns the produced writer.
334    ///
335    /// This can be used to filter an output based on arbitrary [`Metadata`]
336    /// parameters.
337    ///
338    /// # Examples
339    ///
340    /// Writing events with a specific target to an HTTP access log, and other
341    /// events to stdout:
342    ///
343    /// ```
344    /// use better_tracing::fmt::writer::MakeWriterExt;
345    /// use std::{sync::Arc, fs::File};
346    /// # // don't actually create the file when running the tests.
347    /// # fn docs() -> std::io::Result<()> {
348    /// let access_log = Arc::new(File::create("access.log")?);
349    ///
350    /// let mk_writer = access_log
351    ///     // Only write events with the target "http::access_log" to the
352    ///     // access log file.
353    ///     .with_filter(|meta| meta.target() == "http::access_log")
354    ///     // Write events with all other targets to stdout.
355    ///     .or_else(std::io::stdout);
356    ///
357    /// better_tracing::fmt().with_writer(mk_writer).init();
358    /// # Ok(())
359    /// # }
360    /// ```
361    ///
362    /// Conditionally enabling or disabling a log file:
363    /// ```
364    /// use better_tracing::fmt::writer::MakeWriterExt;
365    /// use std::{
366    ///     sync::{Arc, atomic::{AtomicBool, Ordering}},
367    ///     fs::File,
368    /// };
369    ///
370    /// static DEBUG_LOG_ENABLED: AtomicBool = AtomicBool::new(false);
371    ///
372    /// # // don't actually create the file when running the tests.
373    /// # fn docs() -> std::io::Result<()> {
374    /// // Create the debug log file
375    /// let debug_file = Arc::new(File::create("debug.log")?)
376    ///     // Enable the debug log only if the flag is enabled.
377    ///     .with_filter(|_| DEBUG_LOG_ENABLED.load(Ordering::Acquire));
378    ///
379    /// // Always write to stdout
380    /// let mk_writer = std::io::stdout
381    ///     // Write to the debug file if it's enabled
382    ///     .and(debug_file);
383    ///
384    /// better_tracing::fmt().with_writer(mk_writer).init();
385    ///
386    /// // ...
387    ///
388    /// // Later, we can toggle on or off the debug log file.
389    /// DEBUG_LOG_ENABLED.store(true, Ordering::Release);
390    /// # Ok(())
391    /// # }
392    /// ```
393    ///
394    /// [`Metadata`]: tracing_core::Metadata
395    /// [mwf]: MakeWriter::make_writer_for
396    /// [own]: EitherWriter::none
397    fn with_filter<F>(self, filter: F) -> WithFilter<Self, F>
398    where
399        Self: Sized,
400        F: Fn(&Metadata<'_>) -> bool,
401    {
402        WithFilter::new(self, filter)
403    }
404
405    /// Combines `self` with another type implementing [`MakeWriter`], returning
406    /// a new [`MakeWriter`] that produces [writers] that write to *both*
407    /// outputs.
408    ///
409    /// If writing to either writer returns an error, the returned writer will
410    /// return that error. However, both writers will still be written to before
411    /// the error is returned, so it is possible for one writer to fail while
412    /// the other is written to successfully.
413    ///
414    /// # Examples
415    ///
416    /// ```
417    /// use better_tracing::fmt::writer::MakeWriterExt;
418    ///
419    /// // Construct a writer that outputs events to `stdout` *and* `stderr`.
420    /// let mk_writer = std::io::stdout.and(std::io::stderr);
421    ///
422    /// better_tracing::fmt().with_writer(mk_writer).init();
423    /// ```
424    ///
425    /// `and` can be used in conjunction with filtering combinators. For
426    /// example, if we want to write to a number of outputs depending on the
427    /// level of an event, we could write:
428    ///
429    /// ```
430    /// use tracing::Level;
431    /// # use better_tracing::fmt::writer::MakeWriterExt;
432    /// use std::{sync::Arc, fs::File};
433    /// # // don't actually create the file when running the tests.
434    /// # fn docs() -> std::io::Result<()> {
435    /// let debug_log = Arc::new(File::create("debug.log")?);
436    ///
437    /// // Write everything to the debug log.
438    /// let mk_writer = debug_log
439    ///     // Write the `ERROR` and `WARN` levels to stderr.
440    ///     .and(std::io::stderr.with_max_level(Level::WARN))
441    ///     // Write `INFO` to `stdout`.
442    ///     .and(std::io::stdout
443    ///         .with_max_level(Level::INFO)
444    ///         .with_min_level(Level::INFO)
445    ///     );
446    ///
447    /// better_tracing::fmt().with_writer(mk_writer).init();
448    /// # Ok(()) }
449    /// ```
450    ///
451    /// [writers]: std::io::Write
452    fn and<B>(self, other: B) -> Tee<Self, B>
453    where
454        Self: Sized,
455        B: MakeWriter<'a> + Sized,
456    {
457        Tee::new(self, other)
458    }
459
460    /// Combines `self` with another type implementing [`MakeWriter`], returning
461    /// a new [`MakeWriter`] that calls `other`'s [`make_writer`] if `self`'s
462    /// `make_writer` returns [`OptionalWriter::none`][own].
463    ///
464    /// # Examples
465    ///
466    /// ```
467    /// use tracing::Level;
468    /// use better_tracing::fmt::writer::MakeWriterExt;
469    ///
470    /// // Produces a writer that writes to `stderr` if the level is <= WARN,
471    /// // or returns `OptionalWriter::none()` otherwise.
472    /// let stderr = std::io::stderr.with_max_level(Level::WARN);
473    ///
474    /// // If the `stderr` `MakeWriter` is disabled by the max level filter,
475    /// // write to stdout instead:
476    /// let mk_writer = stderr.or_else(std::io::stdout);
477    ///
478    /// better_tracing::fmt().with_writer(mk_writer).init();
479    /// ```
480    ///
481    /// [`make_writer`]: MakeWriter::make_writer
482    /// [own]: EitherWriter::none
483    fn or_else<W, B>(self, other: B) -> OrElse<Self, B>
484    where
485        Self: MakeWriter<'a, Writer = OptionalWriter<W>> + Sized,
486        B: MakeWriter<'a> + Sized,
487        W: Write,
488    {
489        OrElse::new(self, other)
490    }
491}
492
493/// A writer intended to support [`libtest`'s output capturing][capturing] for use in unit tests.
494///
495/// `TestWriter` is used by [`fmt::Subscriber`] or [`fmt::Layer`] to enable capturing support.
496///
497/// `cargo test` can only capture output from the standard library's [`print!`] and [`eprint!`]
498/// macros. See [`libtest`'s output capturing][capturing] and
499/// [rust-lang/rust#90785](https://github.com/rust-lang/rust/issues/90785) for more details about
500/// output capturing.
501///
502/// Writing to [`io::stdout`] and [`io::stderr`] produces the same results as using
503/// [`libtest`'s `--nocapture` option][nocapture] which may make the results look unreadable.
504///
505/// [`fmt::Subscriber`]: super::Subscriber
506/// [`fmt::Layer`]: super::Layer
507/// [capturing]: https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output
508/// [nocapture]: https://doc.rust-lang.org/cargo/commands/cargo-test.html
509/// [`io::stdout`]: std::io::stdout
510/// [`io::stderr`]: std::io::stderr
511/// [`print!`]: std::print!
512#[derive(Default, Debug)]
513pub struct TestWriter {
514    /// Whether or not to use `stderr` instead of the default `stdout` as
515    /// the underlying stream to write to.
516    use_stderr: bool,
517}
518
519/// A writer that erases the specific [`io::Write`] and [`MakeWriter`] types being used.
520///
521/// This is useful in cases where the concrete type of the writer cannot be known
522/// until runtime.
523///
524/// # Examples
525///
526/// A function that returns a [`Subscriber`] that will write to either stdout or stderr:
527///
528/// ```rust
529/// # use tracing::Subscriber;
530/// # use better_tracing::fmt::writer::BoxMakeWriter;
531///
532/// fn dynamic_writer(use_stderr: bool) -> impl Subscriber {
533///     let writer = if use_stderr {
534///         BoxMakeWriter::new(std::io::stderr)
535///     } else {
536///         BoxMakeWriter::new(std::io::stdout)
537///     };
538///
539///     better_tracing::fmt().with_writer(writer).finish()
540/// }
541/// ```
542///
543/// [`Subscriber`]: tracing::Subscriber
544/// [`io::Write`]: std::io::Write
545pub struct BoxMakeWriter {
546    inner: Box<dyn for<'a> MakeWriter<'a, Writer = Box<dyn Write + 'a>> + Send + Sync>,
547    name: &'static str,
548}
549
550/// A [writer] that is one of two types implementing [`io::Write`].
551///
552/// This may be used by [`MakeWriter`] implementations that may conditionally
553/// return one of two writers.
554///
555/// [writer]: std::io::Write
556#[derive(Copy, Clone, Debug, Eq, PartialEq)]
557pub enum EitherWriter<A, B> {
558    /// A writer of type `A`.
559    A(A),
560    /// A writer of type `B`.
561    B(B),
562}
563
564/// A [writer] which may or may not be enabled.
565///
566/// This may be used by [`MakeWriter`] implementations that wish to
567/// conditionally enable or disable the returned writer based on a span or
568/// event's [`Metadata`].
569///
570/// [writer]: std::io::Write
571pub type OptionalWriter<T> = EitherWriter<T, std::io::Sink>;
572
573/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
574/// and events with metadata at or below a specified verbosity [`Level`].
575///
576/// This is returned by the [`MakeWriterExt::with_max_level`] method. See the
577/// method documentation for details.
578///
579/// [writer]: std::io::Write
580/// [`Level`]: tracing_core::Level
581#[derive(Copy, Clone, Debug, Eq, PartialEq)]
582pub struct WithMaxLevel<M> {
583    make: M,
584    level: tracing_core::Level,
585}
586
587/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
588/// and events with metadata at or above a specified verbosity [`Level`].
589///
590/// This is returned by the [`MakeWriterExt::with_min_level`] method. See the
591/// method documentation for details.
592///
593/// [writer]: std::io::Write
594/// [`Level`]: tracing_core::Level
595#[derive(Copy, Clone, Debug, Eq, PartialEq)]
596pub struct WithMinLevel<M> {
597    make: M,
598    level: tracing_core::Level,
599}
600
601/// A [`MakeWriter`] combinator that wraps a [`MakeWriter`] with a predicate for
602/// span and event [`Metadata`], so that the [`MakeWriter::make_writer_for`]
603/// method returns [`OptionalWriter::some`][ows] when the predicate returns `true`,
604/// and [`OptionalWriter::none`][own] when the predicate returns `false`.
605///
606/// This is returned by the [`MakeWriterExt::with_filter`] method. See the
607/// method documentation for details.
608///
609/// [`Metadata`]: tracing_core::Metadata
610/// [ows]: EitherWriter::some
611/// [own]: EitherWriter::none
612#[derive(Copy, Clone, Debug, Eq, PartialEq)]
613pub struct WithFilter<M, F> {
614    make: M,
615    filter: F,
616}
617
618/// Combines a [`MakeWriter`] that returns an [`OptionalWriter`] with another
619/// [`MakeWriter`], so that the second [`MakeWriter`] is used when the first
620/// [`MakeWriter`] returns [`OptionalWriter::none`][own].
621///
622/// This is returned by the [`MakeWriterExt::or_else] method. See the
623/// method documentation for details.
624///
625/// [own]: EitherWriter::none
626#[derive(Copy, Clone, Debug, Eq, PartialEq)]
627pub struct OrElse<A, B> {
628    inner: A,
629    or_else: B,
630}
631
632/// Combines two types implementing [`MakeWriter`] (or [`std::io::Write`]) to
633/// produce a writer that writes to both [`MakeWriter`]'s returned writers.
634///
635/// This is returned by the [`MakeWriterExt::and`] method. See the method
636/// documentation for details.
637#[derive(Copy, Clone, Debug, Eq, PartialEq)]
638pub struct Tee<A, B> {
639    a: A,
640    b: B,
641}
642
643/// A type implementing [`io::Write`] for a [`MutexGuard`] where the type
644/// inside the [`Mutex`] implements [`io::Write`].
645///
646/// This is used by the [`MakeWriter`] implementation for [`Mutex`], because
647/// [`MutexGuard`] itself will not implement [`io::Write`] — instead, it
648/// _dereferences_ to a type implementing [`io::Write`]. Because [`MakeWriter`]
649/// requires the `Writer` type to implement [`io::Write`], it's necessary to add
650/// a newtype that forwards the trait implementation.
651///
652/// [`io::Write`]: std::io::Write
653/// [`MutexGuard`]: std::sync::MutexGuard
654/// [`Mutex`]: std::sync::Mutex
655#[derive(Debug)]
656pub struct MutexGuardWriter<'a, W>(MutexGuard<'a, W>);
657
658/// Implements [`std::io::Write`] for an [`Arc`]<W> where `&W: Write`.
659///
660/// This is an implementation detail of the [`MakeWriter`] impl for [`Arc`].
661#[doc(hidden)]
662#[deprecated(since = "0.1.19", note = "unused implementation detail -- do not use")]
663#[allow(dead_code)]
664#[derive(Clone, Debug)]
665pub struct ArcWriter<W>(Arc<W>);
666
667/// A bridge between `fmt::Write` and `io::Write`.
668///
669/// This is used by the timestamp formatting implementation for the `time`
670/// crate and by the JSON formatter. In both cases, this is needed because
671/// `better-tracing`'s `FormatEvent`/`FormatTime` traits expect a
672/// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s
673/// `format_into` methods expect an `io::Write`.
674#[cfg(any(feature = "json", feature = "time"))]
675pub(in crate::fmt) struct WriteAdaptor<'a> {
676    fmt_write: &'a mut dyn fmt::Write,
677}
678
679impl<'a, F, W> MakeWriter<'a> for F
680where
681    F: Fn() -> W,
682    W: io::Write,
683{
684    type Writer = W;
685
686    fn make_writer(&'a self) -> Self::Writer {
687        (self)()
688    }
689}
690
691impl<'a, W> MakeWriter<'a> for Arc<W>
692where
693    &'a W: io::Write + 'a,
694{
695    type Writer = &'a W;
696    fn make_writer(&'a self) -> Self::Writer {
697        self
698    }
699}
700
701impl<'a> MakeWriter<'a> for std::fs::File {
702    type Writer = &'a std::fs::File;
703    fn make_writer(&'a self) -> Self::Writer {
704        self
705    }
706}
707
708// === impl TestWriter ===
709
710impl TestWriter {
711    /// Returns a new `TestWriter` with the default configuration.
712    pub fn new() -> Self {
713        Self::default()
714    }
715
716    /// Returns a new `TestWriter` that writes to `stderr` instead of `stdout`.
717    pub fn with_stderr() -> Self {
718        Self { use_stderr: true }
719    }
720}
721
722impl io::Write for TestWriter {
723    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
724        let out_str = String::from_utf8_lossy(buf);
725        if self.use_stderr {
726            eprint!("{}", out_str)
727        } else {
728            print!("{}", out_str)
729        }
730        Ok(buf.len())
731    }
732
733    fn flush(&mut self) -> io::Result<()> {
734        Ok(())
735    }
736}
737
738impl<'a> MakeWriter<'a> for TestWriter {
739    type Writer = Self;
740
741    fn make_writer(&'a self) -> Self::Writer {
742        Self::default()
743    }
744}
745
746// === impl BoxMakeWriter ===
747
748impl BoxMakeWriter {
749    /// Constructs a `BoxMakeWriter` wrapping a type implementing [`MakeWriter`].
750    ///
751    pub fn new<M>(make_writer: M) -> Self
752    where
753        M: for<'a> MakeWriter<'a> + Send + Sync + 'static,
754    {
755        Self {
756            inner: Box::new(Boxed(make_writer)),
757            name: std::any::type_name::<M>(),
758        }
759    }
760}
761
762impl fmt::Debug for BoxMakeWriter {
763    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764        f.debug_tuple("BoxMakeWriter")
765            .field(&format_args!("<{}>", self.name))
766            .finish()
767    }
768}
769
770impl<'a> MakeWriter<'a> for BoxMakeWriter {
771    type Writer = Box<dyn Write + 'a>;
772
773    #[inline]
774    fn make_writer(&'a self) -> Self::Writer {
775        self.inner.make_writer()
776    }
777
778    #[inline]
779    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
780        self.inner.make_writer_for(meta)
781    }
782}
783
784struct Boxed<M>(M);
785
786impl<'a, M> MakeWriter<'a> for Boxed<M>
787where
788    M: MakeWriter<'a>,
789{
790    type Writer = Box<dyn Write + 'a>;
791
792    fn make_writer(&'a self) -> Self::Writer {
793        let w = self.0.make_writer();
794        Box::new(w)
795    }
796
797    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
798        let w = self.0.make_writer_for(meta);
799        Box::new(w)
800    }
801}
802
803// === impl Mutex/MutexGuardWriter ===
804
805impl<'a, W> MakeWriter<'a> for Mutex<W>
806where
807    W: io::Write + 'a,
808{
809    type Writer = MutexGuardWriter<'a, W>;
810
811    fn make_writer(&'a self) -> Self::Writer {
812        MutexGuardWriter(self.lock().expect("lock poisoned"))
813    }
814}
815
816impl<W> io::Write for MutexGuardWriter<'_, W>
817where
818    W: io::Write,
819{
820    #[inline]
821    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
822        self.0.write(buf)
823    }
824
825    #[inline]
826    fn flush(&mut self) -> io::Result<()> {
827        self.0.flush()
828    }
829
830    #[inline]
831    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
832        self.0.write_vectored(bufs)
833    }
834
835    #[inline]
836    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
837        self.0.write_all(buf)
838    }
839
840    #[inline]
841    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
842        self.0.write_fmt(fmt)
843    }
844}
845
846// === impl EitherWriter ===
847
848impl<A, B> io::Write for EitherWriter<A, B>
849where
850    A: io::Write,
851    B: io::Write,
852{
853    #[inline]
854    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
855        match self {
856            EitherWriter::A(a) => a.write(buf),
857            EitherWriter::B(b) => b.write(buf),
858        }
859    }
860
861    #[inline]
862    fn flush(&mut self) -> io::Result<()> {
863        match self {
864            EitherWriter::A(a) => a.flush(),
865            EitherWriter::B(b) => b.flush(),
866        }
867    }
868
869    #[inline]
870    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
871        match self {
872            EitherWriter::A(a) => a.write_vectored(bufs),
873            EitherWriter::B(b) => b.write_vectored(bufs),
874        }
875    }
876
877    #[inline]
878    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
879        match self {
880            EitherWriter::A(a) => a.write_all(buf),
881            EitherWriter::B(b) => b.write_all(buf),
882        }
883    }
884
885    #[inline]
886    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
887        match self {
888            EitherWriter::A(a) => a.write_fmt(fmt),
889            EitherWriter::B(b) => b.write_fmt(fmt),
890        }
891    }
892}
893
894impl<T> OptionalWriter<T> {
895    /// Returns a [disabled writer].
896    ///
897    /// Any bytes written to the returned writer are discarded.
898    ///
899    /// This is equivalent to returning [`Option::None`].
900    ///
901    /// [disabled writer]: std::io::sink
902    #[inline]
903    pub fn none() -> Self {
904        EitherWriter::B(std::io::sink())
905    }
906
907    /// Returns an enabled writer of type `T`.
908    ///
909    /// This is equivalent to returning [`Option::Some`].
910    #[inline]
911    pub fn some(t: T) -> Self {
912        EitherWriter::A(t)
913    }
914}
915
916impl<T> From<Option<T>> for OptionalWriter<T> {
917    #[inline]
918    fn from(opt: Option<T>) -> Self {
919        match opt {
920            Some(writer) => Self::some(writer),
921            None => Self::none(),
922        }
923    }
924}
925
926// === impl WithMaxLevel ===
927
928impl<M> WithMaxLevel<M> {
929    /// Wraps the provided [`MakeWriter`] with a maximum [`Level`], so that it
930    /// returns [`OptionalWriter::none`] for spans and events whose level is
931    /// more verbose than the maximum level.
932    ///
933    /// See [`MakeWriterExt::with_max_level`] for details.
934    ///
935    /// [`Level`]: tracing_core::Level
936    pub fn new(make: M, level: tracing_core::Level) -> Self {
937        Self { make, level }
938    }
939}
940
941impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMaxLevel<M> {
942    type Writer = OptionalWriter<M::Writer>;
943
944    #[inline]
945    fn make_writer(&'a self) -> Self::Writer {
946        // If we don't know the level, assume it's disabled.
947        OptionalWriter::none()
948    }
949
950    #[inline]
951    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
952        if meta.level() <= &self.level {
953            return OptionalWriter::some(self.make.make_writer_for(meta));
954        }
955        OptionalWriter::none()
956    }
957}
958
959// === impl WithMinLevel ===
960
961impl<M> WithMinLevel<M> {
962    /// Wraps the provided [`MakeWriter`] with a minimum [`Level`], so that it
963    /// returns [`OptionalWriter::none`] for spans and events whose level is
964    /// less verbose than the maximum level.
965    ///
966    /// See [`MakeWriterExt::with_min_level`] for details.
967    ///
968    /// [`Level`]: tracing_core::Level
969    pub fn new(make: M, level: tracing_core::Level) -> Self {
970        Self { make, level }
971    }
972}
973
974impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMinLevel<M> {
975    type Writer = OptionalWriter<M::Writer>;
976
977    #[inline]
978    fn make_writer(&'a self) -> Self::Writer {
979        // If we don't know the level, assume it's disabled.
980        OptionalWriter::none()
981    }
982
983    #[inline]
984    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
985        if meta.level() >= &self.level {
986            return OptionalWriter::some(self.make.make_writer_for(meta));
987        }
988        OptionalWriter::none()
989    }
990}
991
992// ==== impl WithFilter ===
993
994impl<M, F> WithFilter<M, F> {
995    /// Wraps `make` with the provided `filter`, returning a [`MakeWriter`] that
996    /// will call `make.make_writer_for()` when `filter` returns `true` for a
997    /// span or event's [`Metadata`], and returns a [`sink`] otherwise.
998    ///
999    /// See [`MakeWriterExt::with_filter`] for details.
1000    ///
1001    /// [`Metadata`]: tracing_core::Metadata
1002    /// [`sink`]: std::io::sink
1003    pub fn new(make: M, filter: F) -> Self
1004    where
1005        F: Fn(&Metadata<'_>) -> bool,
1006    {
1007        Self { make, filter }
1008    }
1009}
1010
1011impl<'a, M, F> MakeWriter<'a> for WithFilter<M, F>
1012where
1013    M: MakeWriter<'a>,
1014    F: Fn(&Metadata<'_>) -> bool,
1015{
1016    type Writer = OptionalWriter<M::Writer>;
1017
1018    #[inline]
1019    fn make_writer(&'a self) -> Self::Writer {
1020        OptionalWriter::some(self.make.make_writer())
1021    }
1022
1023    #[inline]
1024    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1025        if (self.filter)(meta) {
1026            OptionalWriter::some(self.make.make_writer_for(meta))
1027        } else {
1028            OptionalWriter::none()
1029        }
1030    }
1031}
1032
1033// === impl Tee ===
1034
1035impl<A, B> Tee<A, B> {
1036    /// Combines two types implementing [`MakeWriter`], returning
1037    /// a new [`MakeWriter`] that produces [writers] that write to *both*
1038    /// outputs.
1039    ///
1040    /// See the documentation for [`MakeWriterExt::and`] for details.
1041    ///
1042    /// [writers]: std::io::Write
1043    pub fn new(a: A, b: B) -> Self {
1044        Self { a, b }
1045    }
1046}
1047
1048impl<'a, A, B> MakeWriter<'a> for Tee<A, B>
1049where
1050    A: MakeWriter<'a>,
1051    B: MakeWriter<'a>,
1052{
1053    type Writer = Tee<A::Writer, B::Writer>;
1054
1055    #[inline]
1056    fn make_writer(&'a self) -> Self::Writer {
1057        Tee::new(self.a.make_writer(), self.b.make_writer())
1058    }
1059
1060    #[inline]
1061    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1062        Tee::new(self.a.make_writer_for(meta), self.b.make_writer_for(meta))
1063    }
1064}
1065
1066macro_rules! impl_tee {
1067    ($self_:ident.$f:ident($($arg:ident),*)) => {
1068        {
1069            let res_a = $self_.a.$f($($arg),*);
1070            let res_b = $self_.b.$f($($arg),*);
1071            (res_a?, res_b?)
1072        }
1073    }
1074}
1075
1076impl<A, B> io::Write for Tee<A, B>
1077where
1078    A: io::Write,
1079    B: io::Write,
1080{
1081    #[inline]
1082    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1083        let (a, b) = impl_tee!(self.write(buf));
1084        Ok(std::cmp::max(a, b))
1085    }
1086
1087    #[inline]
1088    fn flush(&mut self) -> io::Result<()> {
1089        impl_tee!(self.flush());
1090        Ok(())
1091    }
1092
1093    #[inline]
1094    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
1095        let (a, b) = impl_tee!(self.write_vectored(bufs));
1096        Ok(std::cmp::max(a, b))
1097    }
1098
1099    #[inline]
1100    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1101        impl_tee!(self.write_all(buf));
1102        Ok(())
1103    }
1104
1105    #[inline]
1106    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
1107        impl_tee!(self.write_fmt(fmt));
1108        Ok(())
1109    }
1110}
1111
1112// === impl OrElse ===
1113
1114impl<A, B> OrElse<A, B> {
1115    /// Combines
1116    pub fn new<'a, W>(inner: A, or_else: B) -> Self
1117    where
1118        A: MakeWriter<'a, Writer = OptionalWriter<W>>,
1119        B: MakeWriter<'a>,
1120        W: Write,
1121    {
1122        Self { inner, or_else }
1123    }
1124}
1125
1126impl<'a, A, B, W> MakeWriter<'a> for OrElse<A, B>
1127where
1128    A: MakeWriter<'a, Writer = OptionalWriter<W>>,
1129    B: MakeWriter<'a>,
1130    W: io::Write,
1131{
1132    type Writer = EitherWriter<W, B::Writer>;
1133
1134    #[inline]
1135    fn make_writer(&'a self) -> Self::Writer {
1136        match self.inner.make_writer() {
1137            EitherWriter::A(writer) => EitherWriter::A(writer),
1138            EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer()),
1139        }
1140    }
1141
1142    #[inline]
1143    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1144        match self.inner.make_writer_for(meta) {
1145            EitherWriter::A(writer) => EitherWriter::A(writer),
1146            EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer_for(meta)),
1147        }
1148    }
1149}
1150
1151// === impl ArcWriter ===
1152
1153#[allow(deprecated)]
1154impl<W> io::Write for ArcWriter<W>
1155where
1156    for<'a> &'a W: io::Write,
1157{
1158    #[inline]
1159    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1160        (&*self.0).write(buf)
1161    }
1162
1163    #[inline]
1164    fn flush(&mut self) -> io::Result<()> {
1165        (&*self.0).flush()
1166    }
1167
1168    #[inline]
1169    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
1170        (&*self.0).write_vectored(bufs)
1171    }
1172
1173    #[inline]
1174    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1175        (&*self.0).write_all(buf)
1176    }
1177
1178    #[inline]
1179    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
1180        (&*self.0).write_fmt(fmt)
1181    }
1182}
1183
1184// === impl WriteAdaptor ===
1185
1186#[cfg(any(feature = "json", feature = "time"))]
1187impl<'a> WriteAdaptor<'a> {
1188    pub(in crate::fmt) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self {
1189        Self { fmt_write }
1190    }
1191}
1192#[cfg(any(feature = "json", feature = "time"))]
1193impl io::Write for WriteAdaptor<'_> {
1194    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1195        let s =
1196            std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1197
1198        self.fmt_write
1199            .write_str(s)
1200            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
1201
1202        Ok(s.len())
1203    }
1204
1205    fn flush(&mut self) -> io::Result<()> {
1206        Ok(())
1207    }
1208}
1209
1210#[cfg(any(feature = "json", feature = "time"))]
1211impl fmt::Debug for WriteAdaptor<'_> {
1212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1213        f.pad("WriteAdaptor { .. }")
1214    }
1215}
1216// === blanket impls ===
1217
1218impl<'a, M> MakeWriterExt<'a> for M where M: MakeWriter<'a> {}
1219#[cfg(test)]
1220mod test {
1221    use super::*;
1222    use crate::fmt::format::Format;
1223    use crate::fmt::test::{MockMakeWriter, MockWriter};
1224    use crate::fmt::Subscriber;
1225    use std::sync::atomic::{AtomicBool, Ordering};
1226    use std::sync::{Arc, Mutex};
1227    use tracing::{debug, error, info, trace, warn, Level};
1228    use tracing_core::dispatcher::{self, Dispatch};
1229
1230    fn test_writer<T>(make_writer: T, msg: &str, buf: &Mutex<Vec<u8>>)
1231    where
1232        T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,
1233    {
1234        let subscriber = {
1235            #[cfg(feature = "ansi")]
1236            let f = Format::default().without_time().with_ansi(false);
1237            #[cfg(not(feature = "ansi"))]
1238            let f = Format::default().without_time();
1239            Subscriber::builder()
1240                .event_format(f)
1241                .with_writer(make_writer)
1242                .finish()
1243        };
1244        let dispatch = Dispatch::from(subscriber);
1245
1246        dispatcher::with_default(&dispatch, || {
1247            error!("{}", msg);
1248        });
1249
1250        let expected = format!("ERROR {}: {}\n", module_path!(), msg);
1251        let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
1252        assert!(actual.contains(expected.as_str()));
1253    }
1254
1255    fn has_lines(buf: &Mutex<Vec<u8>>, msgs: &[(tracing::Level, &str)]) {
1256        let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
1257        let mut expected_lines = msgs.iter();
1258        for line in actual.lines() {
1259            let line = dbg!(line).trim();
1260            let (level, msg) = expected_lines
1261                .next()
1262                .unwrap_or_else(|| panic!("expected no more lines, but got: {:?}", line));
1263            let expected = format!("{} {}: {}", level, module_path!(), msg);
1264            assert_eq!(line, expected.as_str());
1265        }
1266    }
1267
1268    #[test]
1269    fn custom_writer_closure() {
1270        let buf = Arc::new(Mutex::new(Vec::new()));
1271        let buf2 = buf.clone();
1272        let make_writer = move || MockWriter::new(buf2.clone());
1273        let msg = "my custom writer closure error";
1274        test_writer(make_writer, msg, &buf);
1275    }
1276
1277    #[test]
1278    fn custom_writer_struct() {
1279        let buf = Arc::new(Mutex::new(Vec::new()));
1280        let make_writer = MockMakeWriter::new(buf.clone());
1281        let msg = "my custom writer struct error";
1282        test_writer(make_writer, msg, &buf);
1283    }
1284
1285    #[test]
1286    fn custom_writer_mutex() {
1287        let buf = Arc::new(Mutex::new(Vec::new()));
1288        let writer = MockWriter::new(buf.clone());
1289        let make_writer = Mutex::new(writer);
1290        let msg = "my mutex writer error";
1291        test_writer(make_writer, msg, &buf);
1292    }
1293
1294    #[test]
1295    fn combinators_level_filters() {
1296        let info_buf = Arc::new(Mutex::new(Vec::new()));
1297        let info = MockMakeWriter::new(info_buf.clone());
1298
1299        let debug_buf = Arc::new(Mutex::new(Vec::new()));
1300        let debug = MockMakeWriter::new(debug_buf.clone());
1301
1302        let warn_buf = Arc::new(Mutex::new(Vec::new()));
1303        let warn = MockMakeWriter::new(warn_buf.clone());
1304
1305        let err_buf = Arc::new(Mutex::new(Vec::new()));
1306        let err = MockMakeWriter::new(err_buf.clone());
1307
1308        let make_writer = info
1309            .with_max_level(Level::INFO)
1310            .and(debug.with_max_level(Level::DEBUG))
1311            .and(warn.with_max_level(Level::WARN))
1312            .and(err.with_max_level(Level::ERROR));
1313
1314        let c = {
1315            #[cfg(feature = "ansi")]
1316            let f = Format::default().without_time().with_ansi(false);
1317            #[cfg(not(feature = "ansi"))]
1318            let f = Format::default().without_time();
1319            Subscriber::builder()
1320                .event_format(f)
1321                .with_writer(make_writer)
1322                .with_max_level(Level::TRACE)
1323                .finish()
1324        };
1325
1326        let _s = tracing::subscriber::set_default(c);
1327
1328        trace!("trace");
1329        debug!("debug");
1330        info!("info");
1331        warn!("warn");
1332        error!("error");
1333
1334        let all_lines = [
1335            (Level::TRACE, "trace"),
1336            (Level::DEBUG, "debug"),
1337            (Level::INFO, "info"),
1338            (Level::WARN, "warn"),
1339            (Level::ERROR, "error"),
1340        ];
1341
1342        println!("max level debug");
1343        has_lines(&debug_buf, &all_lines[1..]);
1344
1345        println!("max level info");
1346        has_lines(&info_buf, &all_lines[2..]);
1347
1348        println!("max level warn");
1349        has_lines(&warn_buf, &all_lines[3..]);
1350
1351        println!("max level error");
1352        has_lines(&err_buf, &all_lines[4..]);
1353    }
1354
1355    #[test]
1356    fn combinators_or_else() {
1357        let some_buf = Arc::new(Mutex::new(Vec::new()));
1358        let some = MockMakeWriter::new(some_buf.clone());
1359
1360        let or_else_buf = Arc::new(Mutex::new(Vec::new()));
1361        let or_else = MockMakeWriter::new(or_else_buf.clone());
1362
1363        let return_some = AtomicBool::new(true);
1364        let make_writer = move || {
1365            if return_some.swap(false, Ordering::Relaxed) {
1366                OptionalWriter::some(some.make_writer())
1367            } else {
1368                OptionalWriter::none()
1369            }
1370        };
1371        let make_writer = make_writer.or_else(or_else);
1372        let c = {
1373            #[cfg(feature = "ansi")]
1374            let f = Format::default().without_time().with_ansi(false);
1375            #[cfg(not(feature = "ansi"))]
1376            let f = Format::default().without_time();
1377            Subscriber::builder()
1378                .event_format(f)
1379                .with_writer(make_writer)
1380                .with_max_level(Level::TRACE)
1381                .finish()
1382        };
1383
1384        let _s = tracing::subscriber::set_default(c);
1385        info!("hello");
1386        info!("world");
1387        info!("goodbye");
1388
1389        has_lines(&some_buf, &[(Level::INFO, "hello")]);
1390        has_lines(
1391            &or_else_buf,
1392            &[(Level::INFO, "world"), (Level::INFO, "goodbye")],
1393        );
1394    }
1395
1396    #[test]
1397    fn combinators_or_else_chain() {
1398        let info_buf = Arc::new(Mutex::new(Vec::new()));
1399        let info = MockMakeWriter::new(info_buf.clone());
1400
1401        let debug_buf = Arc::new(Mutex::new(Vec::new()));
1402        let debug = MockMakeWriter::new(debug_buf.clone());
1403
1404        let warn_buf = Arc::new(Mutex::new(Vec::new()));
1405        let warn = MockMakeWriter::new(warn_buf.clone());
1406
1407        let err_buf = Arc::new(Mutex::new(Vec::new()));
1408        let err = MockMakeWriter::new(err_buf.clone());
1409
1410        let make_writer = err.with_max_level(Level::ERROR).or_else(
1411            warn.with_max_level(Level::WARN).or_else(
1412                info.with_max_level(Level::INFO)
1413                    .or_else(debug.with_max_level(Level::DEBUG)),
1414            ),
1415        );
1416
1417        let c = {
1418            #[cfg(feature = "ansi")]
1419            let f = Format::default().without_time().with_ansi(false);
1420            #[cfg(not(feature = "ansi"))]
1421            let f = Format::default().without_time();
1422            Subscriber::builder()
1423                .event_format(f)
1424                .with_writer(make_writer)
1425                .with_max_level(Level::TRACE)
1426                .finish()
1427        };
1428
1429        let _s = tracing::subscriber::set_default(c);
1430
1431        trace!("trace");
1432        debug!("debug");
1433        info!("info");
1434        warn!("warn");
1435        error!("error");
1436
1437        println!("max level debug");
1438        has_lines(&debug_buf, &[(Level::DEBUG, "debug")]);
1439
1440        println!("max level info");
1441        has_lines(&info_buf, &[(Level::INFO, "info")]);
1442
1443        println!("max level warn");
1444        has_lines(&warn_buf, &[(Level::WARN, "warn")]);
1445
1446        println!("max level error");
1447        has_lines(&err_buf, &[(Level::ERROR, "error")]);
1448    }
1449
1450    #[test]
1451    fn combinators_and() {
1452        let a_buf = Arc::new(Mutex::new(Vec::new()));
1453        let a = MockMakeWriter::new(a_buf.clone());
1454
1455        let b_buf = Arc::new(Mutex::new(Vec::new()));
1456        let b = MockMakeWriter::new(b_buf.clone());
1457
1458        let lines = &[(Level::INFO, "hello"), (Level::INFO, "world")];
1459
1460        let make_writer = a.and(b);
1461        let c = {
1462            #[cfg(feature = "ansi")]
1463            let f = Format::default().without_time().with_ansi(false);
1464            #[cfg(not(feature = "ansi"))]
1465            let f = Format::default().without_time();
1466            Subscriber::builder()
1467                .event_format(f)
1468                .with_writer(make_writer)
1469                .with_max_level(Level::TRACE)
1470                .finish()
1471        };
1472
1473        let _s = tracing::subscriber::set_default(c);
1474        info!("hello");
1475        info!("world");
1476
1477        has_lines(&a_buf, &lines[..]);
1478        has_lines(&b_buf, &lines[..]);
1479    }
1480}