Trait tracing_subscriber::fmt::MakeWriter
source · pub trait MakeWriter<'a> {
type Writer: Write;
// Required method
fn make_writer(&'a self) -> Self::Writer;
// Provided method
fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer { ... }
}
Expand description
A type that can create io::Write
instances.
MakeWriter
is used by fmt::Layer
or fmt::Subscriber
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
. Additionally, it is implemented for
std::sync::Mutex
when the type inside the mutex implements
io::Write
.
Examples
The simplest usage is to pass in a named function that returns a writer. For example, to log all events to stderr, we could write:
let subscriber = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.finish();
Any function that returns a writer can be used:
fn make_my_great_writer() -> impl std::io::Write {
// ...
}
let subscriber = tracing_subscriber::fmt()
.with_writer(make_my_great_writer)
.finish();
A closure can be used to introduce arbitrary logic into how the writer is created. Consider the (admittedly rather silly) example of sending every 5th event to stderr, and all other events to stdout:
use std::io;
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
let n = AtomicUsize::new(0);
let subscriber = tracing_subscriber::fmt()
.with_writer(move || -> Box<dyn io::Write> {
if n.fetch_add(1, Relaxed) % 5 == 0 {
Box::new(io::stderr())
} else {
Box::new(io::stdout())
}
})
.finish();
A single instance of a type implementing io::Write
may be used as a
MakeWriter
by wrapping it in a Mutex
. For example, we could
write to a file like so:
use std::{fs::File, sync::Mutex};
let log_file = File::create("my_cool_trace.log")?;
let subscriber = tracing_subscriber::fmt()
.with_writer(Mutex::new(log_file))
.finish();
Required Associated Types§
sourcetype Writer: Write
type Writer: Write
The concrete io::Write
implementation returned by make_writer
.
Required Methods§
sourcefn make_writer(&'a self) -> Self::Writer
fn make_writer(&'a self) -> Self::Writer
Returns an instance of Writer
.
Implementer notes
fmt::Layer
or fmt::Subscriber
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.
Provided Methods§
sourcefn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer
fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer
Returns a Writer
for writing data from the span or event described
by the provided Metadata
.
By default, this calls self.make_writer()
, ignoring
the provided metadata, but implementations can override this to provide
metadata-specific behaviors.
This method allows MakeWriter
implementations to implement different
behaviors based on the span or event being written. The MakeWriter
type might return different writers based on the provided metadata, or
might write some values to the writer before or after providing it to
the caller.
For example, we might want to write data from spans and events at the
ERROR
and WARN
levels to stderr
, and data from spans or events
at lower levels to stdout:
use std::io::{self, Stdout, Stderr, StdoutLock, StderrLock};
use tracing_subscriber::fmt::writer::MakeWriter;
use tracing_core::{Metadata, Level};
pub struct MyMakeWriter {
stdout: Stdout,
stderr: Stderr,
}
/// A lock on either stdout or stderr, depending on the verbosity level
/// of the event being written.
pub enum StdioLock<'a> {
Stdout(StdoutLock<'a>),
Stderr(StderrLock<'a>),
}
impl<'a> io::Write for StdioLock<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
StdioLock::Stdout(lock) => lock.write(buf),
StdioLock::Stderr(lock) => lock.write(buf),
}
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
// ...
}
fn flush(&mut self) -> io::Result<()> {
// ...
}
}
impl<'a> MakeWriter<'a> for MyMakeWriter {
type Writer = StdioLock<'a>;
fn make_writer(&'a self) -> Self::Writer {
// We must have an implementation of `make_writer` that makes
// a "default" writer without any configuring metadata. Let's
// just return stdout in that case.
StdioLock::Stdout(self.stdout.lock())
}
fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
// Here's where we can implement our special behavior. We'll
// check if the metadata's verbosity level is WARN or ERROR,
// and return stderr in that case.
if meta.level() <= &Level::WARN {
return StdioLock::Stderr(self.stderr.lock());
}
// Otherwise, we'll return stdout.
StdioLock::Stdout(self.stdout.lock())
}
}