blob: 303d6f0bf523af6219f6c8550053797018604762 [file] [log] [blame]
//! 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);
}
}