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