tracing_subscriber/fmt/
writer.rs

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