Coverage Report

Created: 2026-02-11 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tracing-subscriber-0.3.22/src/fmt/writer.rs
Line
Count
Source
1
//! Abstractions for creating [`io::Write`] instances.
2
//!
3
//! [`io::Write`]: std::io::Write
4
5
use alloc::{boxed::Box, fmt, string::String, sync::Arc};
6
use std::{
7
    eprint,
8
    io::{self, Write},
9
    print,
10
    sync::{Mutex, MutexGuard},
11
};
12
use 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
98
pub 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
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
209
0
        let _ = meta;
210
0
        self.make_writer()
211
0
    }
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.
220
pub 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
0
    fn with_max_level(self, level: tracing_core::Level) -> WithMaxLevel<Self>
280
0
    where
281
0
        Self: Sized,
282
    {
283
0
        WithMaxLevel::new(self, level)
284
0
    }
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
0
    fn with_min_level(self, level: tracing_core::Level) -> WithMinLevel<Self>
322
0
    where
323
0
        Self: Sized,
324
    {
325
0
        WithMinLevel::new(self, level)
326
0
    }
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
0
    fn with_filter<F>(self, filter: F) -> WithFilter<Self, F>
401
0
    where
402
0
        Self: Sized,
403
0
        F: Fn(&Metadata<'_>) -> bool,
404
    {
405
0
        WithFilter::new(self, filter)
406
0
    }
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
0
    fn and<B>(self, other: B) -> Tee<Self, B>
456
0
    where
457
0
        Self: Sized,
458
0
        B: MakeWriter<'a> + Sized,
459
    {
460
0
        Tee::new(self, other)
461
0
    }
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
0
    fn or_else<W, B>(self, other: B) -> OrElse<Self, B>
487
0
    where
488
0
        Self: MakeWriter<'a, Writer = OptionalWriter<W>> + Sized,
489
0
        B: MakeWriter<'a> + Sized,
490
0
        W: Write,
491
    {
492
0
        OrElse::new(self, other)
493
0
    }
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)]
516
pub 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
548
pub 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)]
560
pub 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
574
pub 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)]
585
pub 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)]
599
pub 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)]
616
pub 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)]
630
pub 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)]
641
pub 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)]
659
pub 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)]
668
pub 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"))]
678
pub(in crate::fmt) struct WriteAdaptor<'a> {
679
    fmt_write: &'a mut dyn fmt::Write,
680
}
681
682
impl<'a, F, W> MakeWriter<'a> for F
683
where
684
    F: Fn() -> W,
685
    W: io::Write,
686
{
687
    type Writer = W;
688
689
0
    fn make_writer(&'a self) -> Self::Writer {
690
0
        (self)()
691
0
    }
692
}
693
694
impl<'a, W> MakeWriter<'a> for Arc<W>
695
where
696
    &'a W: io::Write + 'a,
697
{
698
    type Writer = &'a W;
699
0
    fn make_writer(&'a self) -> Self::Writer {
700
0
        self
701
0
    }
702
}
703
704
impl<'a> MakeWriter<'a> for std::fs::File {
705
    type Writer = &'a std::fs::File;
706
0
    fn make_writer(&'a self) -> Self::Writer {
707
0
        self
708
0
    }
709
}
710
711
// === impl TestWriter ===
712
713
impl TestWriter {
714
    /// Returns a new `TestWriter` with the default configuration.
715
0
    pub fn new() -> Self {
716
0
        Self::default()
717
0
    }
718
719
    /// Returns a new `TestWriter` that writes to `stderr` instead of `stdout`.
720
0
    pub fn with_stderr() -> Self {
721
0
        Self { use_stderr: true }
722
0
    }
723
}
724
725
impl io::Write for TestWriter {
726
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
727
0
        let out_str = String::from_utf8_lossy(buf);
728
0
        if self.use_stderr {
729
0
            eprint!("{}", out_str)
730
        } else {
731
0
            print!("{}", out_str)
732
        }
733
0
        Ok(buf.len())
734
0
    }
735
736
0
    fn flush(&mut self) -> io::Result<()> {
737
0
        Ok(())
738
0
    }
739
}
740
741
impl<'a> MakeWriter<'a> for TestWriter {
742
    type Writer = Self;
743
744
0
    fn make_writer(&'a self) -> Self::Writer {
745
0
        Self::default()
746
0
    }
747
}
748
749
// === impl BoxMakeWriter ===
750
751
impl BoxMakeWriter {
752
    /// Constructs a `BoxMakeWriter` wrapping a type implementing [`MakeWriter`].
753
    ///
754
0
    pub fn new<M>(make_writer: M) -> Self
755
0
    where
756
0
        M: for<'a> MakeWriter<'a> + Send + Sync + 'static,
757
    {
758
0
        Self {
759
0
            inner: Box::new(Boxed(make_writer)),
760
0
            name: std::any::type_name::<M>(),
761
0
        }
762
0
    }
763
}
764
765
impl fmt::Debug for BoxMakeWriter {
766
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767
0
        f.debug_tuple("BoxMakeWriter")
768
0
            .field(&format_args!("<{}>", self.name))
769
0
            .finish()
770
0
    }
771
}
772
773
impl<'a> MakeWriter<'a> for BoxMakeWriter {
774
    type Writer = Box<dyn Write + 'a>;
775
776
    #[inline]
777
0
    fn make_writer(&'a self) -> Self::Writer {
778
0
        self.inner.make_writer()
779
0
    }
780
781
    #[inline]
782
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
783
0
        self.inner.make_writer_for(meta)
784
0
    }
785
}
786
787
struct Boxed<M>(M);
788
789
impl<'a, M> MakeWriter<'a> for Boxed<M>
790
where
791
    M: MakeWriter<'a>,
792
{
793
    type Writer = Box<dyn Write + 'a>;
794
795
0
    fn make_writer(&'a self) -> Self::Writer {
796
0
        let w = self.0.make_writer();
797
0
        Box::new(w)
798
0
    }
799
800
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
801
0
        let w = self.0.make_writer_for(meta);
802
0
        Box::new(w)
803
0
    }
804
}
805
806
// === impl Mutex/MutexGuardWriter ===
807
808
impl<'a, W> MakeWriter<'a> for Mutex<W>
809
where
810
    W: io::Write + 'a,
811
{
812
    type Writer = MutexGuardWriter<'a, W>;
813
814
0
    fn make_writer(&'a self) -> Self::Writer {
815
0
        MutexGuardWriter(self.lock().expect("lock poisoned"))
816
0
    }
817
}
818
819
impl<W> io::Write for MutexGuardWriter<'_, W>
820
where
821
    W: io::Write,
822
{
823
    #[inline]
824
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
825
0
        self.0.write(buf)
826
0
    }
827
828
    #[inline]
829
0
    fn flush(&mut self) -> io::Result<()> {
830
0
        self.0.flush()
831
0
    }
832
833
    #[inline]
834
0
    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
835
0
        self.0.write_vectored(bufs)
836
0
    }
837
838
    #[inline]
839
0
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
840
0
        self.0.write_all(buf)
841
0
    }
842
843
    #[inline]
844
0
    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
845
0
        self.0.write_fmt(fmt)
846
0
    }
847
}
848
849
// === impl EitherWriter ===
850
851
impl<A, B> io::Write for EitherWriter<A, B>
852
where
853
    A: io::Write,
854
    B: io::Write,
855
{
856
    #[inline]
857
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
858
0
        match self {
859
0
            EitherWriter::A(a) => a.write(buf),
860
0
            EitherWriter::B(b) => b.write(buf),
861
        }
862
0
    }
863
864
    #[inline]
865
0
    fn flush(&mut self) -> io::Result<()> {
866
0
        match self {
867
0
            EitherWriter::A(a) => a.flush(),
868
0
            EitherWriter::B(b) => b.flush(),
869
        }
870
0
    }
871
872
    #[inline]
873
0
    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
874
0
        match self {
875
0
            EitherWriter::A(a) => a.write_vectored(bufs),
876
0
            EitherWriter::B(b) => b.write_vectored(bufs),
877
        }
878
0
    }
879
880
    #[inline]
881
0
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
882
0
        match self {
883
0
            EitherWriter::A(a) => a.write_all(buf),
884
0
            EitherWriter::B(b) => b.write_all(buf),
885
        }
886
0
    }
887
888
    #[inline]
889
0
    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
890
0
        match self {
891
0
            EitherWriter::A(a) => a.write_fmt(fmt),
892
0
            EitherWriter::B(b) => b.write_fmt(fmt),
893
        }
894
0
    }
895
}
896
897
impl<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
0
    pub fn none() -> Self {
907
0
        EitherWriter::B(std::io::sink())
908
0
    }
909
910
    /// Returns an enabled writer of type `T`.
911
    ///
912
    /// This is equivalent to returning [`Option::Some`].
913
    #[inline]
914
0
    pub fn some(t: T) -> Self {
915
0
        EitherWriter::A(t)
916
0
    }
917
}
918
919
impl<T> From<Option<T>> for OptionalWriter<T> {
920
    #[inline]
921
0
    fn from(opt: Option<T>) -> Self {
922
0
        match opt {
923
0
            Some(writer) => Self::some(writer),
924
0
            None => Self::none(),
925
        }
926
0
    }
927
}
928
929
// === impl WithMaxLevel ===
930
931
impl<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
0
    pub fn new(make: M, level: tracing_core::Level) -> Self {
940
0
        Self { make, level }
941
0
    }
942
}
943
944
impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMaxLevel<M> {
945
    type Writer = OptionalWriter<M::Writer>;
946
947
    #[inline]
948
0
    fn make_writer(&'a self) -> Self::Writer {
949
        // If we don't know the level, assume it's disabled.
950
0
        OptionalWriter::none()
951
0
    }
952
953
    #[inline]
954
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
955
0
        if meta.level() <= &self.level {
956
0
            return OptionalWriter::some(self.make.make_writer_for(meta));
957
0
        }
958
0
        OptionalWriter::none()
959
0
    }
960
}
961
962
// === impl WithMinLevel ===
963
964
impl<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
0
    pub fn new(make: M, level: tracing_core::Level) -> Self {
973
0
        Self { make, level }
974
0
    }
975
}
976
977
impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMinLevel<M> {
978
    type Writer = OptionalWriter<M::Writer>;
979
980
    #[inline]
981
0
    fn make_writer(&'a self) -> Self::Writer {
982
        // If we don't know the level, assume it's disabled.
983
0
        OptionalWriter::none()
984
0
    }
985
986
    #[inline]
987
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
988
0
        if meta.level() >= &self.level {
989
0
            return OptionalWriter::some(self.make.make_writer_for(meta));
990
0
        }
991
0
        OptionalWriter::none()
992
0
    }
993
}
994
995
// ==== impl WithFilter ===
996
997
impl<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
0
    pub fn new(make: M, filter: F) -> Self
1007
0
    where
1008
0
        F: Fn(&Metadata<'_>) -> bool,
1009
    {
1010
0
        Self { make, filter }
1011
0
    }
1012
}
1013
1014
impl<'a, M, F> MakeWriter<'a> for WithFilter<M, F>
1015
where
1016
    M: MakeWriter<'a>,
1017
    F: Fn(&Metadata<'_>) -> bool,
1018
{
1019
    type Writer = OptionalWriter<M::Writer>;
1020
1021
    #[inline]
1022
0
    fn make_writer(&'a self) -> Self::Writer {
1023
0
        OptionalWriter::some(self.make.make_writer())
1024
0
    }
1025
1026
    #[inline]
1027
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1028
0
        if (self.filter)(meta) {
1029
0
            OptionalWriter::some(self.make.make_writer_for(meta))
1030
        } else {
1031
0
            OptionalWriter::none()
1032
        }
1033
0
    }
1034
}
1035
1036
// === impl Tee ===
1037
1038
impl<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
0
    pub fn new(a: A, b: B) -> Self {
1047
0
        Self { a, b }
1048
0
    }
1049
}
1050
1051
impl<'a, A, B> MakeWriter<'a> for Tee<A, B>
1052
where
1053
    A: MakeWriter<'a>,
1054
    B: MakeWriter<'a>,
1055
{
1056
    type Writer = Tee<A::Writer, B::Writer>;
1057
1058
    #[inline]
1059
0
    fn make_writer(&'a self) -> Self::Writer {
1060
0
        Tee::new(self.a.make_writer(), self.b.make_writer())
1061
0
    }
1062
1063
    #[inline]
1064
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1065
0
        Tee::new(self.a.make_writer_for(meta), self.b.make_writer_for(meta))
1066
0
    }
1067
}
1068
1069
macro_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
1079
impl<A, B> io::Write for Tee<A, B>
1080
where
1081
    A: io::Write,
1082
    B: io::Write,
1083
{
1084
    #[inline]
1085
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1086
0
        let (a, b) = impl_tee!(self.write(buf));
1087
0
        Ok(std::cmp::max(a, b))
1088
0
    }
1089
1090
    #[inline]
1091
0
    fn flush(&mut self) -> io::Result<()> {
1092
0
        impl_tee!(self.flush());
1093
0
        Ok(())
1094
0
    }
1095
1096
    #[inline]
1097
0
    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
1098
0
        let (a, b) = impl_tee!(self.write_vectored(bufs));
1099
0
        Ok(std::cmp::max(a, b))
1100
0
    }
1101
1102
    #[inline]
1103
0
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1104
0
        impl_tee!(self.write_all(buf));
1105
0
        Ok(())
1106
0
    }
1107
1108
    #[inline]
1109
0
    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
1110
0
        impl_tee!(self.write_fmt(fmt));
1111
0
        Ok(())
1112
0
    }
1113
}
1114
1115
// === impl OrElse ===
1116
1117
impl<A, B> OrElse<A, B> {
1118
    /// Combines
1119
0
    pub fn new<'a, W>(inner: A, or_else: B) -> Self
1120
0
    where
1121
0
        A: MakeWriter<'a, Writer = OptionalWriter<W>>,
1122
0
        B: MakeWriter<'a>,
1123
0
        W: Write,
1124
    {
1125
0
        Self { inner, or_else }
1126
0
    }
1127
}
1128
1129
impl<'a, A, B, W> MakeWriter<'a> for OrElse<A, B>
1130
where
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
0
    fn make_writer(&'a self) -> Self::Writer {
1139
0
        match self.inner.make_writer() {
1140
0
            EitherWriter::A(writer) => EitherWriter::A(writer),
1141
0
            EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer()),
1142
        }
1143
0
    }
1144
1145
    #[inline]
1146
0
    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
1147
0
        match self.inner.make_writer_for(meta) {
1148
0
            EitherWriter::A(writer) => EitherWriter::A(writer),
1149
0
            EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer_for(meta)),
1150
        }
1151
0
    }
1152
}
1153
1154
// === impl ArcWriter ===
1155
1156
#[allow(deprecated)]
1157
impl<W> io::Write for ArcWriter<W>
1158
where
1159
    for<'a> &'a W: io::Write,
1160
{
1161
    #[inline]
1162
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1163
0
        (&*self.0).write(buf)
1164
0
    }
1165
1166
    #[inline]
1167
0
    fn flush(&mut self) -> io::Result<()> {
1168
0
        (&*self.0).flush()
1169
0
    }
1170
1171
    #[inline]
1172
0
    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
1173
0
        (&*self.0).write_vectored(bufs)
1174
0
    }
1175
1176
    #[inline]
1177
0
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1178
0
        (&*self.0).write_all(buf)
1179
0
    }
1180
1181
    #[inline]
1182
0
    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
1183
0
        (&*self.0).write_fmt(fmt)
1184
0
    }
1185
}
1186
1187
// === impl WriteAdaptor ===
1188
1189
#[cfg(any(feature = "json", feature = "time"))]
1190
impl<'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"))]
1196
impl 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"))]
1214
impl fmt::Debug for WriteAdaptor<'_> {
1215
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1216
        f.pad("WriteAdaptor { .. }")
1217
    }
1218
}
1219
// === blanket impls ===
1220
1221
impl<'a, M> MakeWriterExt<'a> for M where M: MakeWriter<'a> {}
1222
#[cfg(test)]
1223
mod 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
}