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