pub struct Dispatch { /* private fields */ }
Expand description
The base dispatch logger.
This allows for formatting log records, limiting what records can be passed through, and then dispatching records to other dispatch loggers or output loggers.
Note that all methods are position-insensitive.
Dispatch::new().format(a).chain(b)
produces the exact same result
as Dispatch::new().chain(b).format(a)
. Given this, it is preferred to put
‘format’ and other modifiers before ‘chain’ for the sake of clarity.
Example usage demonstrating all features:
use std::{fs, io};
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"[{} {}] {}",
record.level(),
record.target(),
message,
))
})
.chain(
fern::Dispatch::new()
// by default only accept warn messages
.level(log::LevelFilter::Warn)
// accept info messages from the current crate too
.level_for("my_crate", log::LevelFilter::Info)
// `io::Stdout`, `io::Stderr` and `io::File` can be directly passed in.
.chain(io::stdout()),
)
.chain(
fern::Dispatch::new()
// output all messages
.level(log::LevelFilter::Trace)
// except for hyper, in that case only show info messages
.level_for("hyper", log::LevelFilter::Info)
// `log_file(x)` equates to
// `OpenOptions::new().write(true).append(true).create(true).open(x)`
.chain(fern::log_file("persistent-log.log")?)
.chain(
fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.create(true)
.open("/tmp/temp.log")?,
),
)
.chain(
fern::Dispatch::new()
.level(log::LevelFilter::Error)
.filter(|_meta_data| {
// as an example, randomly reject half of the messages
rand::random()
})
.chain(io::stderr()),
)
// and finally, set as the global logger!
.apply()?;
Implementations§
source§impl Dispatch
impl Dispatch
sourcepub fn format<F>(self, formatter: F) -> Self
pub fn format<F>(self, formatter: F) -> Self
Sets the formatter of this dispatch. The closure should accept a callback, a message and a log record, and write the resulting format to the writer.
The log record is passed for completeness, but the args()
method of
the record should be ignored, and the fmt::Arguments
given
should be used instead. record.args()
may be used to retrieve the
original log message, but in order to allow for true log
chaining, formatters should use the given message instead whenever
including the message in the output.
To avoid all allocation of intermediate results, the formatter is
“completed” by calling a callback, which then calls the rest of the
logging chain with the new formatted message. The callback object keeps
track of if it was called or not via a stack boolean as well, so if
you don’t use out.finish
the log message will continue down
the logger chain unformatted.
Example usage:
fern::Dispatch::new().format(|out, message, record| {
out.finish(format_args!(
"[{} {}] {}",
record.level(),
record.target(),
message
))
})
sourcepub fn chain<T: Into<Output>>(self, logger: T) -> Self
pub fn chain<T: Into<Output>>(self, logger: T) -> Self
Adds a child to this dispatch.
All log records which pass all filters will be formatted and then sent to all child loggers in sequence.
Note: If the child logger is also a Dispatch, and cannot accept any log
records, it will be dropped. This only happens if the child either
has no children itself, or has a minimum log level of
LevelFilter::Off
.
Example usage:
fern::Dispatch::new().chain(fern::Dispatch::new().chain(std::io::stdout()))
sourcepub fn level(self, level: LevelFilter) -> Self
pub fn level(self, level: LevelFilter) -> Self
Sets the overarching level filter for this logger. All messages not
already filtered by something set by Dispatch::level_for
will
be affected.
All messages filtered will be discarded if less severe than the given level.
Default level is LevelFilter::Trace
.
Example usage:
fern::Dispatch::new().level(log::LevelFilter::Info)
sourcepub fn level_for<T: Into<Cow<'static, str>>>(
self,
module: T,
level: LevelFilter,
) -> Self
pub fn level_for<T: Into<Cow<'static, str>>>( self, module: T, level: LevelFilter, ) -> Self
Sets a per-target log level filter. Default target for log messages is
crate_name::module_name
or
crate_name
for logs in the crate root. Targets can also be set with
info!(target: "target-name", ...)
.
For each log record fern will first try to match the most specific level_for, and then progressively more general ones until either a matching level is found, or the default level is used.
For example, a log for the target hyper::http::h1
will first test a
level_for for hyper::http::h1
, then for hyper::http
, then for
hyper
, then use the default level.
Examples:
A program wants to include a lot of debugging output, but the library “hyper” is known to work well, so debug output from it should be excluded:
fern::Dispatch::new()
.level(log::LevelFilter::Trace)
.level_for("hyper", log::LevelFilter::Info)
A program has a ton of debug output per-module, but there is so much that debugging more than one module at a time is not very useful. The command line accepts a list of modules to debug, while keeping the rest of the program at info level:
fn setup_logging<T, I>(verbose_modules: T) -> Result<(), fern::InitError>
where
I: AsRef<str>,
T: IntoIterator<Item = I>,
{
let mut config = fern::Dispatch::new().level(log::LevelFilter::Info);
for module_name in verbose_modules {
config = config.level_for(
format!("my_crate_name::{}", module_name.as_ref()),
log::LevelFilter::Debug,
);
}
config.chain(std::io::stdout()).apply()?;
Ok(())
}
sourcepub fn filter<F>(self, filter: F) -> Self
pub fn filter<F>(self, filter: F) -> Self
Adds a custom filter which can reject messages passing through this logger.
The logger will continue to process log records only if all filters
return true
.
Dispatch::level
and Dispatch::level_for
are preferred if
applicable.
Example usage:
This sends error level messages to stderr and others to stdout.
fern::Dispatch::new()
.level(log::LevelFilter::Info)
.chain(
fern::Dispatch::new()
.filter(|metadata| {
// Reject messages with the `Error` log level.
metadata.level() != log::LevelFilter::Error
})
.chain(std::io::stderr()),
)
.chain(
fern::Dispatch::new()
.level(log::LevelFilter::Error)
.chain(std::io::stdout()),
)
Builds this dispatch and stores it in a clonable structure containing
an Arc
.
Once “shared”, the dispatch can be used as an output for multiple other dispatch loggers.
Example usage:
This separates info and warn messages, sending info to stdout + a log file, and warn to stderr + the same log file. Shared is used so the program only opens “file.log” once.
let file_out = fern::Dispatch::new()
.chain(fern::log_file("file.log")?)
.into_shared();
let info_out = fern::Dispatch::new()
.level(log::LevelFilter::Debug)
.filter(|metadata|
// keep only info and debug (reject warn and error)
metadata.level() <= log::Level::Info)
.chain(std::io::stdout())
.chain(file_out.clone());
let warn_out = fern::Dispatch::new()
.level(log::LevelFilter::Warn)
.chain(std::io::stderr())
.chain(file_out);
fern::Dispatch::new()
.chain(info_out)
.chain(warn_out)
.apply();
sourcepub fn into_log(self) -> (LevelFilter, Box<dyn Log>)
pub fn into_log(self) -> (LevelFilter, Box<dyn Log>)
Builds this logger into a Box<log::Log>
and calculates the minimum
log level needed to have any effect.
While this method is exposed publicly, Dispatch::apply
is typically
used instead.
The returned LevelFilter is a calculation for all level filters of this logger and child loggers, and is the minimum log level needed to for a record to have any chance of passing through this logger.
Example usage:
let (min_level, log) = fern::Dispatch::new()
.level(log::LevelFilter::Info)
.chain(std::io::stdout())
.into_log();
assert_eq!(min_level, log::LevelFilter::Info);