Logging in Rust

Here’s the translation of the Go logging example to Rust, formatted in Markdown suitable for Hugo:

Rust provides several options for logging, including the standard library’s log crate and more feature-rich third-party crates like env_logger and slog. In this example, we’ll use both the log crate and slog for structured logging.

First, let’s add the necessary dependencies to your Cargo.toml:

[dependencies]
log = "0.4"
env_logger = "0.10"
slog = "2.7"
slog-json = "2.6"
slog-term = "2.9"

Now, let’s look at the Rust code:

use log::{info, set_logger, set_max_level, LevelFilter, Log, Metadata, Record};
use slog::{Drain, Logger, o};
use slog_json::Json;
use std::io::Write;

struct SimpleLogger;

impl Log for SimpleLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= log::Level::Info
    }

    fn log(&self, record: &Record) {
        if self.enabled(record.metadata()) {
            println!("{} - {}", record.level(), record.args());
        }
    }

    fn flush(&self) {}
}

static LOGGER: SimpleLogger = SimpleLogger;

fn main() {
    // Set up the simple logger
    set_logger(&LOGGER).unwrap();
    set_max_level(LevelFilter::Info);

    // Using the simple logger
    info!("standard logger");

    // Logging with timestamp
    env_logger::Builder::from_default_env()
        .format(|buf, record| {
            writeln!(buf,
                "{} [{}] - {}",
                chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.6f"),
                record.level(),
                record.args()
            )
        })
        .init();

    info!("with microsecond precision");

    // Logging with file and line information
    log::logger().flush();
    env_logger::builder()
        .format(|buf, record| {
            writeln!(buf,
                "{} {}:{} - {}",
                record.level(),
                record.file().unwrap_or("unknown"),
                record.line().unwrap_or(0),
                record.args()
            )
        })
        .init();

    info!("with file/line");

    // Creating a custom logger with slog
    let plain = slog_term::PlainSyncDecorator::new(std::io::stdout());
    let logger = Logger::root(
        slog_term::FullFormat::new(plain).build().fuse(),
        o!("version" => env!("CARGO_PKG_VERSION"))
    );

    slog::info!(logger, "from custom logger"; "key" => "val");

    // Logging to a string buffer
    let mut buf = Vec::new();
    let writer = std::io::Cursor::new(&mut buf);
    let json = Json::default(writer).build().fuse();
    let buffer_logger = Logger::root(json, o!());

    slog::info!(buffer_logger, "hello"; "to" => "buffer");

    println!("from buffer: {}", String::from_utf8_lossy(&buf));

    // Structured logging with slog-json
    let json_drain = Json::new(std::io::stderr())
        .set_pretty(false)
        .build()
        .fuse();
    let json_logger = Logger::root(json_drain, o!());

    slog::info!(json_logger, "hi there");
    slog::info!(json_logger, "hello again"; "key" => "val", "age" => 25);
}

This Rust code demonstrates various logging techniques:

  1. We start by setting up a simple logger using the log crate.

  2. We then use env_logger to add timestamps to our log messages.

  3. Next, we show how to include file and line information in log messages.

  4. We create a custom logger using slog with a terminal output.

  5. We demonstrate logging to a buffer.

  6. Finally, we use slog-json for structured logging in JSON format.

To run the program:

$ cargo run

Sample output (the date and time emitted will depend on when the example ran):

INFO - standard logger
2023-08-22 10:45:16.904141 [INFO] - with microsecond precision
INFO src/main.rs:67 - with file/line
Aug 22 10:45:16.904166.INFO from custom logger version="0.1.0" key="val"
from buffer: {"msg":"hello","to":"buffer","level":"info","ts":"2023-08-22T10:45:16.904178Z"}
{"msg":"hi there","level":"info","ts":"2023-08-22T10:45:16Z"}
{"msg":"hello again","key":"val","age":25,"level":"info","ts":"2023-08-22T10:45:16Z"}

This example showcases different logging methods in Rust, from basic logging to structured logging with JSON output. The concepts are similar to those in other languages, but the implementation details are specific to Rust and its ecosystem.