winston
A Winston.js-inspired logging library for Rust.
Installation
Add to your Cargo.toml:
[]
= "0.2"
Alternatively, run:
Quick Start
Using the Global Logger
use ;
The global logger is an application-wide static reference that provides centralized logging access, requiring configuration only once to add a transport, as it starts without a default one. It eliminates the need to pass logger instances around, with functions like log(), configure() close() and flush() operating directly on this global logger. Macros like log!() implicitly use it. Since static references don’t automatically call drop, flush() is necessary to ensure all logs are processed, particularly before the application exits.
Creating Your Own Logger
use ;
Configuration Options
| Option | Description | Default Value |
|---|---|---|
level |
Minimum severity of log messages to be logged. Anything equal to or higher in severity will be logged. | info |
levels |
Severity levels for log entries. | {error: 0, warn: 1, info: 2, debug: 3, trace: 4} |
transports |
Logging destinations (stdout, stderr, File, Custom). |
None |
format |
Log message formatting (e.g., json, timestamp). |
json |
channel_capacity |
Maximum size of the log message buffer. | 1024 |
backpressure_strategy |
Action when buffer is full (Block, DropOldest, DropCurrent). |
Block |
Logging Basics
The log! Macro
The simplest way to log messages is using the log! macro:
// Using the global logger
log!;
log!;
// Using a specific logger
log!;
It takes the following parameters:
level: Log level (info,warn,error, etc.).Message: A string message.- Optional key-value pairs: Metadata to add context.
Level-specific Methods and Macros
Winston provides macros to create level-specific logging methods and macros:
use HashMap;
use ;
// Define custom logging methods and macros
create_log_methods!; // Creates methods like logger.foo(), logger.bar(), etc.
create_level_macros!; // Creates macros like foo!(), bar!(), etc.
let logger = builder
.add_transport // Use stdout as the logging transport
.levels
.level // Set the minimum log level to "bar" (log bar and more severe levels)
.build; // Build the logger instance
// Usage of the logger methods with various levels and metadata:
// Log a message at the "foo" level with no metadata
logger.foo;
// Log a message at the "foobar" level with metadata (key-value pairs)
logger.foobar;
// Use the "foobar" macro to log a message at the "foobar" level
foobar!;
// with metadata
foobar!;
// Log a message at the "foo" level globally (no logger instance needed)
foo!;
// Log a message at the "foo" level globally with metadata
foo!;
Key Concepts
Transports
Transports define the destinations where log messages are written. Winston includes core transports that leverage Rust's standard I/O capabilities, with additional custom transports possible through community contributions. Each transport implements the Transport trait from winston_transport:
Built-in Transports
Winston provides two core transports:
WriterTransport
A generic transport that writes to any destination implementing Rust's Write trait:
use ;
use WriterTransport;
// Write to stdout
let stdout_transport = new
.with_level;
// Write to a file
let file = create.unwrap;
let file_transport = new
.with_format;
// Write to a network socket
let stream = connect.unwrap;
let network_transport = new;
There are quick WriterTransport creation for common use cases:
use ;
// Quick stdout/stderr transports
let logger = builder
.add_transport // Same as WriterTransport::new(io::stdout())
.add_transport // Same as WriterTransport::new(io::stderr())
.build;
File Transport
Specialized file transport with querying capabilities for log retrieval.
Creating Custom Transports
To define a custom transport, implement the Transport trait and define the log method:
use ;
;
Multiple Transports
You can use multiple transports simultaneously, even of the same type. Each transport can have its own configuration:
use ;
use File;
let logger = builder
// Log all info and above to stdout with simple formatting
.add_transport
// Log all error to file with JSON formatting
.add_transport
.build;
// Usage
log!;
log!;
Logging Levels
Winston's logging levels conform to the severity ordering specified by RFC 5424, ranked in ascending order of importance. Lower numeric values indicate more critical (important) events.
levels:
Custom Logging Levels
In addition to the predefined rust, syslog, and cli levels available in winston via winston::format::config::, you can also choose to define your own:
use HashMap;
use Logger;
let custom_levels = from;
let logger = builder
.levels
.build;
Log Level
The level configuration represents the minimum severity of messages to be logged. For instance, if the level is set to "info", the logger will process only info, warn, and error messages while ignoring less critical levels like debug and trace.
let logger = builder
.level // Logs only info, warn, and error levels
.build;
Per-Transport Log Level
Each transport can define its own log level, overriding the logger level. This allows for targeted logging based on the output medium.
let logger = builder
.level // Logger default level
.add_transport
.add_transport
.build;
In this example:
- The logger level is set to
info. - The stderr transport logs only
errormessages. - The file transport logs
debugand higher (i.e.,debug,info,warn, anderror).
Formats
For advanced formatting, Winston leverages logform, which is re-exported as winston::format for convenience:
use ;
let logger = builder
.format
.build;
Each transport can have its own format, which takes precedence over the logger format:
let logger = builder
.format // Logger default format
.add_transport
.add_transport
.build;
Advanced Features
Backpressure Handling
Winston provides three backpressure strategies when the logging channel is full:
Block: Wait until space is availableDropOldest: Remove the oldest log messageDropCurrent: Discard the current log message
use ;
let logger = builder
.channel_capacity
.backpressure_strategy
.build;
Log Querying
Winston supports retrieving log entries from transports.
To enable querying for a custom transport, override the query method in your Transport implementation.
use ;
let query = new
.from
.until
.levels
.limit
.order
.search_term
let results = logger.query;
LogQuery Configuration Options
| Option | Description | Default Value |
|---|---|---|
from |
Start time for the query (supports string formats compatible with parse_datetime) |
Utc::now() - Duration::days(1) |
until |
End time for the query(supports string formats compatible with parse_datetime) |
Utc::now() |
limit |
Maximum number of log entries to retrieve. | 50 |
start |
Offset for query results, used for pagination. | 0 |
order |
Order of results, either asc, ascending, descending or desc. |
Descending |
levels |
List of log levels to include in the query (e.g., ["error", "info"]). |
[] (no filter, includes all levels) |
fields |
List of fields to filter by. | [] (no specific fields required) |
search_term |
Text to search for in log messages. | None (no search term applied) |
Logging Timestamps
Timestamps are essential for effective log querying. Log entries must include a timestamp field in their metadata (LogInfo.meta) for Winston’s querying capabilities to function as expected. The timestamp field should be a string compatible with dateparser.
Winston's built-in timestamp format simplifies this requirement:
use ;
let logger = new
.format // Adds a timestamp to each log entry
.build;
Runtime Reconfiguration
Change logging configuration dynamically at runtime:
use ;
let logger = default;
logger.configure;
Performance
- Configurable Buffering: Adjust channel capacity to match your application's needs
Contributing
Contributions are welcome! Please submit issues and pull requests on our GitHub repository.
License
MIT License