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