kvlog: High-performance structured binary logging for Rust.
kvlog provides macros for emitting structured log messages with key-value pairs, optimized for high throughput and fast compile times. Log messages are encoded in a compact binary format with nanosecond-resolution timestamps.
Usage
Add to your Cargo.toml:
[]
= "0.1"
Basic Logging
// Initialize the collector
let _guard = spawn_collector_from_env;
// Simple message
info!;
// With key-value pairs
let status = 200u16;
let object_id = 42u64;
info!;
// Explicit key names
info!;
Log Levels
debug!- Development-only logging (requiresdebugfeature)info!- Useful context about application statewarn!- Expected but potentially problematic conditionserror!- Unexpected failures requiring intervention
Format Specifiers
let err = "connection refused";
let config = vec!;
// %expr uses Display formatting
error!;
// ?expr uses Debug formatting
warn!;
Conditional Fields
let response_length: = Some;
info!;
Conditional Logging
Use an EnvGuard to enable a log site from an environment variable:
static AUDIO_LOGS: EnvGuard =
new;
info!;
The environment variable must be present to enable the guard. The exact value
0 disables logging; any other value enables it. The result is cached after
the first check, and EnvGuard::set can override it explicitly. Declare guards
as static, not const, so that cached and explicitly set values persist.
The expression before the semicolon has its is_enabled() method called. When
it returns false, the logger is not accessed and the rest of the log expression
is not evaluated. This syntax is supported by debug!, info!, warn!, and
error!.
Timer
let timer = start;
// ... do some work ...
info!;
Spans
kvlog supports hierarchical spans for distributed tracing. Span markers:
span.start = id- Mark the beginning of a spanspan.current = id- Log within an active spanspan.end = id- Mark the end of a spanspan.parent = Some(parent_id)- Establish parent-child relationship (use withspan.start)
Basic span usage:
use SpanID;
let span = next;
info!;
info!;
info!;
Nested spans with parent-child relationships:
use SpanID;
let request_span = next;
info!;
// Create a child span for database work
let db_span = next;
info!;
info!;
info!;
Using SpanID::enter() to set thread-local span context:
use SpanID;
let span = next;
let _guard = span.enter; // Set as current thread-local span
info!;
do_database_work; // Can access current span via SpanID::current()
info!;
// Guard dropped here, previous span context restored
Default Test Logger
When no collector is explicitly initialized, kvlog automatically emits logs to stdout in a human-readable format. This works seamlessly with Rust's test runner - use cargo test -- --nocapture to see log output during tests:
This zero-configuration behavior is ideal for development and debugging. For production use, initialize a collector for better performance and output control.
Collector Configuration
For production or when you need specific output behavior, configure a collector via the KVLOG_COLLECTOR_CONFIG environment variable.
Format: [SERVICE_NAME@]KIND[:PATH]
| Kind | Description |
|---|---|
Stdout |
Log to standard output |
Directory:/path |
Log to timestamped files in directory |
SingleFile:/path |
Log to a single file |
SocketOrStdout |
Log to Unix socket, fallback to stdout |
Examples:
StdoutDirectory:/var/log/my_appSingleFile:/tmp/app.logmy-service@SocketOrStdout:/tmp/collector.sock
Features
debug- Enable thedebug!macro (compiled out by default)jiff-02- Integration with the jiff datetime library
License
MIT