1 //! Abstractions for creating [`io::Write`] instances. 2 //! 3 //! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html 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 tyoe 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`]: https://doc.rust-lang.org/std/io/trait.Write.html 100 /// [`make_writer`]: #tymethod.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`]: #associatedtype.Writer 113 /// [`fmt::Layer`]: crate::fmt::Layer 114 /// [`fmt::Subscriber`]: crate::fmt::Subscriber 115 /// [`io::Write`]: std::io::Write make_writer(&'a self) -> Self::Writer116 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 make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer206 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 with_max_level(self, level: tracing_core::Level) -> WithMaxLevel<Self> where Self: Sized,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 with_min_level(self, level: tracing_core::Level) -> WithMinLevel<Self> where Self: Sized,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 with_filter<F>(self, filter: F) -> WithFilter<Self, F> where Self: Sized, F: Fn(&Metadata<'_>) -> bool,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 and<B>(self, other: B) -> Tee<Self, B> where Self: Sized, B: MakeWriter<'a> + Sized,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 or_else<W, B>(self, other: B) -> OrElse<Self, B> where Self: MakeWriter<'a, Writer = OptionalWriter<W>> + Sized, B: MakeWriter<'a> + Sized, W: Write,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`]: ../struct.Subscriber.html 505 /// [`fmt::Layer`]: ../struct.Layer.html 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`]: https://doc.rust-lang.org/std/io/fn.stdout.html 509 /// [`io::stderr`]: https://doc.rust-lang.org/std/io/fn.stderr.html 510 /// [`print!`]: https://doc.rust-lang.org/std/macro.print.html 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`]: https://doc.rust-lang.org/std/io/trait.Write.html 650 /// [`MutexGuard`]: https://doc.rust-lang.org/std/sync/struct.MutexGuard.html 651 /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html 652 /// [`MakeWriter`]: trait.MakeWriter.html 653 #[derive(Debug)] 654 pub struct MutexGuardWriter<'a, W>(MutexGuard<'a, W>); 655 656 /// Implements [`std::io::Write`] for an [`Arc`]<W> where `&W: Write`. 657 /// 658 /// This is an implementation detail of the [`MakeWriter`] impl for [`Arc`]. 659 #[derive(Clone, Debug)] 660 pub struct ArcWriter<W>(Arc<W>); 661 662 /// A bridge between `fmt::Write` and `io::Write`. 663 /// 664 /// This is used by the timestamp formatting implementation for the `time` 665 /// crate and by the JSON formatter. In both cases, this is needed because 666 /// `tracing-subscriber`'s `FormatEvent`/`FormatTime` traits expect a 667 /// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s 668 /// `format_into` methods expect an `io::Write`. 669 #[cfg(any(feature = "json", feature = "time"))] 670 pub(in crate::fmt) struct WriteAdaptor<'a> { 671 fmt_write: &'a mut dyn fmt::Write, 672 } 673 674 impl<'a, F, W> MakeWriter<'a> for F 675 where 676 F: Fn() -> W, 677 W: io::Write, 678 { 679 type Writer = W; 680 make_writer(&'a self) -> Self::Writer681 fn make_writer(&'a self) -> Self::Writer { 682 (self)() 683 } 684 } 685 686 impl<'a, W> MakeWriter<'a> for Arc<W> 687 where 688 &'a W: io::Write + 'a, 689 { 690 type Writer = &'a W; make_writer(&'a self) -> Self::Writer691 fn make_writer(&'a self) -> Self::Writer { 692 &*self 693 } 694 } 695 696 impl<'a> MakeWriter<'a> for std::fs::File { 697 type Writer = &'a std::fs::File; make_writer(&'a self) -> Self::Writer698 fn make_writer(&'a self) -> Self::Writer { 699 self 700 } 701 } 702 703 // === impl TestWriter === 704 705 impl TestWriter { 706 /// Returns a new `TestWriter` with the default configuration. new() -> Self707 pub fn new() -> Self { 708 Self::default() 709 } 710 } 711 712 impl io::Write for TestWriter { write(&mut self, buf: &[u8]) -> io::Result<usize>713 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 714 let out_str = String::from_utf8_lossy(buf); 715 print!("{}", out_str); 716 Ok(buf.len()) 717 } 718 flush(&mut self) -> io::Result<()>719 fn flush(&mut self) -> io::Result<()> { 720 Ok(()) 721 } 722 } 723 724 impl<'a> MakeWriter<'a> for TestWriter { 725 type Writer = Self; 726 make_writer(&'a self) -> Self::Writer727 fn make_writer(&'a self) -> Self::Writer { 728 Self::default() 729 } 730 } 731 732 // === impl BoxMakeWriter === 733 734 impl BoxMakeWriter { 735 /// Constructs a `BoxMakeWriter` wrapping a type implementing [`MakeWriter`]. 736 /// 737 /// [`MakeWriter`]: trait.MakeWriter.html new<M>(make_writer: M) -> Self where M: for<'a> MakeWriter<'a> + Send + Sync + 'static,738 pub fn new<M>(make_writer: M) -> Self 739 where 740 M: for<'a> MakeWriter<'a> + Send + Sync + 'static, 741 { 742 Self { 743 inner: Box::new(Boxed(make_writer)), 744 name: std::any::type_name::<M>(), 745 } 746 } 747 } 748 749 impl fmt::Debug for BoxMakeWriter { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result750 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 751 f.debug_tuple("BoxMakeWriter") 752 .field(&format_args!("<{}>", self.name)) 753 .finish() 754 } 755 } 756 757 impl<'a> MakeWriter<'a> for BoxMakeWriter { 758 type Writer = Box<dyn Write + 'a>; 759 760 #[inline] make_writer(&'a self) -> Self::Writer761 fn make_writer(&'a self) -> Self::Writer { 762 self.inner.make_writer() 763 } 764 765 #[inline] make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer766 fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { 767 self.inner.make_writer_for(meta) 768 } 769 } 770 771 struct Boxed<M>(M); 772 773 impl<'a, M> MakeWriter<'a> for Boxed<M> 774 where 775 M: MakeWriter<'a>, 776 { 777 type Writer = Box<dyn Write + 'a>; 778 make_writer(&'a self) -> Self::Writer779 fn make_writer(&'a self) -> Self::Writer { 780 let w = self.0.make_writer(); 781 Box::new(w) 782 } 783 make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer784 fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { 785 let w = self.0.make_writer_for(meta); 786 Box::new(w) 787 } 788 } 789 790 // === impl Mutex/MutexGuardWriter === 791 792 impl<'a, W> MakeWriter<'a> for Mutex<W> 793 where 794 W: io::Write + 'a, 795 { 796 type Writer = MutexGuardWriter<'a, W>; 797 make_writer(&'a self) -> Self::Writer798 fn make_writer(&'a self) -> Self::Writer { 799 MutexGuardWriter(self.lock().expect("lock poisoned")) 800 } 801 } 802 803 impl<'a, W> io::Write for MutexGuardWriter<'a, W> 804 where 805 W: io::Write, 806 { 807 #[inline] write(&mut self, buf: &[u8]) -> io::Result<usize>808 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 809 self.0.write(buf) 810 } 811 812 #[inline] flush(&mut self) -> io::Result<()>813 fn flush(&mut self) -> io::Result<()> { 814 self.0.flush() 815 } 816 817 #[inline] write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>818 fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { 819 self.0.write_vectored(bufs) 820 } 821 822 #[inline] write_all(&mut self, buf: &[u8]) -> io::Result<()>823 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { 824 self.0.write_all(buf) 825 } 826 827 #[inline] write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()>828 fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> { 829 self.0.write_fmt(fmt) 830 } 831 } 832 833 // === impl EitherWriter === 834 835 impl<A, B> io::Write for EitherWriter<A, B> 836 where 837 A: io::Write, 838 B: io::Write, 839 { 840 #[inline] write(&mut self, buf: &[u8]) -> io::Result<usize>841 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 842 match self { 843 EitherWriter::A(a) => a.write(buf), 844 EitherWriter::B(b) => b.write(buf), 845 } 846 } 847 848 #[inline] flush(&mut self) -> io::Result<()>849 fn flush(&mut self) -> io::Result<()> { 850 match self { 851 EitherWriter::A(a) => a.flush(), 852 EitherWriter::B(b) => b.flush(), 853 } 854 } 855 856 #[inline] write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>857 fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { 858 match self { 859 EitherWriter::A(a) => a.write_vectored(bufs), 860 EitherWriter::B(b) => b.write_vectored(bufs), 861 } 862 } 863 864 #[inline] write_all(&mut self, buf: &[u8]) -> io::Result<()>865 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { 866 match self { 867 EitherWriter::A(a) => a.write_all(buf), 868 EitherWriter::B(b) => b.write_all(buf), 869 } 870 } 871 872 #[inline] write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()>873 fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> { 874 match self { 875 EitherWriter::A(a) => a.write_fmt(fmt), 876 EitherWriter::B(b) => b.write_fmt(fmt), 877 } 878 } 879 } 880 881 impl<T> OptionalWriter<T> { 882 /// Returns a [disabled writer]. 883 /// 884 /// Any bytes written to the returned writer are discarded. 885 /// 886 /// This is equivalent to returning [`Option::None`]. 887 /// 888 /// [disabled writer]: std::io::sink 889 #[inline] none() -> Self890 pub fn none() -> Self { 891 EitherWriter::B(std::io::sink()) 892 } 893 894 /// Returns an enabled writer of type `T`. 895 /// 896 /// This is equivalent to returning [`Option::Some`]. 897 #[inline] some(t: T) -> Self898 pub fn some(t: T) -> Self { 899 EitherWriter::A(t) 900 } 901 } 902 903 impl<T> From<Option<T>> for OptionalWriter<T> { 904 #[inline] from(opt: Option<T>) -> Self905 fn from(opt: Option<T>) -> Self { 906 match opt { 907 Some(writer) => Self::some(writer), 908 None => Self::none(), 909 } 910 } 911 } 912 913 // === impl WithMaxLevel === 914 915 impl<M> WithMaxLevel<M> { 916 /// Wraps the provided [`MakeWriter`] with a maximum [`Level`], so that it 917 /// returns [`OptionalWriter::none`] for spans and events whose level is 918 /// more verbose than the maximum level. 919 /// 920 /// See [`MakeWriterExt::with_max_level`] for details. 921 /// 922 /// [`Level`]: tracing_core::Level new(make: M, level: tracing_core::Level) -> Self923 pub fn new(make: M, level: tracing_core::Level) -> Self { 924 Self { make, level } 925 } 926 } 927 928 impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMaxLevel<M> { 929 type Writer = OptionalWriter<M::Writer>; 930 931 #[inline] make_writer(&'a self) -> Self::Writer932 fn make_writer(&'a self) -> Self::Writer { 933 // If we don't know the level, assume it's disabled. 934 OptionalWriter::none() 935 } 936 937 #[inline] make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer938 fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { 939 if meta.level() <= &self.level { 940 return OptionalWriter::some(self.make.make_writer_for(meta)); 941 } 942 OptionalWriter::none() 943 } 944 } 945 946 // === impl WithMinLevel === 947 948 impl<M> WithMinLevel<M> { 949 /// Wraps the provided [`MakeWriter`] with a minimum [`Level`], so that it 950 /// returns [`OptionalWriter::none`] for spans and events whose level is 951 /// less verbose than the maximum level. 952 /// 953 /// See [`MakeWriterExt::with_min_level`] for details. 954 /// 955 /// [`Level`]: tracing_core::Level new(make: M, level: tracing_core::Level) -> Self956 pub fn new(make: M, level: tracing_core::Level) -> Self { 957 Self { make, level } 958 } 959 } 960 961 impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMinLevel<M> { 962 type Writer = OptionalWriter<M::Writer>; 963 964 #[inline] make_writer(&'a self) -> Self::Writer965 fn make_writer(&'a self) -> Self::Writer { 966 // If we don't know the level, assume it's disabled. 967 OptionalWriter::none() 968 } 969 970 #[inline] make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer971 fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { 972 if meta.level() >= &self.level { 973 return OptionalWriter::some(self.make.make_writer_for(meta)); 974 } 975 OptionalWriter::none() 976 } 977 } 978 979 // ==== impl WithFilter === 980 981 impl<M, F> WithFilter<M, F> { 982 /// Wraps `make` with the provided `filter`, returning a [`MakeWriter`] that 983 /// will call `make.make_writer_for()` when `filter` returns `true` for a 984 /// span or event's [`Metadata`], and returns a [`sink`] otherwise. 985 /// 986 /// See [`MakeWriterExt::with_filter`] for details. 987 /// 988 /// [`Metadata`]: tracing_core::Metadata 989 /// [`sink`]: std::io::sink new(make: M, filter: F) -> Self where F: Fn(&Metadata<'_>) -> bool,990 pub fn new(make: M, filter: F) -> Self 991 where 992 F: Fn(&Metadata<'_>) -> bool, 993 { 994 Self { make, filter } 995 } 996 } 997 998 impl<'a, M, F> MakeWriter<'a> for WithFilter<M, F> 999 where 1000 M: MakeWriter<'a>, 1001 F: Fn(&Metadata<'_>) -> bool, 1002 { 1003 type Writer = OptionalWriter<M::Writer>; 1004 1005 #[inline] make_writer(&'a self) -> Self::Writer1006 fn make_writer(&'a self) -> Self::Writer { 1007 OptionalWriter::some(self.make.make_writer()) 1008 } 1009 1010 #[inline] make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer1011 fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { 1012 if (self.filter)(meta) { 1013 OptionalWriter::some(self.make.make_writer_for(meta)) 1014 } else { 1015 OptionalWriter::none() 1016 } 1017 } 1018 } 1019 1020 // === impl Tee === 1021 1022 impl<A, B> Tee<A, B> { 1023 /// Combines two types implementing [`MakeWriter`], returning 1024 /// a new [`MakeWriter`] that produces [writers] that write to *both* 1025 /// outputs. 1026 /// 1027 /// See the documentation for [`MakeWriterExt::and`] for details. new(a: A, b: B) -> Self1028 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] make_writer(&'a self) -> Self::Writer1041 fn make_writer(&'a self) -> Self::Writer { 1042 Tee::new(self.a.make_writer(), self.b.make_writer()) 1043 } 1044 1045 #[inline] make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer1046 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] write(&mut self, buf: &[u8]) -> io::Result<usize>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] flush(&mut self) -> io::Result<()>1073 fn flush(&mut self) -> io::Result<()> { 1074 impl_tee!(self.flush()); 1075 Ok(()) 1076 } 1077 1078 #[inline] write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>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] write_all(&mut self, buf: &[u8]) -> io::Result<()>1085 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { 1086 impl_tee!(self.write_all(buf)); 1087 Ok(()) 1088 } 1089 1090 #[inline] write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()>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 new<'a, W>(inner: A, or_else: B) -> Self where A: MakeWriter<'a, Writer = OptionalWriter<W>>, B: MakeWriter<'a>, W: Write,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] make_writer(&'a self) -> Self::Writer1120 fn make_writer(&'a self) -> Self::Writer { 1121 match self.inner.make_writer() { 1122 EitherWriter::A(writer) => EitherWriter::A(writer), 1123 EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer()), 1124 } 1125 } 1126 1127 #[inline] make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer1128 fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { 1129 match self.inner.make_writer_for(meta) { 1130 EitherWriter::A(writer) => 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] write(&mut self, buf: &[u8]) -> io::Result<usize>1143 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 1144 (&*self.0).write(buf) 1145 } 1146 1147 #[inline] flush(&mut self) -> io::Result<()>1148 fn flush(&mut self) -> io::Result<()> { 1149 (&*self.0).flush() 1150 } 1151 1152 #[inline] write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>1153 fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { 1154 (&*self.0).write_vectored(bufs) 1155 } 1156 1157 #[inline] write_all(&mut self, buf: &[u8]) -> io::Result<()>1158 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { 1159 (&*self.0).write_all(buf) 1160 } 1161 1162 #[inline] write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()>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> { new(fmt_write: &'a mut dyn fmt::Write) -> Self1172 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> { write(&mut self, buf: &[u8]) -> io::Result<usize>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 flush(&mut self) -> io::Result<()>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> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1196 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 test_writer<T>(make_writer: T, msg: &str, buf: &Mutex<Vec<u8>>) where T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,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 has_lines(buf: &Mutex<Vec<u8>>, msgs: &[(tracing::Level, &str)])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] custom_writer_closure()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] custom_writer_struct()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] custom_writer_mutex()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] combinators_level_filters()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] combinators_or_else()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] combinators_or_else_chain()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] combinators_and()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