Skip to main content

Crate rasant

Crate rasant 

Source
Expand description

Rasant is a lightweight, high performance and flexible Rust library for structured logging, inspired by the likes of zap and zerolog.

It offers nanosecond precision, stackable logging and outstanding performance: on modern systems, Rasant can process and dispatch logs to multiple sinks in tens of nanoseconds, being normally bottlenecked by I/O operations. Can’t wait that long? There’s built-in async support!

§Main Features

§Examples

§Basic Logging

Loggers can be easily initialized using sink defaults, and accessed via methods…

use rasant;
use rasant::Value;

let mut log = rasant::Logger::new();
log.add_sink(rasant::sink::stderr::default()).set_level(rasant::Level::Info);

log.set("program_name", "test");
log.info("hello world!");
log.warn_with("here's some context", [("line", Value::from(7))]);
log.debug("and i'm ignored :(");

…or the much nicer macro API:

use rasant as r;

let mut log = r::Logger::new();
log.add_sink(r::sink::stderr::default()).set_level(r::Level::Info);

r::set!(log, program_name="test");
r::info!(log, "hello world!");
r::warn!(log, "here's some context", line = 7);
r::debug!(log, "and i'm ignored :(");
2026-04-03 17:16:03.773 +0200 [INF] hello world! program_name="test"
2026-04-03 17:16:03.773 +0200 [WRN] here's some context program_name="test" line=7

§Attributes

Rasant supports multiple attribute types (a.k.a Values): single Scalar values, lists and maps.

use rasant as r;

let mut log = r::Logger::new();
log.add_sink(r::sink::stderr::default()).set_level(r::Level::Info);

r::info!(log, "a single", value = 123.456);
let simple_list = [1, 2, 3, 4];
r::info!(log, "lists can be simple", list = r::list!(simple_list));
r::info!(log, "or have mixed types", list = r::list!("string!", 123.456, 789012 as usize));
r::info!(log, "and so can maps!", map = r::map!("key #1" => 123, 456 => 789.012));
2026-05-04 03:58:41.189 +0200 [INF] a single value=123.456
2026-05-04 03:58:41.189 +0200 [INF] lists can be simple list=[1, 2, 3, 4]
2026-05-04 03:58:41.189 +0200 [INF] or have mixed types list=["string!", 123.456, 0xc0a14]
2026-05-04 03:58:41.189 +0200 [INF] and so can maps! map={"key #1": 123, 456: 789.012}

§Stacking

All Loggers can be cheaply cloned, inheriting all settings from its parents - including Levels, sinks, filters and fixed attributes, allowing for very flexible setups.

For example, to have all errors (or higher) within a thread logged to stderr:

use rasant as r;
use std::thread;

let mut log = r::Logger::new();
log.add_sink(r::sink::stdout::default()).set_level(r::Level::Info);
r::info!(log, "main logs to stdout only");

let mut thread_log = log.clone();
thread::spawn(move || {
    thread_log.add_sink(r::sink::stderr::default()).set_level(r::Level::Error);
	r::set!(thread_log, thread_id = thread::current().id());

	r::info!(thread_log, "this will not log anything");
	r::fatal!(thread_log, "but this will log to both stdout and stderr");
});

§Configuring Sinks

sinks can be configured to tweak multiple parameters, including time and overall output format.

use rasant as r;

let mut log = r::Logger::new();
log.set_level(r::Level::Info).add_sink(
    r::sink::stdout::new(r::sink::stdout::StdoutConfig {
		formatter_cfg: r::FormatterConfig {
			format: r::OutputFormat::Json,
			time_format: r::TimeFormat::UtcNanosDateTime,
			..r::FormatterConfig::default()
		},
		..r::sink::stdout::StdoutConfig::default()
	})
);

r::info!(log, "hello!");
{"time":"2026-04-03 16:03:04.481888522","level":"info","message":"hello!"}

§Asynchronous Logging

Loggers can dynamically enable/disable async writes.

When in async mode, log operations have a slightly longer (as details are copied into a queue) but fixed lock time, making it ideal f.ex. for writing to slow storage without compromising overall performance.

use rasant as r;

let mut log = r::Logger::new();
log.set_level(r::Level::Info).add_sink(r::sink::stdout::default());

r::info!(log, "this is writen synchronously");
log.set_async(true);
r::info!(log, "and these write");
r::warn!(log, "asynchronously, but");
r::info!(log, "in order!");

§Filtering

Loggers can apply configurable runtime filters on log operations. Supported filters include:

Note that filters are evaluated at logging time, and will introduce (minimal) latency, regardless of Loggers having async mode enabled.

use rasant as r;
use std::time::Duration;

// Log a maximum of 10 Debug, Warning and Fatal updates per second, to keep SREs happy.
let mut log = r::Logger::new();
log
    .add_sink(r::sink::stdout::default())
    .set_all_levels()
    .add_filter(
        r::filter::level::In::new(
            r::filter::level::InConfig {
                levels: [r::Level::Debug, r::Level::Warning, r::Level::Fatal],
            }))
    .add_filter(
        r::filter::sample::Burst::new(
            r::filter::sample::BurstConfig {
                period: Duration::from_millis(1000),
                max_updates: 10,
            }));

r::info!(log, "this will not log");
r::debug!(log, "but");
r::fatal!(log, "these");
r::warn!(log, "will");

§Concepts

Rasant is a structured logging library: it logs messages with a set of associated key-Value pairs, in formats (f.ex. JSON) which are intended to be easily machine-readable.

§Methodology

Rasant is built around individual Logger logging instances and sinks, which are configurable destinations for log updates. When a log operation is performed, its level is compared to the one defined for the Logger and, if applicable, the log is written on all its sinks.

Once a sink is added to a Logger, it cannot be removed nor modified.

§Attributes

§Types

Attributes are the defining quality of a structured logging system, expressed as key-value pairs. In Rasant, keys are &str, and Values are a dedicated type, supporting different configuration of Scalars.

  • Scalars are the base unit for attribute values, mapping to basic data types: integers, floats and strings.
  • Value is a structured collection of Scalars.

Rasant supports three basic Value types:

§Scope

Attributes can be set for Loggers as a whole, affecting all log operations, or for individual log writes, which can optionally provide extra attributes with additional information.

Upon key collisions, attribute values for the log call take precedence and override Logger settings, but without modifying it.

§Memory Management

Rasant keeps all items associated with a Logger (keys, attribute values, their Scalars and all strings) in a group of owned vector arrays. No other heap allocation is ever performed.

These vectors will grow in size when needed - but never resize down. In practice, this means that after just a few log calls vectors will grow to the size required for normal operation, at which point all Rasant operations become effectively zero-allocation.

The vectored nature of Logger storage also makes cloning and dropping these extremely efficient.

§Cloning and Stacking

Loggers can be cheaply cloned, extended and dropped. When a Logger is cloned, it inherits all settings from the original, including levels, filters, sinks (owned + inherited) and attributes.

This allows for very flexible logging setups. New Loggers can just be extensions of an original with extra arguments, have newly defined sinks, log levels, filters and/or async modes - or all of the above.

In general, programs using Rasant will instantiate a single root logger via Logger::new(), and spawn nested clones as required.

§Asynchronous Operation

By default, log operations lock until writes are propagated to all sinks associated with a given Logger.

To improve performance when slow and/or a high number of sinks is involved, Rasant supports dynamic asynchronous logging.

Loggers can be switched to asynchronous mode via Logger::set_async. When enabled, log operations defer writes by pushing them into a processing queue, and return immediately.

Rasant will spawn a single thread to handle all asynchronous write operations, and close it automatically once no async Loggers are present, and all their deferred writes have been flushed.

§Log Filters

Loggers supports optional, configurable filters for log updates. These are evaluated, in order, on every log operation, blocking sink writes unless the configured criteria for all filters is met. Multiple filters can be stacked to combine their behavior.

filters are evaluated after normal level checks, so their output is affected by each Loggers log level. When using level-based filters (f.ex. Levels), consider enabling set_all_levels() to avoid unexpected interactions.

Note that filters are evaluated at logging time, even for Loggers in asynchronous mode; as a result, every filter will introduce additional latency on all log operations for that Logger.

§Error Handling

For performance’s sake, very few operations in Rasant’s public API return errors, and will panic upon failures instead.

Pretty much all errors related to logging are unrecoverable anyway - these will either happen at initialization time, or when trying to write to a sink.

§Repository

This project is currently hosted at GitHub.

§License

Rasant is distrubuted under the MIT license.

Modules§

filter
Log filters for use with Rasant Logger instances.
sink
Log sinks for use with Rasant crate::Logger instances.

Macros§

debug
Logs an update with debug level.
error
Logs an update with error level.
fatal
Logs an update with fatal level.
info
Logs an update with info level.
list
Creates a List from types which can be cast to a collection of Scalars.
map
Creates a Map from key/value types which can be cast to collections of Scalars.
panic
Logs an update with panic level.
set
Sets a number of attributes for a given logger.
trace
Logs an update with trace level.
warn
Logs an update with warning level.

Structs§

AttributeString
A string container for any of the types supported in attributes: String, static &str, or an index within a string container.
FormatterConfig
Configuration struct for output formatting.
Logger
Base logger structure for Rasant.

Enums§

Level
Log level definition.
OutputFormat
Supported log output format for all sinks.
Scalar
Scalar definitions for all log operations. Scalars are the basic data units for Rasant, representing a single type.
TimeFormat
ntime::Format, re-exported for convenience. Defines a format for Timestamp string serialization.
Value
Value definition for all log operations. These are associated with a single &str key in attribute maps for Loggers.

Traits§

AttributeStringSeek
Defines a trait to resolve indexed AttributeStrings from a container.