1 //! Abstractions for creating [`io::Write`] instances.
3 //! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
9 use tracing_core
::Metadata
;
11 /// A type that can create [`io::Write`] instances.
13 /// `MakeWriter` is used by [`fmt::Subscriber`] or [`fmt::Layer`] to print formatted text representations of
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`].
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.
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:
36 /// let subscriber = tracing_subscriber::fmt()
37 /// .with_writer(std::io::stderr)
39 /// # drop(subscriber);
42 /// Any function that returns a writer can be used:
45 /// fn make_my_great_writer() -> impl std::io::Write {
47 /// # std::io::stdout()
50 /// let subscriber = tracing_subscriber::fmt()
51 /// .with_writer(make_my_great_writer)
53 /// # drop(subscriber);
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:
62 /// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
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())
70 /// Box::new(io::stdout())
74 /// # drop(subscriber);
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`].
91 /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
92 /// [`make_writer`]: #tymethod.make_writer
93 type Writer
: io
::Write
;
95 /// Returns an instance of [`Writer`].
97 /// # Implementer notes
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.
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
;
110 /// Returns a [`Writer`] for writing data from the span or event described
111 /// by the provided [`Metadata`].
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.
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
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:
128 /// use std::io::{self, Stdout, Stderr};
129 /// use tracing_subscriber::fmt::writer::MakeWriter;
130 /// use tracing_core::{Metadata, Level};
132 /// pub struct MyMakeWriter {}
134 /// /// A lock on either stdout or stderr, depending on the verbosity level
135 /// /// of the event being written.
141 /// impl io::Write for Stdio {
142 /// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
144 /// Stdio::Stdout(io) => io.write(buf),
145 /// Stdio::Stderr(io) => io.write(buf),
149 /// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
152 /// # Stdio::Stdout(io) => io.write_all(buf),
153 /// # Stdio::Stderr(io) => io.write_all(buf),
157 /// fn flush(&mut self) -> io::Result<()> {
160 /// # Stdio::Stdout(io) => io.flush(),
161 /// # Stdio::Stderr(io) => io.flush(),
166 /// impl MakeWriter for MyMakeWriter {
167 /// type Writer = Stdio;
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())
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());
184 /// // Otherwise, we'll return stdout.
185 /// Stdio::Stdout(io::stdout())
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
{
201 /// Extension trait adding combinators for working with types implementing
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
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`.
212 /// Events whose level is more verbose than `level` will be ignored, and no
213 /// output will be written.
218 /// use tracing::Level;
219 /// use tracing_subscriber::fmt::writer::MakeWriterExt;
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);
225 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
228 /// Writing the `ERROR` and `WARN` levels to `stderr`, and everything else
232 /// # use tracing::Level;
233 /// # use tracing_subscriber::fmt::writer::MakeWriterExt;
235 /// let mk_writer = std::io::stderr
236 /// .with_max_level(Level::WARN)
237 /// .or_else(std::io::stdout);
239 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
242 /// Writing the `ERROR` level to `stderr`, the `INFO` and `WARN` levels to
243 /// `stdout`, and the `INFO` and DEBUG` levels to a file:
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")?);
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))
260 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
264 /// [`Level`]: tracing_core::Level
265 /// [`io::Write`]: std::io::Write
266 fn with_max_level(self, level
: tracing_core
::Level
) -> WithMaxLevel
<Self>
270 WithMaxLevel
::new(self, level
)
273 /// Wraps `self` and returns a [`MakeWriter`] that will only write output
274 /// for events at or above the provided verbosity [`Level`].
276 /// Events whose level is less verbose than `level` will be ignored, and no
277 /// output will be written.
282 /// use tracing::Level;
283 /// use tracing_subscriber::fmt::writer::MakeWriterExt;
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);
289 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
291 /// This can be combined with [`MakeWriterExt::with_max_level`] to write
292 /// only within a range of levels:
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));
304 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
306 /// [`Level`]: tracing_core::Level
307 /// [`io::Write`]: std::io::Write
308 fn with_min_level(self, level
: tracing_core
::Level
) -> WithMinLevel
<Self>
312 WithMinLevel
::new(self, level
)
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.
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.
325 /// This can be used to filter an output based on arbitrary [`Metadata`]
330 /// Writing events with a specific target to an HTTP access log, and other
331 /// events to stdout:
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")?);
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);
347 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
352 /// Conditionally enabling or disabling a log file:
354 /// use tracing_subscriber::fmt::writer::MakeWriterExt;
356 /// sync::{Arc, atomic::{AtomicBool, Ordering}},
360 /// static DEBUG_LOG_ENABLED: AtomicBool = AtomicBool::new(false);
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));
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);
374 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
378 /// // Later, we can toggle on or off the debug log file.
379 /// DEBUG_LOG_ENABLED.store(true, Ordering::Release);
384 /// [`Metadata`]: tracing_core::Metadata
385 /// [mwf]: MakeWriter::make_writer_for
386 fn with_filter
<F
>(self, filter
: F
) -> WithFilter
<Self, F
>
389 F
: Fn(&Metadata
<'_
>) -> bool
,
391 WithFilter
::new(self, filter
)
394 /// Combines `self` with another type implementing [`MakeWriter`], returning
395 /// a new [`MakeWriter`] that produces [writers] that write to *both*
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.
406 /// use tracing_subscriber::fmt::writer::MakeWriterExt;
408 /// // Construct a writer that outputs events to `stdout` *and* `stderr`.
409 /// let mk_writer = std::io::stdout.and(std::io::stderr);
411 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
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
>
419 B
: MakeWriter
+ Sized
,
421 Tee
::new(self, other
)
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`].
431 /// use tracing::Level;
432 /// use tracing_subscriber::fmt::writer::MakeWriterExt;
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);
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);
442 /// tracing_subscriber::fmt().with_writer(mk_writer).init();
444 fn or_else
<W
, B
>(self, other
: B
) -> OrElse
<Self, B
>
446 Self: MakeWriter
<Writer
= OptionalWriter
<W
>> + Sized
,
447 B
: MakeWriter
+ Sized
,
450 OrElse
::new(self, other
)
454 /// A writer intended to support [`libtest`'s output capturing][capturing] for use in unit tests.
456 /// `TestWriter` is used by [`fmt::Subscriber`] or [`fmt::Layer`] to enable capturing support.
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.
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.
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
{
476 /// A writer that erases the specific [`io::Write`] and [`MakeWriter`] types being used.
478 /// This is useful in cases where the concrete type of the writer cannot be known
483 /// A function that returns a [`Subscriber`] that will write to either stdout or stderr:
486 /// # use tracing::Subscriber;
487 /// # use tracing_subscriber::fmt::writer::BoxMakeWriter;
489 /// fn dynamic_writer(use_stderr: bool) -> impl Subscriber {
490 /// let writer = if use_stderr {
491 /// BoxMakeWriter::new(std::io::stderr)
493 /// BoxMakeWriter::new(std::io::stdout)
496 /// tracing_subscriber::fmt().with_writer(writer).finish()
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
>,
507 /// A [writer] that is one of two types implementing [`io::Write`][writer].
509 /// This may be used by [`MakeWriter`] implementations that may conditionally
510 /// return one of two writers.
512 /// [writer]: std::io::Write
513 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
514 pub enum EitherWriter
<A
, B
> {
515 /// A writer of type `A`.
517 /// A writer of type `B`.
521 /// A [writer] which may or may not be enabled.
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`].
527 /// [writer]: std::io::Write
528 pub type OptionalWriter
<T
> = EitherWriter
<T
, std
::io
::Sink
>;
530 /// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
531 /// and events with metadata at or below a specified verbosity [`Level`].
533 /// This is returned by the [`MakeWriterExt::with_max_level] method. See the
534 /// method documentation for details.
536 /// [writer]: std::io::Write
537 /// [`Level`]: tracing_core::Level
538 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
539 pub struct WithMaxLevel
<M
> {
541 level
: tracing_core
::Level
,
544 /// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
545 /// and events with metadata at or above a specified verbosity [`Level`].
547 /// This is returned by the [`MakeWriterExt::with_min_level] method. See the
548 /// method documentation for details.
550 /// [writer]: std::io::Write
551 /// [`Level`]: tracing_core::Level
552 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
553 pub struct WithMinLevel
<M
> {
555 level
: tracing_core
::Level
,
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`.
563 /// This is returned by the [`MakeWriterExt::with_filter`] method. See the
564 /// method documentation for details.
566 /// [`Metadata`]: tracing_core::Metadata
567 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
568 pub struct WithFilter
<M
, F
> {
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`].
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
> {
585 /// Combines two types implementing [`MakeWriter`] (or [`std::io::Write`]) to
586 /// produce a writer that writes to both [`MakeWriter`]'s returned writers.
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
> {
596 impl<F
, W
> MakeWriter
for F
603 fn make_writer(&self) -> Self::Writer
{
608 impl<W
> MakeWriter
for Arc
<W
>
610 for<'a
> &'a W
: io
::Write
,
612 type Writer
= ArcWriter
<W
>;
613 fn make_writer(&self) -> Self::Writer
{
614 ArcWriter(self.clone())
618 /// Implements [`std::io::Write`] for an [`Arc`]<W> where `&W: Write`.
620 /// This is an implementation detail of the [`MakeWriter`] impl for [`Arc`].
621 #[derive(Clone, Debug)]
622 pub struct ArcWriter
<W
>(Arc
<W
>);
624 // === impl TestWriter ===
627 /// Returns a new `TestWriter` with the default configuration.
628 pub fn new() -> Self {
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
);
640 fn flush(&mut self) -> io
::Result
<()> {
645 impl MakeWriter
for TestWriter
{
648 fn make_writer(&self) -> Self::Writer
{
654 /// Constructs a `BoxMakeWriter` wrapping a type implementing [`MakeWriter`].
656 /// [`MakeWriter`]: trait.MakeWriter.html
657 pub fn new
<M
>(make_writer
: M
) -> Self
659 M
: MakeWriter
+ Send
+ Sync
+ '
static,
660 M
::Writer
: Write
+ '
static,
663 inner
: Box
::new(Boxed(make_writer
)),
664 name
: std
::any
::type_name
::<M
>(),
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
))
677 impl MakeWriter
for BoxMakeWriter
{
678 type Writer
= Box
<dyn Write
>;
680 fn make_writer(&self) -> Self::Writer
{
681 self.inner
.make_writer()
684 fn make_writer_for(&self, meta
: &Metadata
<'_
>) -> Self::Writer
{
685 self.inner
.make_writer_for(meta
)
691 impl<M
> MakeWriter
for Boxed
<M
>
694 M
::Writer
: Write
+ '
static,
696 type Writer
= Box
<dyn Write
>;
698 fn make_writer(&self) -> Self::Writer
{
699 let w
= self.0.make_writer();
703 fn make_writer_for(&self, meta
: &Metadata
<'_
>) -> Self::Writer
{
704 let w
= self.0.make_writer_for(meta
);
709 // === impl EitherWriter ===
711 impl<A
, B
> io
::Write
for EitherWriter
<A
, B
>
717 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
719 EitherWriter
::A(a
) => a
.write(buf
),
720 EitherWriter
::B(b
) => b
.write(buf
),
725 fn flush(&mut self) -> io
::Result
<()> {
727 EitherWriter
::A(a
) => a
.flush(),
728 EitherWriter
::B(b
) => b
.flush(),
733 fn write_vectored(&mut self, bufs
: &[io
::IoSlice
<'_
>]) -> io
::Result
<usize> {
735 EitherWriter
::A(a
) => a
.write_vectored(bufs
),
736 EitherWriter
::B(b
) => b
.write_vectored(bufs
),
741 fn write_all(&mut self, buf
: &[u8]) -> io
::Result
<()> {
743 EitherWriter
::A(a
) => a
.write_all(buf
),
744 EitherWriter
::B(b
) => b
.write_all(buf
),
749 fn write_fmt(&mut self, fmt
: std
::fmt
::Arguments
<'_
>) -> io
::Result
<()> {
751 EitherWriter
::A(a
) => a
.write_fmt(fmt
),
752 EitherWriter
::B(b
) => b
.write_fmt(fmt
),
757 impl<T
> OptionalWriter
<T
> {
758 /// Returns a [disabled writer].
760 /// Any bytes written to the returned writer are discarded.
762 /// This is equivalent to returning [`Option::None`].
764 /// [disabled writer]: std::io::sink
766 pub fn none() -> Self {
767 EitherWriter
::B(std
::io
::sink())
770 /// Returns an enabled writer of type `T`.
772 /// This is equivalent to returning [`Option::Some`].
774 pub fn some(t
: T
) -> Self {
779 impl<T
> From
<Option
<T
>> for OptionalWriter
<T
> {
781 fn from(opt
: Option
<T
>) -> Self {
783 Some(writer
) => Self::some(writer
),
784 None
=> Self::none(),
789 // === impl WithMaxLevel ===
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.
796 /// See [`MakeWriterExt::with_max_level`] for details.
798 /// [`Level`]: tracing_core::Level
799 pub fn new(make
: M
, level
: tracing_core
::Level
) -> Self {
804 impl<M
: MakeWriter
> MakeWriter
for WithMaxLevel
<M
> {
805 type Writer
= OptionalWriter
<M
::Writer
>;
808 fn make_writer(&self) -> Self::Writer
{
809 // If we don't know the level, assume it's disabled.
810 OptionalWriter
::none()
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
));
818 OptionalWriter
::none()
822 // === impl WithMinLevel ===
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.
829 /// See [`MakeWriterExt::with_min_level`] for details.
831 /// [`Level`]: tracing_core::Level
832 pub fn new(make
: M
, level
: tracing_core
::Level
) -> Self {
837 impl<M
: MakeWriter
> MakeWriter
for WithMinLevel
<M
> {
838 type Writer
= OptionalWriter
<M
::Writer
>;
841 fn make_writer(&self) -> Self::Writer
{
842 // If we don't know the level, assume it's disabled.
843 OptionalWriter
::none()
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
));
851 OptionalWriter
::none()
855 // ==== impl WithFilter ===
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.
862 /// See [`MakeWriterExt::with_filter`] for details.
864 /// [`Metadata`]: tracing_core::Metadata
865 /// [`sink`]: std::io::sink
866 pub fn new(make
: M
, filter
: F
) -> Self
868 F
: Fn(&Metadata
<'_
>) -> bool
,
870 Self { make, filter }
874 impl<M
, F
> MakeWriter
for WithFilter
<M
, F
>
877 F
: Fn(&Metadata
<'_
>) -> bool
,
879 type Writer
= OptionalWriter
<M
::Writer
>;
882 fn make_writer(&self) -> Self::Writer
{
883 OptionalWriter
::some(self.make
.make_writer())
887 fn make_writer_for(&self, meta
: &Metadata
<'_
>) -> Self::Writer
{
888 if (self.filter
)(meta
) {
889 OptionalWriter
::some(self.make
.make_writer_for(meta
))
891 OptionalWriter
::none()
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*
903 /// See the documentation for [`MakeWriterExt::and`] for details.
904 pub fn new(a
: A
, b
: B
) -> Self {
909 impl<A
, B
> MakeWriter
for Tee
<A
, B
>
914 type Writer
= Tee
<A
::Writer
, B
::Writer
>;
917 fn make_writer(&self) -> Self::Writer
{
918 Tee
::new(self.a
.make_writer(), self.b
.make_writer())
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
))
927 macro_rules
! impl_tee
{
928 ($self_
:ident
.$f
:ident($
($arg
:ident
),*)) => {
930 let res_a
= $self_
.a
.$
f($
($arg
),*);
931 let res_b
= $self_
.b
.$
f($
($arg
),*);
937 impl<A
, B
> io
::Write
for Tee
<A
, B
>
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
))
949 fn flush(&mut self) -> io
::Result
<()> {
950 impl_tee
!(self.flush());
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
))
961 fn write_all(&mut self, buf
: &[u8]) -> io
::Result
<()> {
962 impl_tee
!(self.write_all(buf
));
967 fn write_fmt(&mut self, fmt
: std
::fmt
::Arguments
<'_
>) -> io
::Result
<()> {
968 impl_tee
!(self.write_fmt(fmt
));
973 // === impl OrElse ===
975 impl<A
, B
> OrElse
<A
, B
> {
977 pub fn new
<W
>(inner
: A
, or_else
: B
) -> Self
979 A
: MakeWriter
<Writer
= OptionalWriter
<W
>>,
983 Self { inner, or_else }
987 impl<A
, B
, W
> MakeWriter
for OrElse
<A
, B
>
989 A
: MakeWriter
<Writer
= OptionalWriter
<W
>>,
993 type Writer
= EitherWriter
<W
, B
::Writer
>;
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()),
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
)),
1012 // === impl ArcWriter ===
1014 impl<W
> io
::Write
for ArcWriter
<W
>
1016 for<'a
> &'a W
: io
::Write
,
1019 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
1020 (&*self.0).write(buf
)
1024 fn flush(&mut self) -> io
::Result
<()> {
1029 fn write_vectored(&mut self, bufs
: &[io
::IoSlice
<'_
>]) -> io
::Result
<usize> {
1030 (&*self.0).write_vectored(bufs
)
1034 fn write_all(&mut self, buf
: &[u8]) -> io
::Result
<()> {
1035 (&*self.0).write_all(buf
)
1039 fn write_fmt(&mut self, fmt
: std
::fmt
::Arguments
<'_
>) -> io
::Result
<()> {
1040 (&*self.0).write_fmt(fmt
)
1044 // === blanket impls ===
1046 impl<M
> MakeWriterExt
for M
where M
: MakeWriter {}
1051 use crate::fmt
::format
::Format
;
1052 use crate::fmt
::test
::{MockMakeWriter, MockWriter}
;
1053 use crate::fmt
::Subscriber
;
1054 use lazy_static
::lazy_static
;
1056 atomic
::{AtomicBool, Ordering}
,
1059 use tracing
::{debug, error, info, trace, warn, Level}
;
1060 use tracing_core
::dispatcher
::{self, Dispatch}
;
1062 fn test_writer
<T
>(make_writer
: T
, msg
: &str, buf
: &Mutex
<Vec
<u8>>)
1064 T
: MakeWriter
+ Send
+ Sync
+ '
static,
1067 #[cfg(feature = "ansi")]
1069 let f
= Format
::default().without_time().with_ansi(false);
1070 Subscriber
::builder()
1072 .with_writer(make_writer
)
1075 #[cfg(not(feature = "ansi"))]
1077 let f
= Format
::default().without_time();
1078 Subscriber
::builder()
1080 .with_writer(make_writer
)
1084 let dispatch
= Dispatch
::from(subscriber
);
1086 dispatcher
::with_default(&dispatch
, || {
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()));
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
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());
1109 fn custom_writer_closure() {
1111 static ref BUF
: Mutex
<Vec
<u8>> = Mutex
::new(vec
![]);
1114 let make_writer
= || MockWriter
::new(&BUF
);
1115 let msg
= "my custom writer closure error";
1116 test_writer(make_writer
, msg
, &BUF
);
1120 fn custom_writer_struct() {
1122 static ref BUF
: Mutex
<Vec
<u8>> = Mutex
::new(vec
![]);
1125 let make_writer
= MockMakeWriter
::new(&BUF
);
1126 let msg
= "my custom writer struct error";
1127 test_writer(make_writer
, msg
, &BUF
);
1131 fn combinators_level_filters() {
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
![]);
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
);
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
));
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()
1157 .with_writer(make_writer
)
1158 .with_max_level(Level
::TRACE
)
1162 let _s
= tracing
::subscriber
::set_default(c
);
1171 (Level
::TRACE
, "trace"),
1172 (Level
::DEBUG
, "debug"),
1173 (Level
::INFO
, "info"),
1174 (Level
::WARN
, "warn"),
1175 (Level
::ERROR
, "error"),
1178 println
!("max level debug");
1179 has_lines(&DEBUG_BUF
, &all_lines
[1..]);
1181 println
!("max level info");
1182 has_lines(&INFO_BUF
, &all_lines
[2..]);
1184 println
!("max level warn");
1185 has_lines(&WARN_BUF
, &all_lines
[3..]);
1187 println
!("max level error");
1188 has_lines(&ERR_BUF
, &all_lines
[4..]);
1192 fn combinators_or_else() {
1194 static ref SOME_BUF
: Mutex
<Vec
<u8>> = Mutex
::new(vec
![]);
1195 static ref OR_ELSE_BUF
: Mutex
<Vec
<u8>> = Mutex
::new(vec
![]);
1198 let some
= MockMakeWriter
::new(&SOME_BUF
);
1199 let or_else
= MockMakeWriter
::new(&OR_ELSE_BUF
);
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())
1206 OptionalWriter
::none()
1209 let make_writer
= make_writer
.or_else(or_else
);
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()
1217 .with_writer(make_writer
)
1218 .with_max_level(Level
::TRACE
)
1222 let _s
= tracing
::subscriber
::set_default(c
);
1227 has_lines(&SOME_BUF
, &[(Level
::INFO
, "hello")]);
1230 &[(Level
::INFO
, "world"), (Level
::INFO
, "goodbye")],
1235 fn combinators_or_else_chain() {
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
![]);
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
);
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
)),
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()
1262 .with_writer(make_writer
)
1263 .with_max_level(Level
::TRACE
)
1267 let _s
= tracing
::subscriber
::set_default(c
);
1275 println
!("max level debug");
1276 has_lines(&DEBUG_BUF
, &[(Level
::DEBUG
, "debug")]);
1278 println
!("max level info");
1279 has_lines(&INFO_BUF
, &[(Level
::INFO
, "info")]);
1281 println
!("max level warn");
1282 has_lines(&WARN_BUF
, &[(Level
::WARN
, "warn")]);
1284 println
!("max level error");
1285 has_lines(&ERR_BUF
, &[(Level
::ERROR
, "error")]);
1289 fn combinators_and() {
1291 static ref A_BUF
: Mutex
<Vec
<u8>> = Mutex
::new(vec
![]);
1292 static ref B_BUF
: Mutex
<Vec
<u8>> = Mutex
::new(vec
![]);
1295 let a
= MockMakeWriter
::new(&A_BUF
);
1296 let b
= MockMakeWriter
::new(&B_BUF
);
1298 let lines
= &[(Level
::INFO
, "hello"), (Level
::INFO
, "world")];
1300 let make_writer
= a
.and(b
);
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()
1308 .with_writer(make_writer
)
1309 .with_max_level(Level
::TRACE
)
1313 let _s
= tracing
::subscriber
::set_default(c
);
1317 has_lines(&A_BUF
, &lines
[..]);
1318 has_lines(&B_BUF
, &lines
[..]);