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`][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 |
96 | pub 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. |
218 | pub 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)] |
512 | pub 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 |
542 | pub 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)] |
554 | pub 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 |
568 | pub 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)] |
579 | pub 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)] |
593 | pub 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)] |
610 | pub 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)] |
624 | pub 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)] |
635 | pub 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)] |
653 | pub 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)] |
659 | pub 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" ))] |
669 | pub(in crate::fmt) struct WriteAdaptor<'a> { |
670 | fmt_write: &'a mut dyn fmt::Write, |
671 | } |
672 | |
673 | impl<'a, F, W> MakeWriter<'a> for F |
674 | where |
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 | |
685 | impl<'a, W> MakeWriter<'a> for Arc<W> |
686 | where |
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 | |
695 | impl<'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 | |
704 | impl TestWriter { |
705 | /// Returns a new `TestWriter` with the default configuration. |
706 | pub fn new() -> Self { |
707 | Self::default() |
708 | } |
709 | } |
710 | |
711 | impl 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 | |
723 | impl<'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 | |
733 | impl 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 | |
747 | impl 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 | |
755 | impl<'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 | |
769 | struct Boxed<M>(M); |
770 | |
771 | impl<'a, M> MakeWriter<'a> for Boxed<M> |
772 | where |
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 | |
790 | impl<'a, W> MakeWriter<'a> for Mutex<W> |
791 | where |
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 | |
801 | impl<'a, W> io::Write for MutexGuardWriter<'a, W> |
802 | where |
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 | |
833 | impl<A, B> io::Write for EitherWriter<A, B> |
834 | where |
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 | |
879 | impl<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 | |
901 | impl<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 | |
913 | impl<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 | |
926 | impl<'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 | |
946 | impl<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 | |
959 | impl<'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 | |
979 | impl<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 | |
996 | impl<'a, M, F> MakeWriter<'a> for WithFilter<M, F> |
997 | where |
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 | |
1020 | impl<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 | |
1033 | impl<'a, A, B> MakeWriter<'a> for Tee<A, B> |
1034 | where |
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 | |
1051 | macro_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 | |
1061 | impl<A, B> io::Write for Tee<A, B> |
1062 | where |
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 | |
1099 | impl<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 | |
1111 | impl<'a, A, B, W> MakeWriter<'a> for OrElse<A, B> |
1112 | where |
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 | |
1138 | impl<W> io::Write for ArcWriter<W> |
1139 | where |
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" ))] |
1171 | impl<'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" ))] |
1177 | impl<'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" ))] |
1195 | impl<'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 | |
1202 | impl<'a, M> MakeWriterExt<'a> for M where M: MakeWriter<'a> {} |
1203 | #[cfg (test)] |
1204 | mod 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 | |