Rust:
Logging

How to:

Let’s set up a basic logging scenario in Rust using the log crate, which provides a logging facade, and env_logger, a logging implementation for the log crate. First, add them to your Cargo.toml:

[dependencies]
log = "0.4.14"
env_logger = "0.9.0"

Now, set up and initialize the logger in your main.rs:

use log::{info, warn};

fn main() {
    env_logger::init();

    info!("This is an info message.");
    warn!("This is a warning message.");
}

Run your app with RUST_LOG=info cargo run, and you’ll see the output:

INFO: This is an info message.
WARN: This is a warning message.

Play around with the RUST_LOG environment variable by setting it to error, warn, info, debug, or trace to control the verbosity of your logs.

Deep Dive

The concept of logging isn’t anything new; it has been around since the early days of computing. Before logging was common in software, developers relied on primitive methods such as print statements or debugger tools to trace program execution. As programs grew in complexity, so too did the need for structured approaches to logging.

In Rust, the log crate abstracts away logging implementation details, allowing developers to plug in different logging backends. While env_logger is a common choice, there are alternatives like fern, slog, or tracing each with their own set of features and configuration options.

Some considerations when implementing logging include:

  1. Log Levels: Controlling verbosity is key. Rust’s log crate defines several log levels: error, warn, info, debug, and trace, in decreasing order of severity.

  2. Performance: Logging can impact performance. It’s critical to use it judiciously, making sure to avoid logging in performance-critical paths or excessively verbose logs in production.

  3. Structured Logging: Modern best practices involve structured logging, where logs are written in a machine-readable format like JSON. Libraries like slog allow for structured logging in Rust, which can be indexed and queried using log management systems like ELK Stack or Splunk.

  4. Asynchronous Logging: To minimize impact on the main application, logging can be done asynchronously. This is often achieved by having the logging library write to an in-memory queue, and a separate thread processes the queue and writes logs to the destination.

  5. Configuration: Many logging frameworks support configuration through environment variables, configuration files, and/or code. This flexibility is key for fine-tuning output in different environments (development, staging, production).

See Also