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