Logging for Rust: Best Solutions
Logging is one of the key components of any production application. The Rust ecosystem has a mature stack of tools that allows flexible configuration of log collection, formatting, and output. In this article, we will cover the main libraries, their capabilities, and usage examples.
1. The log Crate — Abstraction over Logging
The log library is the foundation of the entire logging system in Rust. It provides a facade — a set of traits and macros that do not depend on a specific backend. You write the code once, and configure log output through an external logger.
Main macros:
error!— critical errorswarn!— warningsinfo!— informational messagesdebug!— debug informationtrace!— detailed tracing
Usage example:
use log::{info, warn, error};
fn main() { // A logger must be initialized before use // env_logger::init(); // or another backend info!("Application started"); warn!("Disk is 90% full"); error!("Database connection error: {:?}", err);}2. env_logger — Simplicity and Flexibility
The most popular backend for log. Configuration is done via the RUST_LOG environment variable. This is an ideal choice for small projects and utilities.
Installation:
[dependencies]log = "0.4"env_logger = "0.11"Example with module filtering:
use log::info;
fn main() { env_logger::init(); // Run with: RUST_LOG=my_crate=info cargo run info!("This message will only appear for my_crate"); // RUST_LOG=warn — shows only warn and error // RUST_LOG=debug — shows everything, including debug}The RUST_LOG variable supports complex filters:
RUST_LOG=info— level info and aboveRUST_LOG=my_crate=debug,other_crate=warn— different levels for different cratesRUST_LOG=off— disable logging
3. log4rs — Configuration via YAML
If you need advanced control — multiple appenders (file, console, syslog), log rotation, formatting — choose log4rs. It is inspired by Java Log4j.
Example log4rs.yaml configuration:
refresh_rate: 30 seconds
appenders: stdout: kind: console encoder: pattern: "{d(%Y-%m-%d %H:%M:%S)} [{l}] {m}{n}" file: kind: file path: "app.log" encoder: pattern: "{d} {l} {M} - {m}{n}"
root: level: info appenders: - stdout
loggers: app::db: level: debug appenders: - file additive: falseInitialization in code:
use log4rs;
fn main() { log4rs::init_file("log4rs.yaml", Default::default()).unwrap(); log::info!("Logging configured via YAML"); log::debug!("This message will only go to the file");}Key features of log4rs:
- Log rotation by size or time
- Different appenders for different modules
- Automatic configuration reload
- JSON format support
4. tracing — Modern Approach
The tracing library from the Tokio team is not just logging, but a whole system for application diagnostics. It supports structured events and spans, which is especially useful in asynchronous applications.
Example with spans:
use tracing::{in