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