Configure Logging

Enable log levels per module

log-badge env_logger-badge cat-debugging-badge

Creates two modules foo and nested foo::bar with logging directives controlled separately with RUST_LOG environmental variable.

mod foo {
    mod bar {
        pub fn run() {
            log::warn!("[bar] warn");
            log::info!("[bar] info");
            log::debug!("[bar] debug");
        }
    }

    pub fn run() {
        log::warn!("[foo] warn");
        log::info!("[foo] info");
        log::debug!("[foo] debug");
        bar::run();
    }
}

fn main() {
    env_logger::init();
    log::warn!("[root] warn");
    log::info!("[root] info");
    log::debug!("[root] debug");
    foo::run();
}

RUST_LOG environment variable controls env_logger output. Module declarations take comma separated entries formatted like path::to::module=log_level. From the cloned Rust Cookbook repository, run the example as follows:

RUST_LOG="warn,log_mod::foo=info,log_mod::foo::bar=debug" cargo run --example log-mod

This sets the default log::Level to warn for the entire application, module foo in the application to info, and sub-module foo::bar to debug.

Note that because the example filename has a minus sign ('-') in it, which is converted to and underscore ('_') because module names cannot have a minus sign.

[2022-05-21T12:30:34Z WARN  log_mod] [root] warn
[2022-05-21T12:30:34Z WARN  log_mod::foo] [foo] warn
[2022-05-21T12:30:34Z INFO  log_mod::foo] [foo] info
[2022-05-21T12:30:34Z WARN  log_mod::foo::bar] [bar] warn
[2022-05-21T12:30:34Z INFO  log_mod::foo::bar] [bar] info
[2022-05-21T12:30:34Z DEBUG log_mod::foo::bar] [bar] debug

Use a custom environment variable to set up logging

log-badge env_logger-badge cat-debugging-badge

Builder configures logging.

[Builder::parse] parses MY_APP_LOG environment variable contents in the form of RUST_LOG syntax. Then, Builder::init initializes the logger. All these steps are normally done internally by env_logger::init.

use log::{error, info, warn};
use env_logger::Builder;

fn main() {
    Builder::new()
        .parse_env("MY_APP_LOG")
        .init();

    info!("informational message");
    warn!("warning message");
    error!("this is an error {}", "message");
}

Without setting MY_APP_LOG, the output of the example will be something like:

$ cargo run --quiet --example log-env-variable
[2022-04-17T00:52:42Z ERROR log_env_variable] this is an error message

When setting the environment variable MY_APP_LOG with a different log level, more will be printed:

$ MY_APP_LOG=warn cargo run --quiet --example log-env-variable
[2022-04-17T00:56:51Z WARN  log_env_variable] warning message
[2022-04-17T00:56:51Z ERROR log_env_variable] this is an error message

Include timestamp in log messages

log-badge env_logger-badge chrono-badge cat-debugging-badge

Creates a custom logger configuration with Builder. Each log entry calls Local::now to get the current DateTime in local timezone and uses DateTime::format with strftime::specifiers to format a timestamp used in the final log.

The example calls Builder::format to set a closure which formats each message text with timestamp, Record::level and body (Record::args).

use std::io::Write;
use chrono::Local;
use env_logger::Builder;
use log::LevelFilter;

fn main() {
    Builder::new()
        .format(|buf, record| {
            writeln!(buf,
                "{} [{}] - {}",
                Local::now().format("%Y-%m-%dT%H:%M:%S"),
                record.level(),
                record.args()
            )
        })
        .filter(None, LevelFilter::Info)
        .init();

    log::warn!("warn");
    log::info!("info");
    log::debug!("debug");
}

stderr output will contain

2017-05-22T21:57:06 [WARN] - warn
2017-05-22T21:57:06 [INFO] - info

Log messages to a custom location

log-badge log4rs-badge cat-debugging-badge

log4rs configures log output to a custom location. log4rs can use either an external YAML file or a builder configuration.

Create the log configuration with log4rs::append::file::FileAppender. An appender defines the logging destination. The configuration continues with encoding using a custom pattern from log4rs::encode::pattern. Assigns the configuration to log4rs::config::Config and sets the default log::LevelFilter.

use std::error::Error;

use log::LevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::encode::pattern::PatternEncoder;
use log4rs::config::{Appender, Config, Root};

fn main() -> Result<(), Box<dyn Error>> {
    let logfile = FileAppender::builder()
        .encoder(Box::new(PatternEncoder::new("{l} - {m}\n")))
        .build("log/output.log")?;

    let config = Config::builder()
        .appender(Appender::builder().build("logfile", Box::new(logfile)))
        .build(Root::builder()
                   .appender("logfile")
                   .build(LevelFilter::Info))?;

    log4rs::init_config(config)?;

    log::info!("Hello, world!");

    Ok(())
}