tracing_subscriber/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 = tracing_subscriber::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 = tracing_subscriber::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 = tracing_subscriber::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 = tracing_subscriber::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 tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::fmt().with_writer(mk_writer).init();
358    /// # Ok(())
359    /// # }
360    /// ```
361    ///
362    /// Conditionally enabling or disabling a log file:
363    /// ```
364    /// use tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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 tracing_subscriber::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    /// tracing_subscriber::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!`] macro. See
498/// [`libtest`'s output capturing][capturing] for more details about output capturing.
499///
500/// Writing to [`io::stdout`] and [`io::stderr`] produces the same results as using
501/// [`libtest`'s `--nocapture` option][nocapture] which may make the results look unreadable.
502///
503/// [`fmt::Subscriber`]: super::Subscriber
504/// [`fmt::Layer`]: super::Layer
505/// [capturing]: https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output
506/// [nocapture]: https://doc.rust-lang.org/cargo/commands/cargo-test.html
507/// [`io::stdout`]: std::io::stdout
508/// [`io::stderr`]: std::io::stderr
509/// [`print!`]: std::print!
510#[derive(Default, Debug)]
511pub struct TestWriter {
512    _p: (),
513}
514
515/// A writer that erases the specific [`io::Write`] and [`MakeWriter`] types being used.
516///
517/// This is useful in cases where the concrete type of the writer cannot be known
518/// until runtime.
519///
520/// # Examples
521///
522/// A function that returns a [`Subscriber`] that will write to either stdout or stderr:
523///
524/// ```rust
525/// # use tracing::Subscriber;
526/// # use tracing_subscriber::fmt::writer::BoxMakeWriter;
527///
528/// fn dynamic_writer(use_stderr: bool) -> impl Subscriber {
529///     let writer = if use_stderr {
530///         BoxMakeWriter::new(std::io::stderr)
531///     } else {
532///         BoxMakeWriter::new(std::io::stdout)
533///     };
534///
535///     tracing_subscriber::fmt().with_writer(writer).finish()
536/// }
537/// ```
538///
539/// [`Subscriber`]: tracing::Subscriber
540/// [`io::Write`]: std::io::Write
541pub struct BoxMakeWriter {
542    inner: Box<dyn for<'a> MakeWriter<'a, Writer = Box<dyn Write + 'a>> + Send + Sync>,
543    name: &'static str,
544}
545
546/// A [writer] that is one of two types implementing [`io::Write`].
547///
548/// This may be used by [`MakeWriter`] implementations that may conditionally
549/// return one of two writers.
550///
551/// [writer]: std::io::Write
552#[derive(Copy, Clone, Debug, Eq, PartialEq)]
553pub enum EitherWriter<A, B> {
554    /// A writer of type `A`.
555    A(A),
556    /// A writer of type `B`.
557    B(B),
558}
559
560/// A [writer] which may or may not be enabled.
561///
562/// This may be used by [`MakeWriter`] implementations that wish to
563/// conditionally enable or disable the returned writer based on a span or
564/// event's [`Metadata`].
565///
566/// [writer]: std::io::Write
567pub type OptionalWriter<T> = EitherWriter<T, std::io::Sink>;
568
569/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
570/// and events with metadata at or below a specified verbosity [`Level`].
571///
572/// This is returned by the [`MakeWriterExt::with_max_level`] method. See the
573/// method documentation for details.
574///
575/// [writer]: std::io::Write
576/// [`Level`]: tracing_core::Level
577#[derive(Copy, Clone, Debug, Eq, PartialEq)]
578pub struct WithMaxLevel<M> {
579    make: M,
580    level: tracing_core::Level,
581}
582
583/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
584/// and events with metadata at or above a specified verbosity [`Level`].
585///
586/// This is returned by the [`MakeWriterExt::with_min_level`] method. See the
587/// method documentation for details.
588///
589/// [writer]: std::io::Write
590/// [`Level`]: tracing_core::Level
591#[derive(Copy, Clone, Debug, Eq, PartialEq)]
592pub struct WithMinLevel<M> {
593    make: M,
594    level: tracing_core::Level,
595}
596
597/// A [`MakeWriter`] combinator that wraps a [`MakeWriter`] with a predicate for
598/// span and event [`Metadata`], so that the [`MakeWriter::make_writer_for`]
599/// method returns [`OptionalWriter::some`][ows] when the predicate returns `true`,
600/// and [`OptionalWriter::none`][own] when the predicate returns `false`.
601///
602/// This is returned by the [`MakeWriterExt::with_filter`] method. See the
603/// method documentation for details.
604///
605/// [`Metadata`]: tracing_core::Metadata
606/// [ows]: EitherWriter::some
607/// [own]: EitherWriter::none
608#[derive(Copy, Clone, Debug, Eq, PartialEq)]
609pub struct WithFilter<M, F> {
610    make: M,
611    filter: F,
612}
613
614/// Combines a [`MakeWriter`] that returns an [`OptionalWriter`] with another
615/// [`MakeWriter`], so that the second [`MakeWriter`] is used when the first
616/// [`MakeWriter`] returns [`OptionalWriter::none`][own].
617///
618/// This is returned by the [`MakeWriterExt::or_else] method. See the
619/// method documentation for details.
620///
621/// [own]: EitherWriter::none
622#[derive(Copy, Clone, Debug, Eq, PartialEq)]
623pub struct OrElse<A, B> {
624    inner: A,
625    or_else: B,
626}
627
628/// Combines two types implementing [`MakeWriter`] (or [`std::io::Write`]) to
629/// produce a writer that writes to both [`MakeWriter`]'s returned writers.
630///
631/// This is returned by the [`MakeWriterExt::and`] method. See the method
632/// documentation for details.
633#[derive(Copy, Clone, Debug, Eq, PartialEq)]
634pub struct Tee<A, B> {
635    a: A,
636    b: B,
637}
638
639/// A type implementing [`io::Write`] for a [`MutexGuard`] where the type
640/// inside the [`Mutex`] implements [`io::Write`].
641///
642/// This is used by the [`MakeWriter`] implementation for [`Mutex`], because
643/// [`MutexGuard`] itself will not implement [`io::Write`] — instead, it
644/// _dereferences_ to a type implementing [`io::Write`]. Because [`MakeWriter`]
645/// requires the `Writer` type to implement [`io::Write`], it's necessary to add
646/// a newtype that forwards the trait implementation.
647///
648/// [`io::Write`]: std::io::Write
649/// [`MutexGuard`]: std::sync::MutexGuard
650/// [`Mutex`]: std::sync::Mutex
651#[derive(Debug)]
652pub struct MutexGuardWriter<'a, W>(MutexGuard<'a, W>);
653
654/// Implements [`std::io::Write`] for an [`Arc`]<W> where `&W: Write`.
655///
656/// This is an implementation detail of the [`MakeWriter`] impl for [`Arc`].
657#[derive(Clone, Debug)]
658pub struct ArcWriter<W>(Arc<W>);
659
660/// A bridge between `fmt::Write` and `io::Write`.
661///
662/// This is used by the timestamp formatting implementation for the `time`
663/// crate and by the JSON formatter. In both cases, this is needed because
664/// `tracing-subscriber`'s `FormatEvent`/`FormatTime` traits expect a
665/// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s
666/// `format_into` methods expect an `io::Write`.
667#[cfg(any(feature = "json", feature = "time"))]
668pub(in crate::fmt) struct WriteAdaptor<'a> {
669    fmt_write: &'a mut dyn fmt::Write,
670}
671
672impl<'a, F, W> MakeWriter<'a> for F
673where
674    F: Fn() -> W,
675    W: io::Write,
676{
677    type Writer = W;
678
679    fn make_writer(&'a self) -> Self::Writer {
680        (self)()
681    }
682}
683
684impl<'a, W> MakeWriter<'a> for Arc<W>
685where
686    &'a W: io::Write + 'a,
687{
688    type Writer = &'a W;
689    fn make_writer(&'a self) -> Self::Writer {
690        self
691    }
692}
693
694impl<'a> MakeWriter<'a> for std::fs::File {
695    type Writer = &'a std::fs::File;
696    fn make_writer(&'a self) -> Self::Writer {
697        self
698    }
699}
700
701// === impl TestWriter ===
702
703impl TestWriter {
704    /// Returns a new `TestWriter` with the default configuration.
705    pub fn new() -> Self {
706        Self::default()
707    }
708}
709
710impl io::Write for TestWriter {
711    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
712        let out_str = String::from_utf8_lossy(buf);
713        print!("{}", out_str);
714        Ok(buf.len())
715    }
716
717    fn flush(&mut self) -> io::Result<()> {
718        Ok(())
719    }
720}
721
722impl<'a> MakeWriter<'a> for TestWriter {
723    type Writer = Self;
724
725    fn make_writer(&'a self) -> Self::Writer {
726        Self::default()
727    }
728}
729
730// === impl BoxMakeWriter ===
731
732impl BoxMakeWriter {
733    /// Constructs a `BoxMakeWriter` wrapping a type implementing [`MakeWriter`].
734    ///
735    pub fn new<M>(make_writer: M) -> Self
736    where
737        M: for<'a> MakeWriter<'a> + Send + Sync + 'static,
738    {
739        Self {
740            inner: Box::new(Boxed(make_writer)),
741            name: std::any::type_name::<M>(),
742        }
743    }
744}
745
746impl fmt::Debug for BoxMakeWriter {
747    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
748        f.debug_tuple("BoxMakeWriter")
749            .field(&format_args!("<{}>", self.name))
750            .finish()
751    }
752}
753
754impl<'a> MakeWriter<'a> for BoxMakeWriter {
755    type Writer = Box<dyn Write + 'a>;
756
757    #[inline]
758    fn make_writer(&'a self) -> Self::Writer {
759        self.inner.make_writer()
760    }
761
762    #[inline]
763    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
764        self.inner.make_writer_for(meta)
765    }
766}
767
768struct Boxed<M>(M);
769
770impl<'a, M> MakeWriter<'a> for Boxed<M>
771where
772    M: MakeWriter<'a>,
773{
774    type Writer = Box<dyn Write + 'a>;
775
776    fn make_writer(&'a self) -> Self::Writer {
777        let w = self.0.make_writer();
778        Box::new(w)
779    }
780
781    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
782        let w = self.0.make_writer_for(meta);
783        Box::new(w)
784    }
785}
786
787// === impl Mutex/MutexGuardWriter ===
788
789impl<'a, W> MakeWriter<'a> for Mutex<W>
790where
791    W: io::Write + 'a,
792{
793    type Writer = MutexGuardWriter<'a, W>;
794
795    fn make_writer(&'a self) -> Self::Writer {
796        MutexGuardWriter(self.lock().expect("lock poisoned"))
797    }
798}
799
800impl<'a, W> io::Write for MutexGuardWriter<'a, W>
801where
802    W: io::Write,
803{
804    #[inline]
805    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
806        self.0.write(buf)
807    }
808
809    #[inline]
810    fn flush(&mut self) -> io::Result<()> {
811        self.0.flush()
812    }
813
814    #[inline]
815    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
816        self.0.write_vectored(bufs)
817    }
818
819    #[inline]
820    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
821        self.0.write_all(buf)
822    }
823
824    #[inline]
825    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
826        self.0.write_fmt(fmt)
827    }
828}
829
830// === impl EitherWriter ===
831
832impl<A, B> io::Write for EitherWriter<A, B>
833where
834    A: io::Write,
835    B: io::Write,
836{
837    #[inline]
838    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
839        match self {
840            EitherWriter::A(a) => a.write(buf),
841            EitherWriter::B(b) => b.write(buf),
842        }
843    }
844
845    #[inline]
846    fn flush(&mut self) -> io::Result<()> {
847        match self {
848            EitherWriter::A(a) => a.flush(),
849            EitherWriter::B(b) => b.flush(),
850        }
851    }
852
853    #[inline]
854    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
855        match self {
856            EitherWriter::A(a) => a.write_vectored(bufs),
857            EitherWriter::B(b) => b.write_vectored(bufs),
858        }
859    }
860
861    #[inline]
862    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
863        match self {
864            EitherWriter::A(a) => a.write_all(buf),
865            EitherWriter::B(b) => b.write_all(buf),
866        }
867    }
868
869    #[inline]
870    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
871        match self {
872            EitherWriter::A(a) => a.write_fmt(fmt),
873            EitherWriter::B(b) => b.write_fmt(fmt),
874        }
875    }
876}
877
878impl<T> OptionalWriter<T> {
879    /// Returns a [disabled writer].
880    ///
881    /// Any bytes written to the returned writer are discarded.
882    ///
883    /// This is equivalent to returning [`Option::None`].
884    ///
885    /// [disabled writer]: std::io::sink
886    #[inline]
887    pub fn none() -> Self {
888        EitherWriter::B(std::io::sink())
889    }
890
891    /// Returns an enabled writer of type `T`.
892    ///
893    /// This is equivalent to returning [`Option::Some`].
894    #[inline]
895    pub fn some(t: T) -> Self {
896        EitherWriter::A(t)
897    }
898}
899
900impl<T> From<Option<T>> for OptionalWriter<T> {
901    #[inline]
902    fn from(opt: Option<T>) -> Self {
903        match opt {
904            Some(writer) => Self::some(writer),
905            None => Self::none(),
906        }
907    }
908}
909
910// === impl WithMaxLevel ===
911
912impl<M> WithMaxLevel<M> {
913    /// Wraps the provided [`MakeWriter`] with a maximum [`Level`], so that it
914    /// returns [`OptionalWriter::none`] for spans and events whose level is
915    /// more verbose than the maximum level.
916    ///
917    /// See [`MakeWriterExt::with_max_level`] for details.
918    ///
919    /// [`Level`]: tracing_core::Level
920    pub fn new(make: M, level: tracing_core::Level) -> Self {
921        Self { make, level }
922    }
923}
924
925impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMaxLevel<M> {
926    type Writer = OptionalWriter<M::Writer>;
927
928    #[inline]
929    fn make_writer(&'a self) -> Self::Writer {
930        // If we don't know the level, assume it's disabled.
931        OptionalWriter::none()
932    }
933
934    #[inline]
935    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
936        if meta.level() <= &self.level {
937            return OptionalWriter::some(self.make.make_writer_for(meta));
938        }
939        OptionalWriter::none()
940    }
941}
942
943// === impl WithMinLevel ===
944
945impl<M> WithMinLevel<M> {
946    /// Wraps the provided [`MakeWriter`] with a minimum [`Level`], so that it
947    /// returns [`OptionalWriter::none`] for spans and events whose level is
948    /// less verbose than the maximum level.
949    ///
950    /// See [`MakeWriterExt::with_min_level`] for details.
951    ///
952    /// [`Level`]: tracing_core::Level
953    pub fn new(make: M, level: tracing_core::Level) -> Self {
954        Self { make, level }
955    }
956}
957
958impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMinLevel<M> {
959    type Writer = OptionalWriter<M::Writer>;
960
961    #[inline]
962    fn make_writer(&'a self) -> Self::Writer {
963        // If we don't know the level, assume it's disabled.
964        OptionalWriter::none()
965    }
966
967    #[inline]
968    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
969        if meta.level() >= &self.level {
970            return OptionalWriter::some(self.make.make_writer_for(meta));
971        }
972        OptionalWriter::none()
973    }
974}
975
976// ==== impl WithFilter ===
977
978impl<M, F> WithFilter<M, F> {
979    /// Wraps `make` with the provided `filter`, returning a [`MakeWriter`] that
980    /// will call `make.make_writer_for()` when `filter` returns `true` for a
981    /// span or event's [`Metadata`], and returns a [`sink`] otherwise.
982    ///
983    /// See [`MakeWriterExt::with_filter`] for details.
984    ///
985    /// [`Metadata`]: tracing_core::Metadata
986    /// [`sink`]: std::io::sink
987    pub fn new(make: M, filter: F) -> Self
988    where
989        F: Fn(&Metadata<'_>) -> bool,
990    {
991        Self { make, filter }
992    }
993}
994
995impl<'a, M, F> MakeWriter<'a> for WithFilter<M, F>
996where
997    M: MakeWriter<'a>,
998    F: Fn(&Metadata<'_>) -> bool,
999{
1000    type Writer = OptionalWriter<M::Writer>;
1001
1002    #[inline]
1003    fn make_writer(&'a self) -> Self::Writer {
1004        OptionalWriter::some(self.make.make_writer())
1005    }
1006
1007    #[inline]
1008    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1009        if (self.filter)(meta) {
1010            OptionalWriter::some(self.make.make_writer_for(meta))
1011        } else {
1012            OptionalWriter::none()
1013        }
1014    }
1015}
1016
1017// === impl Tee ===
1018
1019impl<A, B> Tee<A, B> {
1020    /// Combines two types implementing [`MakeWriter`], returning
1021    /// a new [`MakeWriter`] that produces [writers] that write to *both*
1022    /// outputs.
1023    ///
1024    /// See the documentation for [`MakeWriterExt::and`] for details.
1025    ///
1026    /// [writers]: std::io::Write
1027    pub fn new(a: A, b: B) -> Self {
1028        Self { a, b }
1029    }
1030}
1031
1032impl<'a, A, B> MakeWriter<'a> for Tee<A, B>
1033where
1034    A: MakeWriter<'a>,
1035    B: MakeWriter<'a>,
1036{
1037    type Writer = Tee<A::Writer, B::Writer>;
1038
1039    #[inline]
1040    fn make_writer(&'a self) -> Self::Writer {
1041        Tee::new(self.a.make_writer(), self.b.make_writer())
1042    }
1043
1044    #[inline]
1045    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1046        Tee::new(self.a.make_writer_for(meta), self.b.make_writer_for(meta))
1047    }
1048}
1049
1050macro_rules! impl_tee {
1051    ($self_:ident.$f:ident($($arg:ident),*)) => {
1052        {
1053            let res_a = $self_.a.$f($($arg),*);
1054            let res_b = $self_.b.$f($($arg),*);
1055            (res_a?, res_b?)
1056        }
1057    }
1058}
1059
1060impl<A, B> io::Write for Tee<A, B>
1061where
1062    A: io::Write,
1063    B: io::Write,
1064{
1065    #[inline]
1066    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1067        let (a, b) = impl_tee!(self.write(buf));
1068        Ok(std::cmp::max(a, b))
1069    }
1070
1071    #[inline]
1072    fn flush(&mut self) -> io::Result<()> {
1073        impl_tee!(self.flush());
1074        Ok(())
1075    }
1076
1077    #[inline]
1078    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
1079        let (a, b) = impl_tee!(self.write_vectored(bufs));
1080        Ok(std::cmp::max(a, b))
1081    }
1082
1083    #[inline]
1084    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1085        impl_tee!(self.write_all(buf));
1086        Ok(())
1087    }
1088
1089    #[inline]
1090    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
1091        impl_tee!(self.write_fmt(fmt));
1092        Ok(())
1093    }
1094}
1095
1096// === impl OrElse ===
1097
1098impl<A, B> OrElse<A, B> {
1099    /// Combines
1100    pub fn new<'a, W>(inner: A, or_else: B) -> Self
1101    where
1102        A: MakeWriter<'a, Writer = OptionalWriter<W>>,
1103        B: MakeWriter<'a>,
1104        W: Write,
1105    {
1106        Self { inner, or_else }
1107    }
1108}
1109
1110impl<'a, A, B, W> MakeWriter<'a> for OrElse<A, B>
1111where
1112    A: MakeWriter<'a, Writer = OptionalWriter<W>>,
1113    B: MakeWriter<'a>,
1114    W: io::Write,
1115{
1116    type Writer = EitherWriter<W, B::Writer>;
1117
1118    #[inline]
1119    fn make_writer(&'a self) -> Self::Writer {
1120        match self.inner.make_writer() {
1121            EitherWriter::A(writer) => EitherWriter::A(writer),
1122            EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer()),
1123        }
1124    }
1125
1126    #[inline]
1127    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1128        match self.inner.make_writer_for(meta) {
1129            EitherWriter::A(writer) => EitherWriter::A(writer),
1130            EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer_for(meta)),
1131        }
1132    }
1133}
1134
1135// === impl ArcWriter ===
1136
1137impl<W> io::Write for ArcWriter<W>
1138where
1139    for<'a> &'a W: io::Write,
1140{
1141    #[inline]
1142    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1143        (&*self.0).write(buf)
1144    }
1145
1146    #[inline]
1147    fn flush(&mut self) -> io::Result<()> {
1148        (&*self.0).flush()
1149    }
1150
1151    #[inline]
1152    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
1153        (&*self.0).write_vectored(bufs)
1154    }
1155
1156    #[inline]
1157    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1158        (&*self.0).write_all(buf)
1159    }
1160
1161    #[inline]
1162    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
1163        (&*self.0).write_fmt(fmt)
1164    }
1165}
1166
1167// === impl WriteAdaptor ===
1168
1169#[cfg(any(feature = "json", feature = "time"))]
1170impl<'a> WriteAdaptor<'a> {
1171    pub(in crate::fmt) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self {
1172        Self { fmt_write }
1173    }
1174}
1175#[cfg(any(feature = "json", feature = "time"))]
1176impl<'a> io::Write for WriteAdaptor<'a> {
1177    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1178        let s =
1179            std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1180
1181        self.fmt_write
1182            .write_str(s)
1183            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
1184
1185        Ok(s.as_bytes().len())
1186    }
1187
1188    fn flush(&mut self) -> io::Result<()> {
1189        Ok(())
1190    }
1191}
1192
1193#[cfg(any(feature = "json", feature = "time"))]
1194impl<'a> fmt::Debug for WriteAdaptor<'a> {
1195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1196        f.pad("WriteAdaptor { .. }")
1197    }
1198}
1199// === blanket impls ===
1200
1201impl<'a, M> MakeWriterExt<'a> for M where M: MakeWriter<'a> {}
1202#[cfg(test)]
1203mod test {
1204    use super::*;
1205    use crate::fmt::format::Format;
1206    use crate::fmt::test::{MockMakeWriter, MockWriter};
1207    use crate::fmt::Subscriber;
1208    use std::sync::atomic::{AtomicBool, Ordering};
1209    use std::sync::{Arc, Mutex};
1210    use tracing::{debug, error, info, trace, warn, Level};
1211    use tracing_core::dispatcher::{self, Dispatch};
1212
1213    fn test_writer<T>(make_writer: T, msg: &str, buf: &Mutex<Vec<u8>>)
1214    where
1215        T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,
1216    {
1217        let subscriber = {
1218            #[cfg(feature = "ansi")]
1219            let f = Format::default().without_time().with_ansi(false);
1220            #[cfg(not(feature = "ansi"))]
1221            let f = Format::default().without_time();
1222            Subscriber::builder()
1223                .event_format(f)
1224                .with_writer(make_writer)
1225                .finish()
1226        };
1227        let dispatch = Dispatch::from(subscriber);
1228
1229        dispatcher::with_default(&dispatch, || {
1230            error!("{}", msg);
1231        });
1232
1233        let expected = format!("ERROR {}: {}\n", module_path!(), msg);
1234        let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
1235        assert!(actual.contains(expected.as_str()));
1236    }
1237
1238    fn has_lines(buf: &Mutex<Vec<u8>>, msgs: &[(tracing::Level, &str)]) {
1239        let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
1240        let mut expected_lines = msgs.iter();
1241        for line in actual.lines() {
1242            let line = dbg!(line).trim();
1243            let (level, msg) = expected_lines
1244                .next()
1245                .unwrap_or_else(|| panic!("expected no more lines, but got: {:?}", line));
1246            let expected = format!("{} {}: {}", level, module_path!(), msg);
1247            assert_eq!(line, expected.as_str());
1248        }
1249    }
1250
1251    #[test]
1252    fn custom_writer_closure() {
1253        let buf = Arc::new(Mutex::new(Vec::new()));
1254        let buf2 = buf.clone();
1255        let make_writer = move || MockWriter::new(buf2.clone());
1256        let msg = "my custom writer closure error";
1257        test_writer(make_writer, msg, &buf);
1258    }
1259
1260    #[test]
1261    fn custom_writer_struct() {
1262        let buf = Arc::new(Mutex::new(Vec::new()));
1263        let make_writer = MockMakeWriter::new(buf.clone());
1264        let msg = "my custom writer struct error";
1265        test_writer(make_writer, msg, &buf);
1266    }
1267
1268    #[test]
1269    fn custom_writer_mutex() {
1270        let buf = Arc::new(Mutex::new(Vec::new()));
1271        let writer = MockWriter::new(buf.clone());
1272        let make_writer = Mutex::new(writer);
1273        let msg = "my mutex writer error";
1274        test_writer(make_writer, msg, &buf);
1275    }
1276
1277    #[test]
1278    fn combinators_level_filters() {
1279        let info_buf = Arc::new(Mutex::new(Vec::new()));
1280        let info = MockMakeWriter::new(info_buf.clone());
1281
1282        let debug_buf = Arc::new(Mutex::new(Vec::new()));
1283        let debug = MockMakeWriter::new(debug_buf.clone());
1284
1285        let warn_buf = Arc::new(Mutex::new(Vec::new()));
1286        let warn = MockMakeWriter::new(warn_buf.clone());
1287
1288        let err_buf = Arc::new(Mutex::new(Vec::new()));
1289        let err = MockMakeWriter::new(err_buf.clone());
1290
1291        let make_writer = info
1292            .with_max_level(Level::INFO)
1293            .and(debug.with_max_level(Level::DEBUG))
1294            .and(warn.with_max_level(Level::WARN))
1295            .and(err.with_max_level(Level::ERROR));
1296
1297        let c = {
1298            #[cfg(feature = "ansi")]
1299            let f = Format::default().without_time().with_ansi(false);
1300            #[cfg(not(feature = "ansi"))]
1301            let f = Format::default().without_time();
1302            Subscriber::builder()
1303                .event_format(f)
1304                .with_writer(make_writer)
1305                .with_max_level(Level::TRACE)
1306                .finish()
1307        };
1308
1309        let _s = tracing::subscriber::set_default(c);
1310
1311        trace!("trace");
1312        debug!("debug");
1313        info!("info");
1314        warn!("warn");
1315        error!("error");
1316
1317        let all_lines = [
1318            (Level::TRACE, "trace"),
1319            (Level::DEBUG, "debug"),
1320            (Level::INFO, "info"),
1321            (Level::WARN, "warn"),
1322            (Level::ERROR, "error"),
1323        ];
1324
1325        println!("max level debug");
1326        has_lines(&debug_buf, &all_lines[1..]);
1327
1328        println!("max level info");
1329        has_lines(&info_buf, &all_lines[2..]);
1330
1331        println!("max level warn");
1332        has_lines(&warn_buf, &all_lines[3..]);
1333
1334        println!("max level error");
1335        has_lines(&err_buf, &all_lines[4..]);
1336    }
1337
1338    #[test]
1339    fn combinators_or_else() {
1340        let some_buf = Arc::new(Mutex::new(Vec::new()));
1341        let some = MockMakeWriter::new(some_buf.clone());
1342
1343        let or_else_buf = Arc::new(Mutex::new(Vec::new()));
1344        let or_else = MockMakeWriter::new(or_else_buf.clone());
1345
1346        let return_some = AtomicBool::new(true);
1347        let make_writer = move || {
1348            if return_some.swap(false, Ordering::Relaxed) {
1349                OptionalWriter::some(some.make_writer())
1350            } else {
1351                OptionalWriter::none()
1352            }
1353        };
1354        let make_writer = make_writer.or_else(or_else);
1355        let c = {
1356            #[cfg(feature = "ansi")]
1357            let f = Format::default().without_time().with_ansi(false);
1358            #[cfg(not(feature = "ansi"))]
1359            let f = Format::default().without_time();
1360            Subscriber::builder()
1361                .event_format(f)
1362                .with_writer(make_writer)
1363                .with_max_level(Level::TRACE)
1364                .finish()
1365        };
1366
1367        let _s = tracing::subscriber::set_default(c);
1368        info!("hello");
1369        info!("world");
1370        info!("goodbye");
1371
1372        has_lines(&some_buf, &[(Level::INFO, "hello")]);
1373        has_lines(
1374            &or_else_buf,
1375            &[(Level::INFO, "world"), (Level::INFO, "goodbye")],
1376        );
1377    }
1378
1379    #[test]
1380    fn combinators_or_else_chain() {
1381        let info_buf = Arc::new(Mutex::new(Vec::new()));
1382        let info = MockMakeWriter::new(info_buf.clone());
1383
1384        let debug_buf = Arc::new(Mutex::new(Vec::new()));
1385        let debug = MockMakeWriter::new(debug_buf.clone());
1386
1387        let warn_buf = Arc::new(Mutex::new(Vec::new()));
1388        let warn = MockMakeWriter::new(warn_buf.clone());
1389
1390        let err_buf = Arc::new(Mutex::new(Vec::new()));
1391        let err = MockMakeWriter::new(err_buf.clone());
1392
1393        let make_writer = err.with_max_level(Level::ERROR).or_else(
1394            warn.with_max_level(Level::WARN).or_else(
1395                info.with_max_level(Level::INFO)
1396                    .or_else(debug.with_max_level(Level::DEBUG)),
1397            ),
1398        );
1399
1400        let c = {
1401            #[cfg(feature = "ansi")]
1402            let f = Format::default().without_time().with_ansi(false);
1403            #[cfg(not(feature = "ansi"))]
1404            let f = Format::default().without_time();
1405            Subscriber::builder()
1406                .event_format(f)
1407                .with_writer(make_writer)
1408                .with_max_level(Level::TRACE)
1409                .finish()
1410        };
1411
1412        let _s = tracing::subscriber::set_default(c);
1413
1414        trace!("trace");
1415        debug!("debug");
1416        info!("info");
1417        warn!("warn");
1418        error!("error");
1419
1420        println!("max level debug");
1421        has_lines(&debug_buf, &[(Level::DEBUG, "debug")]);
1422
1423        println!("max level info");
1424        has_lines(&info_buf, &[(Level::INFO, "info")]);
1425
1426        println!("max level warn");
1427        has_lines(&warn_buf, &[(Level::WARN, "warn")]);
1428
1429        println!("max level error");
1430        has_lines(&err_buf, &[(Level::ERROR, "error")]);
1431    }
1432
1433    #[test]
1434    fn combinators_and() {
1435        let a_buf = Arc::new(Mutex::new(Vec::new()));
1436        let a = MockMakeWriter::new(a_buf.clone());
1437
1438        let b_buf = Arc::new(Mutex::new(Vec::new()));
1439        let b = MockMakeWriter::new(b_buf.clone());
1440
1441        let lines = &[(Level::INFO, "hello"), (Level::INFO, "world")];
1442
1443        let make_writer = a.and(b);
1444        let c = {
1445            #[cfg(feature = "ansi")]
1446            let f = Format::default().without_time().with_ansi(false);
1447            #[cfg(not(feature = "ansi"))]
1448            let f = Format::default().without_time();
1449            Subscriber::builder()
1450                .event_format(f)
1451                .with_writer(make_writer)
1452                .with_max_level(Level::TRACE)
1453                .finish()
1454        };
1455
1456        let _s = tracing::subscriber::set_default(c);
1457        info!("hello");
1458        info!("world");
1459
1460        has_lines(&a_buf, &lines[..]);
1461        has_lines(&b_buf, &lines[..]);
1462    }
1463}