Simple structured logging.
use lumbermill::{info, Logger}
fn main() {
// Initialize the logger early
Logger::default().init();
// Log a single line
info!("Incoming connection from {:?} {}", addr, port);
// Attach key-value pairs with the log message
info!(addr.ip = ip, addr.port = port, "Listening on {}", port);
// Or use the shorthand if the key's name is the same as the variable:
info!(addr.ip, port, "Listening on {}", port);
// Attach key-value pairs with the log message, formatting them using their
// `Debug` trait (useful when variables do not implement `Display`)
info!(addr.ip = ?ip, addr.port = port, "Listening on {}", port);
// Or in the shorthand notation:
info!(?addr.ip, port, "Listening on {}", port);
}
The trace!
, debug!
, info!
, warn!
, error!
& fatal!
are heavily inspired
by tracing
's macros because they're good.
The default logger prints pretty logs to stdout
only, but you can configure the Logger
to behave differently:
use lumbermill::{LogFormat, LogLevel, RollInterval};
Logger::builder()
.format(LogFormat::Compact) // Set the format of logs
.level(LogLevel::Info) // Set the minimum log level
.stdout(false) // Stop printing to stdout
.file("./logs", RollInterval::Daily) // Log to a directory; one file per day
// Shorthands
.pretty() // .format(LogFormat::Pretty)
.compact() // .format(LogFormat::Compact)
.pretty_structured() // .format(LogFormat::PrettyStructured)
.json() // .format(LogFormat::Json)
// Remember to call `init` after configuration!
.init();
You can have different active configurations in different scenarios by using the
#![cfg]
macro:
// Pretty logs on stdout during development
#[cfg(debug_assertions)]
Logger::default().level(LogLevel::Trace).pretty().init();
// Compact logs on rolling files in production
#[cfg(not(debug_assertions))]
{
let dir = "./logs";
std::fs::create_dir_all(dir)?;
Logger::default()
.level(LogLevel::Info)
.compact()
.file(dir, lumbermill::RollInterval::Hourly)
.init();
}
Examples are a good entrypoint to learn about the library. Run them this way:
$ cargo run --example 01-defaults # Or replace this wil a different example's name
Docs usually go into more detail once you get the hang of things.
The tracing
ecosystem is awesome, but it's also overkill for a lot of apps who
only need structured logging and not a distributed tracing solution. The log
crate
is the obvious alternative, but its kv
module is a work-in-progress.
You are also unable to log key-value pairs that do not implement Display
in
a incovenient way.
This crate is a stop-gap till log::kv
stabilizes. It marries tracing
's awesome
event!
macro to log
's simplicity. The plan is to eventually drop the custom
macros in this crate and integrate with log
directly.
This crate currently requires at least Rust 1.70