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