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