Expand description
Efficient, configurable logging in Rust.
Depending on fern
Ensure you require both fern and log in your project’s Cargo.toml
:
[dependencies]
log = "0.4"
fern = "0.5"
Then declare both in main.rs
or lib.rs
:
#[macro_use]
extern crate log;
extern crate fern;
Example setup
With fern, all logger configuration is done via builder-like methods on
instances of the Dispatch
structure.
Here’s an example logger which formats messages, and sends everything Debug and above to both stdout and an output.log file:
extern crate fern;
#[macro_use]
extern crate log;
extern crate chrono;
fn setup_logger() -> Result<(), fern::InitError> {
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}][{}] {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
record.target(),
record.level(),
message
))
})
.level(log::LevelFilter::Debug)
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?)
.apply()?;
Ok(())
}
Let’s unwrap this:
Create an empty configuration.
Add a formatter to the logger, modifying all messages sent through.
Get the current time in the local timezone using the chrono
library.
See the time-and-date docs.
.format("[%Y-%m-%d][%H:%M:%S]")
Use chrono’s lazy format specifier to turn the time into a readable string.
Call the fern::FormattingCallback
to submit the formatted message.
This roundabout way is slightly odd, but it allows for very fast logging. No string allocation required!
format_args!()
has the same format as println!()
(and every other
std::fmt
-based macro).
.level(log::LevelFilter::Debug)
Set the minimum level needed to output to Debug
.
Add a child to the logger. All messages which pass the filters will be sent to stdout.
Dispatch::chain
accepts Stdout
, Stderr
, File
and other
Dispatch
instances.
Add a second child sending messages to the file “output.log”.
See fern::log_file()
for more info on file output.
Consume the configuration and instantiate it as the current runtime global logger.
This will fail if and only if .apply()
or equivalent form another crate
has already been used this runtime.
Since the binary crate is the only one ever setting up logging, the
apply
result can be reasonably unwrapped: it’s a bug if any crate is
calling this method more than once.
The final output will look like:
[2017-01-20][12:55:04][crate-name][INFO] Hello, world!
[2017-01-20][12:56:21][crate-name][WARN] Ahhh!
[2017-01-20][12:58:00][crate-name][DEBUG] Something less important happened.
Logging
Once the logger has been set, it will pick up all logging calls from your crate and all libraries you depend on.
fern::Dispatch::new()
// ...
.apply()?;
trace!("Trace message");
debug!("Debug message");
info!("Info message");
warn!("Warning message");
error!("Error message");
More
The Dispatch
documentation has example usages of each method, and the
full example program might be useful for using fern in a larger
application context.
See the colors module for examples using ANSI terminal coloring.
See the syslog module for examples outputting to the unix syslog, or the syslog full example program for a more realistic sample.
See the meta module for information on getting logging-within-logging working correctly.
Modules
Display
or Debug
implementations.fern
with the syslog
crate.