| 1 | //! Abstractions for creating [`io::Write`] instances. |
| 2 | //! |
| 3 | //! [`io::Write`]: std::io::Write |
| 4 | use std::{ |
| 5 | fmt, |
| 6 | io::{self, Write}, |
| 7 | sync::{Arc, Mutex, MutexGuard}, |
| 8 | }; |
| 9 | use tracing_core::Metadata; |
| 10 | |
| 11 | /// A type that can create [`io::Write`] instances. |
| 12 | /// |
| 13 | /// `MakeWriter` is used by [`fmt::Layer`] or [`fmt::Subscriber`] to print |
| 14 | /// formatted text representations of [`Event`]s. |
| 15 | /// |
| 16 | /// This trait is already implemented for function pointers and |
| 17 | /// immutably-borrowing closures that return an instance of [`io::Write`], such |
| 18 | /// as [`io::stdout`] and [`io::stderr`]. Additionally, it is implemented for |
| 19 | /// [`std::sync::Mutex`] when the type inside the mutex implements |
| 20 | /// [`io::Write`]. |
| 21 | /// |
| 22 | /// # Examples |
| 23 | /// |
| 24 | /// The simplest usage is to pass in a named function that returns a writer. For |
| 25 | /// example, to log all events to stderr, we could write: |
| 26 | /// ``` |
| 27 | /// let subscriber = tracing_subscriber::fmt() |
| 28 | /// .with_writer(std::io::stderr) |
| 29 | /// .finish(); |
| 30 | /// # drop(subscriber); |
| 31 | /// ``` |
| 32 | /// |
| 33 | /// Any function that returns a writer can be used: |
| 34 | /// |
| 35 | /// ``` |
| 36 | /// fn make_my_great_writer() -> impl std::io::Write { |
| 37 | /// // ... |
| 38 | /// # std::io::stdout() |
| 39 | /// } |
| 40 | /// |
| 41 | /// let subscriber = tracing_subscriber::fmt() |
| 42 | /// .with_writer(make_my_great_writer) |
| 43 | /// .finish(); |
| 44 | /// # drop(subscriber); |
| 45 | /// ``` |
| 46 | /// |
| 47 | /// A closure can be used to introduce arbitrary logic into how the writer is |
| 48 | /// created. Consider the (admittedly rather silly) example of sending every 5th |
| 49 | /// event to stderr, and all other events to stdout: |
| 50 | /// |
| 51 | /// ``` |
| 52 | /// use std::io; |
| 53 | /// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; |
| 54 | /// |
| 55 | /// let n = AtomicUsize::new(0); |
| 56 | /// let subscriber = tracing_subscriber::fmt() |
| 57 | /// .with_writer(move || -> Box<dyn io::Write> { |
| 58 | /// if n.fetch_add(1, Relaxed) % 5 == 0 { |
| 59 | /// Box::new(io::stderr()) |
| 60 | /// } else { |
| 61 | /// Box::new(io::stdout()) |
| 62 | /// } |
| 63 | /// }) |
| 64 | /// .finish(); |
| 65 | /// # drop(subscriber); |
| 66 | /// ``` |
| 67 | /// |
| 68 | /// A single instance of a type implementing [`io::Write`] may be used as a |
| 69 | /// `MakeWriter` by wrapping it in a [`Mutex`]. For example, we could |
| 70 | /// write to a file like so: |
| 71 | /// |
| 72 | /// ``` |
| 73 | /// use std::{fs::File, sync::Mutex}; |
| 74 | /// |
| 75 | /// # fn docs() -> Result<(), Box<dyn std::error::Error>> { |
| 76 | /// let log_file = File::create("my_cool_trace.log" )?; |
| 77 | /// let subscriber = tracing_subscriber::fmt() |
| 78 | /// .with_writer(Mutex::new(log_file)) |
| 79 | /// .finish(); |
| 80 | /// # drop(subscriber); |
| 81 | /// # Ok(()) |
| 82 | /// # } |
| 83 | /// ``` |
| 84 | /// |
| 85 | /// [`io::Write`]: std::io::Write |
| 86 | /// [`fmt::Layer`]: crate::fmt::Layer |
| 87 | /// [`fmt::Subscriber`]: crate::fmt::Subscriber |
| 88 | /// [`Event`]: tracing_core::event::Event |
| 89 | /// [`io::stdout`]: std::io::stdout() |
| 90 | /// [`io::stderr`]: std::io::stderr() |
| 91 | /// [`MakeWriter::make_writer_for`]: MakeWriter::make_writer_for |
| 92 | /// [`Metadata`]: tracing_core::Metadata |
| 93 | /// [levels]: tracing_core::Level |
| 94 | /// [targets]: tracing_core::Metadata::target |
| 95 | pub trait MakeWriter<'a> { |
| 96 | /// The concrete [`io::Write`] implementation returned by [`make_writer`]. |
| 97 | /// |
| 98 | /// [`io::Write`]: std::io::Write |
| 99 | /// [`make_writer`]: MakeWriter::make_writer |
| 100 | type Writer: io::Write; |
| 101 | |
| 102 | /// Returns an instance of [`Writer`]. |
| 103 | /// |
| 104 | /// # Implementer notes |
| 105 | /// |
| 106 | /// [`fmt::Layer`] or [`fmt::Subscriber`] will call this method each time an event is recorded. Ensure any state |
| 107 | /// that must be saved across writes is not lost when the [`Writer`] instance is dropped. If |
| 108 | /// creating a [`io::Write`] instance is expensive, be sure to cache it when implementing |
| 109 | /// [`MakeWriter`] to improve performance. |
| 110 | /// |
| 111 | /// [`Writer`]: MakeWriter::Writer |
| 112 | /// [`fmt::Layer`]: crate::fmt::Layer |
| 113 | /// [`fmt::Subscriber`]: crate::fmt::Subscriber |
| 114 | /// [`io::Write`]: std::io::Write |
| 115 | fn make_writer(&'a self) -> Self::Writer; |
| 116 | |
| 117 | /// Returns a [`Writer`] for writing data from the span or event described |
| 118 | /// by the provided [`Metadata`]. |
| 119 | /// |
| 120 | /// By default, this calls [`self.make_writer()`][make_writer], ignoring |
| 121 | /// the provided metadata, but implementations can override this to provide |
| 122 | /// metadata-specific behaviors. |
| 123 | /// |
| 124 | /// This method allows `MakeWriter` implementations to implement different |
| 125 | /// behaviors based on the span or event being written. The `MakeWriter` |
| 126 | /// type might return different writers based on the provided metadata, or |
| 127 | /// might write some values to the writer before or after providing it to |
| 128 | /// the caller. |
| 129 | /// |
| 130 | /// For example, we might want to write data from spans and events at the |
| 131 | /// [`ERROR`] and [`WARN`] levels to `stderr`, and data from spans or events |
| 132 | /// at lower levels to stdout: |
| 133 | /// |
| 134 | /// ``` |
| 135 | /// use std::io::{self, Stdout, Stderr, StdoutLock, StderrLock}; |
| 136 | /// use tracing_subscriber::fmt::writer::MakeWriter; |
| 137 | /// use tracing_core::{Metadata, Level}; |
| 138 | /// |
| 139 | /// pub struct MyMakeWriter { |
| 140 | /// stdout: Stdout, |
| 141 | /// stderr: Stderr, |
| 142 | /// } |
| 143 | /// |
| 144 | /// /// A lock on either stdout or stderr, depending on the verbosity level |
| 145 | /// /// of the event being written. |
| 146 | /// pub enum StdioLock<'a> { |
| 147 | /// Stdout(StdoutLock<'a>), |
| 148 | /// Stderr(StderrLock<'a>), |
| 149 | /// } |
| 150 | /// |
| 151 | /// impl<'a> io::Write for StdioLock<'a> { |
| 152 | /// fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| 153 | /// match self { |
| 154 | /// StdioLock::Stdout(lock) => lock.write(buf), |
| 155 | /// StdioLock::Stderr(lock) => lock.write(buf), |
| 156 | /// } |
| 157 | /// } |
| 158 | /// |
| 159 | /// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
| 160 | /// // ... |
| 161 | /// # match self { |
| 162 | /// # StdioLock::Stdout(lock) => lock.write_all(buf), |
| 163 | /// # StdioLock::Stderr(lock) => lock.write_all(buf), |
| 164 | /// # } |
| 165 | /// } |
| 166 | /// |
| 167 | /// fn flush(&mut self) -> io::Result<()> { |
| 168 | /// // ... |
| 169 | /// # match self { |
| 170 | /// # StdioLock::Stdout(lock) => lock.flush(), |
| 171 | /// # StdioLock::Stderr(lock) => lock.flush(), |
| 172 | /// # } |
| 173 | /// } |
| 174 | /// } |
| 175 | /// |
| 176 | /// impl<'a> MakeWriter<'a> for MyMakeWriter { |
| 177 | /// type Writer = StdioLock<'a>; |
| 178 | /// |
| 179 | /// fn make_writer(&'a self) -> Self::Writer { |
| 180 | /// // We must have an implementation of `make_writer` that makes |
| 181 | /// // a "default" writer without any configuring metadata. Let's |
| 182 | /// // just return stdout in that case. |
| 183 | /// StdioLock::Stdout(self.stdout.lock()) |
| 184 | /// } |
| 185 | /// |
| 186 | /// fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { |
| 187 | /// // Here's where we can implement our special behavior. We'll |
| 188 | /// // check if the metadata's verbosity level is WARN or ERROR, |
| 189 | /// // and return stderr in that case. |
| 190 | /// if meta.level() <= &Level::WARN { |
| 191 | /// return StdioLock::Stderr(self.stderr.lock()); |
| 192 | /// } |
| 193 | /// |
| 194 | /// // Otherwise, we'll return stdout. |
| 195 | /// StdioLock::Stdout(self.stdout.lock()) |
| 196 | /// } |
| 197 | /// } |
| 198 | /// ``` |
| 199 | /// |
| 200 | /// [`Writer`]: MakeWriter::Writer |
| 201 | /// [`Metadata`]: tracing_core::Metadata |
| 202 | /// [make_writer]: MakeWriter::make_writer |
| 203 | /// [`WARN`]: tracing_core::Level::WARN |
| 204 | /// [`ERROR`]: tracing_core::Level::ERROR |
| 205 | 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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> dynMakeWriter<'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 | |
| 679 | 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; |
| 689 | 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; |
| 696 | 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. |
| 705 | pub fn new() -> Self { |
| 706 | Self::default() |
| 707 | } |
| 708 | } |
| 709 | |
| 710 | impl io::Write for TestWriter { |
| 711 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| 712 | let out_str: Cow<'_, str> = String::from_utf8_lossy(buf); |
| 713 | print!(" {}" , out_str); |
| 714 | Ok(buf.len()) |
| 715 | } |
| 716 | |
| 717 | fn flush(&mut self) -> io::Result<()> { |
| 718 | Ok(()) |
| 719 | } |
| 720 | } |
| 721 | |
| 722 | impl<'a> MakeWriter<'a> for TestWriter { |
| 723 | type Writer = Self; |
| 724 | |
| 725 | 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 | /// |
| 735 | pub fn new<M>(make_writer: M) -> Self |
| 736 | where |
| 737 | M: for<'a> dynMakeWriter<'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 { |
| 747 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 748 | f&mut DebugTuple<'_, '_>.debug_tuple(name:"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 ] |
| 758 | fn make_writer(&'a self) -> Self::Writer { |
| 759 | self.inner.make_writer() |
| 760 | } |
| 761 | |
| 762 | #[inline ] |
| 763 | 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 | |
| 776 | fn make_writer(&'a self) -> Self::Writer { |
| 777 | let w: >::Writer = self.0.make_writer(); |
| 778 | Box::new(w) |
| 779 | } |
| 780 | |
| 781 | fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { |
| 782 | let w: >::Writer = 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 | |
| 795 | fn make_writer(&'a self) -> Self::Writer { |
| 796 | MutexGuardWriter(self.lock().expect(msg:"lock poisoned" )) |
| 797 | } |
| 798 | } |
| 799 | |
| 800 | impl<'a, W> io::Write for MutexGuardWriter<'a, W> |
| 801 | where |
| 802 | W: io::Write, |
| 803 | { |
| 804 | #[inline ] |
| 805 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| 806 | self.0.write(buf) |
| 807 | } |
| 808 | |
| 809 | #[inline ] |
| 810 | fn flush(&mut self) -> io::Result<()> { |
| 811 | self.0.flush() |
| 812 | } |
| 813 | |
| 814 | #[inline ] |
| 815 | fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { |
| 816 | self.0.write_vectored(bufs) |
| 817 | } |
| 818 | |
| 819 | #[inline ] |
| 820 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
| 821 | self.0.write_all(buf) |
| 822 | } |
| 823 | |
| 824 | #[inline ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 887 | 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 ] |
| 895 | pub fn some(t: T) -> Self { |
| 896 | EitherWriter::A(t) |
| 897 | } |
| 898 | } |
| 899 | |
| 900 | impl<T> From<Option<T>> for OptionalWriter<T> { |
| 901 | #[inline ] |
| 902 | fn from(opt: Option<T>) -> Self { |
| 903 | match opt { |
| 904 | Some(writer: T) => 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 |
| 920 | 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 ] |
| 929 | 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 ] |
| 935 | 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 |
| 953 | 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 ] |
| 962 | 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 ] |
| 968 | 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 |
| 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 ] |
| 1003 | fn make_writer(&'a self) -> Self::Writer { |
| 1004 | OptionalWriter::some(self.make.make_writer()) |
| 1005 | } |
| 1006 | |
| 1007 | #[inline ] |
| 1008 | 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 |
| 1027 | 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 ] |
| 1040 | fn make_writer(&'a self) -> Self::Writer { |
| 1041 | Tee::new(self.a.make_writer(), self.b.make_writer()) |
| 1042 | } |
| 1043 | |
| 1044 | #[inline ] |
| 1045 | 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 ] |
| 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 ] |
| 1072 | fn flush(&mut self) -> io::Result<()> { |
| 1073 | impl_tee!(self.flush()); |
| 1074 | Ok(()) |
| 1075 | } |
| 1076 | |
| 1077 | #[inline ] |
| 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 ] |
| 1084 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
| 1085 | impl_tee!(self.write_all(buf)); |
| 1086 | Ok(()) |
| 1087 | } |
| 1088 | |
| 1089 | #[inline ] |
| 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 |
| 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 ] |
| 1119 | fn make_writer(&'a self) -> Self::Writer { |
| 1120 | match self.inner.make_writer() { |
| 1121 | EitherWriter::A(writer: W) => EitherWriter::A(writer), |
| 1122 | EitherWriter::B(_) => EitherWriter::B(self.or_else.make_writer()), |
| 1123 | } |
| 1124 | } |
| 1125 | |
| 1126 | #[inline ] |
| 1127 | fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { |
| 1128 | match self.inner.make_writer_for(meta) { |
| 1129 | EitherWriter::A(writer: W) => 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 ] |
| 1142 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| 1143 | (&*self.0).write(buf) |
| 1144 | } |
| 1145 | |
| 1146 | #[inline ] |
| 1147 | fn flush(&mut self) -> io::Result<()> { |
| 1148 | (&*self.0).flush() |
| 1149 | } |
| 1150 | |
| 1151 | #[inline ] |
| 1152 | fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { |
| 1153 | (&*self.0).write_vectored(bufs) |
| 1154 | } |
| 1155 | |
| 1156 | #[inline ] |
| 1157 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
| 1158 | (&*self.0).write_all(buf) |
| 1159 | } |
| 1160 | |
| 1161 | #[inline ] |
| 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> { |
| 1171 | 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> { |
| 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 | |
| 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> { |
| 1195 | 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 | |
| 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 | |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 ] |
| 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 | |