Coverage Report

Created: 2025-11-11 06:41

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