fern

Struct Dispatch

source
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

source

pub fn new() -> Self

Creates a dispatch, which will initially do nothing.

source

pub fn format<F>(self, formatter: F) -> Self
where F: Fn(FormatCallback<'_>, &Arguments<'_>, &Record<'_>) + Sync + Send + 'static,

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
    ))
})
source

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()))
source

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)
source

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(())
}
source

pub fn filter<F>(self, filter: F) -> Self
where F: Fn(&Metadata<'_>) -> bool + Send + Sync + 'static,

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()),
    )
source

pub fn into_shared(self) -> SharedDispatch

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();
source

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);
source

pub fn apply(self) -> Result<(), SetLoggerError>

Builds this logger and instantiates it as the global log logger.

§Errors:

This function will return an error if a global logger has already been set to a previous logger.

Trait Implementations§

source§

impl Debug for Dispatch

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Dispatch

source§

fn default() -> Self

Returns a logger configuration that does nothing with log records.

Equivalent to Dispatch::new.

source§

impl From<Dispatch> for Output

source§

fn from(log: Dispatch) -> Self

Creates an output logger forwarding all messages to the dispatch.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.