Logging in Rust

Jack Chan
Nerd For Tech
Published in
3 min readApr 12, 2021

In this article, I want to talk about logging in Rust. With some background information, I will walk you through two logging libraries: env_logger and log4rs. In the end, I will share my recommendation and the github for snippets.

Background

The log create is the de-facto logging API in Rust. There are five log levels: error (highest priority), warn, info, debug, and trace (lowest priority). To log a message, you use the corresponding logging marcos: error!, warn!, etc. These marcos behave like println! and supports the syntax of format!. That is, {} calls display on an object, {:?} calls debug on an object, and {:#?} pretty-print the debug formatting. (We will see some examples later.)

One important note is that the log crate only provides the API, not implementations. You must pick a library that implements a logger. So, what is the most commonly used logging library in Rust?

Libraries

env_logger

By far, the most commonly used logging library in Rust is the env_logger crate. On crates.io, env_logger has totalled more than 23 million downloads. With one line of configuration in code, env_logger::init(), this simple library writes all your log to stderr (configurable to stdout). As its name suggests, the env_logger takes an environment variable RUST_LOG to configure its log level. For example, RUST_LOG=debug cargo run --bin env_logger logs everything emitted by the env_logger binary at or above debug level, i.e. all but trace.

This simple rust program ties it together:

use log::debug;
use log::error;
use log::info;
use log::warn;
fn main() {
env_logger::init();
debug!("Mary has a little lamb");
error!("{}", "Its fleece was white as snow");
info!("{:?}", "And every where that Mary went");
warn!("{:#?}", "The lamb was sure to go");
}

Here is the output:

In addition, there are a few other libraries that build on top of env_logger. For examples, the pretty_env_logger and json_env_logger crates. You may find them useful, if you want to pretty print your log or log your messages as json instead of text.

log4rs

The log4rs crate is modeled after Java’s log4j libraries. To start logging, you must create an appender, which tells where the logs go: console, file, or syslog. In a production system, you almost always want to use a rolling file appender. A rolling file appender generates a new log file based on time, say every hour. This naturally organizes your log files by time and let you skips any period that is uninteresting, say, when you only want to look at things that happened at 7pm on 15th Apr.

Then, you want to configure how many log files you want to keep in your system, usually by storage size (keep 300GB) or by retention time (keep 30 days).

This rust program ties it together: (as you can see, the configuration is more verbose)

use log::error;
use log::info;
use log::warn;
use log::{debug, LevelFilter};
use log4rs::append::console::ConsoleAppender;
use log4rs::config::{Appender, Root};
use log4rs::Config;
fn main() {
let stdout = ConsoleAppender::builder().build();
let config = Config::builder()
.appender(Appender::builder().build("stdout", Box::new(stdout)))
.build(Root::builder().appender("stdout").build(LevelFilter::Trace))
.unwrap();
let _handle = log4rs::init_config(config).unwrap(); debug!("Mary has a little lamb");
error!("{}", "Its fleece was white as snow");
info!("{:?}", "And every where that Mary went");
warn!("{:#?}", "The lamb was sure to go");
}

Here is the output:

Conclusion

My recommendation would be to start with something simple — env_logger. If you are getting more serious with your side projects, switch to log4rs for better trouble shooting capabilities.

I have put together these examples on github under rust-logging-samples. Feel free to send me pull requests for add more libraries. You can also follow me on twitter if you are interested in this topic.

--

--

Jack Chan
Nerd For Tech

The Woodpecker. Make logs ingestion cheap and query fast.