| //! Abstractions for creating [`io::Write`] instances. |
| //! |
| //! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html |
| |
| use std::io; |
| |
| /// A type that can create [`io::Write`] instances. |
| /// |
| /// `MakeWriter` is used by [`FmtSubscriber`] to print formatted text representations of |
| /// [`Event`]s. |
| /// |
| /// This trait is already implemented for function pointers and immutably-borrowing closures that |
| /// return an instance of [`io::Write`], such as [`io::stdout`] and [`io::stderr`]. |
| /// |
| /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html |
| /// [`FmtSubscriber`]: ../struct.Subscriber.html |
| /// [`Event`]: https://docs.rs/tracing-core/0.1.5/tracing_core/event/struct.Event.html |
| /// [`io::stdout`]: https://doc.rust-lang.org/std/io/fn.stdout.html |
| /// [`io::stderr`]: https://doc.rust-lang.org/std/io/fn.stderr.html |
| pub trait MakeWriter { |
| /// The concrete [`io::Write`] implementation returned by [`make_writer`]. |
| /// |
| /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html |
| /// [`make_writer`]: #tymethod.make_writer |
| type Writer: io::Write; |
| |
| /// Returns an instance of [`Writer`]. |
| /// |
| /// # Implementer notes |
| /// |
| /// [`FmtSubscriber`] will call this method each time an event is recorded. Ensure any state |
| /// that must be saved across writes is not lost when the [`Writer`] instance is dropped. If |
| /// creating a [`io::Write`] instance is expensive, be sure to cache it when implementing |
| /// [`MakeWriter`] to improve performance. |
| /// |
| /// [`Writer`]: #associatedtype.Writer |
| /// [`FmtSubscriber`]: ../struct.Subscriber.html |
| /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html |
| /// [`MakeWriter`]: trait.MakeWriter.html |
| fn make_writer(&self) -> Self::Writer; |
| } |
| |
| impl<F, W> MakeWriter for F |
| where |
| F: Fn() -> W, |
| W: io::Write, |
| { |
| type Writer = W; |
| |
| fn make_writer(&self) -> Self::Writer { |
| (self)() |
| } |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::MakeWriter; |
| use crate::fmt::format::Format; |
| use crate::fmt::test::{MockMakeWriter, MockWriter}; |
| use crate::fmt::Subscriber; |
| use lazy_static::lazy_static; |
| use std::sync::Mutex; |
| use tracing::error; |
| use tracing_core::dispatcher::{self, Dispatch}; |
| |
| fn test_writer<T>(make_writer: T, msg: &str, buf: &Mutex<Vec<u8>>) |
| where |
| T: MakeWriter + Send + Sync + 'static, |
| { |
| let subscriber = { |
| #[cfg(feature = "ansi")] |
| { |
| let f = Format::default().without_time().with_ansi(false); |
| Subscriber::builder() |
| .event_format(f) |
| .with_writer(make_writer) |
| .finish() |
| } |
| #[cfg(not(feature = "ansi"))] |
| { |
| let f = Format::default().without_time(); |
| Subscriber::builder() |
| .event_format(f) |
| .with_writer(make_writer) |
| .finish() |
| } |
| }; |
| let dispatch = Dispatch::from(subscriber); |
| |
| dispatcher::with_default(&dispatch, || { |
| error!("{}", msg); |
| }); |
| |
| let expected = format!("ERROR {}: {}\n", module_path!(), msg); |
| let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap(); |
| assert!(actual.contains(expected.as_str())); |
| } |
| |
| #[test] |
| fn custom_writer_closure() { |
| lazy_static! { |
| static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]); |
| } |
| |
| let make_writer = || MockWriter::new(&BUF); |
| let msg = "my custom writer closure error"; |
| test_writer(make_writer, msg, &BUF); |
| } |
| |
| #[test] |
| fn custom_writer_struct() { |
| lazy_static! { |
| static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]); |
| } |
| |
| let make_writer = MockMakeWriter::new(&BUF); |
| let msg = "my custom writer struct error"; |
| test_writer(make_writer, msg, &BUF); |
| } |
| } |