Configure Logging
Recipe | Crates | Categories |
---|---|---|
Enable log levels per module | ||
Use a custom environment variable to set up logging | ||
Include a timestamp in log messages | ||
Log messages to a custom location |
Enable log levels per module
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(); }
The RUST_LOG
environment variable controls env-logger
⮳ output. Module declarations take comma separated entries formatted like path::to::module=log_level
. Run the test
application as follows:
RUST_LOG="warn,test::foo=info,test::foo::bar=debug" test
Sets the default log::Level
⮳ to warn
, module foo
and module foo::bar
to info
and debug
.
WARN:test: [root] warn
WARN:test::foo: [foo] warn
INFO:test::foo: [foo] info
WARN:test::foo::bar: [bar] warn
INFO:test::foo::bar: [bar] info
DEBUG:test::foo::bar: [bar] debug
Use a custom environment variable to set up logging
env_logger::Builder
⮳ configures logging.
env_logger::Builder::parse
⮳ parses MY_APP_LOG
environment variable contents in the form of RUST_LOG
⮳ syntax.
Then, env_logger::Builder::init
⮳ initializes the logger.
All these steps are normally done internally by env_logger::init
⮳.
fn main() { init_logger(); log::info!("informational message"); log::warn!("warning message"); log::error!("this is an error {}", "message"); if log::log_enabled!(log::Level::Info) { let x = 3 * 4; // "Expensive" computation log::trace!("the answer was: {}", x); } } //#[cfg(not(test))] fn init_logger() { // env_logger is a simple logger that can be configured via environment // variables. Example: RUST_LOG=info ./app // Typically you would use: // env_logger::init(); // Initialise a logger with filter level Off, // then override the log filter from an environment variable called // MY_APP_LOG: env_logger::Builder::new() .filter_level(log::LevelFilter::Off) .parse_env("MY_APP_LOG") .init(); // Alternatively, `Env` lets us tweak what the environment // variables to read are and what the default // value is if they're missing // let env = env_logger::Env::default() // // Specify an environment variable to read the filter from. // // If the variable is not set, the default value will be used. // .filter_or("MY_APP_LOG", "trace") // .write_style_or("MY_APP_LOG_STYLE", "always"); // env_logger::init_from_env(env); }
Include a timestamp in log messages
Creates a custom logger configuration with env_logger::Builder
⮳
Each log entry calls chrono::offset::Local::now
⮳ to get the current chrono::DateTime
⮳ in local timezone and uses chrono::DateTime::format
⮳ with chrono::format::strftime
⮳ to format a timestamp used in the final log.
The example calls env_logger::Builder::format
⮳ to set a closure which formats each message text with timestamp, log::Record::level
⮳ and body (log::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
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 anyhow::Result; use log::LevelFilter; use log4rs::append::file::FileAppender; use log4rs::config::Appender; use log4rs::config::Config; use log4rs::config::Root; use log4rs::encode::pattern::PatternEncoder; fn main() -> Result<()> { let logfile = FileAppender::builder() .encoder(Box::new(PatternEncoder::new("{l} - {m}\n"))) .build("temp/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(()) }