MCP server: One MCP server.

Rlg

@sebastienrousseauMCP server · External

MCP server exposing rlg log streams to LLM agents via JSON-RPC 2.0 over stdio.

Application monitoringv0.0.15Apache-2.0Rust
Freeno charge per call

Runs on your machine from its package; the steps are below.

The rlg CLI filtering a service log to errors in Elastic Common Schema, then rlg-report summarising the same file by level, component and message
From the README

What it does

  1. Reads
  2. Writes
  3. High impact

At most: only reads or looks up information.

What it costs

Free

Odel charges nothing per call. The publisher may charge for its own service.

Runs locally over stdio

This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).

Dockerghcr.io/sebastienrousseau/rlg-mcp:0.0.15

Run

docker run -i --rm ghcr.io/sebastienrousseau/rlg-mcp:0.0.15

MCP client config

{
  "mcpServers": {
    "rlg": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "ghcr.io/sebastienrousseau/rlg-mcp:0.0.15"
      ]
    }
  }
}
README9 min read

rlg logo

rlg

Near-lock-free structured logging for Rust: records leave the application thread with a few atomic operations and are formatted and written by a background flusher.

Build Registry Docs OpenSSF Scorecard OpenSSF Best Practices License: Apache-2.0 OR MIT Minimum supported Rust version 1.88.0

The rlg CLI filtering a service log to errors in Elastic Common Schema, then rlg-report summarising the same file by level, component and message


Contents

Getting started

  • Install — Cargo for the libraries, cargo install for the CLIs and the MCP server
  • Requirements — toolchain floor, platforms
  • Quick Start — one structured record, fired and flushed

The rlg ecosystem

  • The rlg ecosystem — rlg, rlg-cli, rlg-report, rlg-mcp, rlg-otlp, rlg-redact, rlg-tower, rlg-test, rlg-wasm, rlg-ebpf

Library reference

Operational


Install

As a Rust library

toml
[dependencies]
rlg = "0.0.15"

Satellites install the same way, all at the same version:

toml
[dependencies]
rlg-otlp   = "0.0.15"  # ship records to an OpenTelemetry Collector
rlg-tower  = "0.0.15"  # per-request access logs for tower services
rlg-redact = "0.0.15"  # scrub secrets and PII before they are written

[dev-dependencies]
rlg-test   = "0.0.15"  # assert on captured records in tests

Command-line tools

bash
cargo install rlg-cli      # `rlg`: filter and convert log files
cargo install rlg-report   # `rlg-report`: summaries by level, component and message
cargo install rlg-mcp      # `rlg-mcp`: log files as tools for AI agents

From a checkout, make install builds the three binaries and installs them with their manpages and bash, zsh and fish completions under /usr/local (PREFIX and DESTDIR are honoured; make uninstall reverses it). The binaries generate both themselves: rlg --manpage > rlg.1, rlg --completions zsh > _rlg.

rlg-mcp is also published as a container image, ghcr.io/sebastienrousseau/rlg-mcp, and listed in the MCP registry.


Requirements

  • Rust 1.88.0 or newer (edition 2024). CI builds every library and binary on 1.88.0; see the toolchain policy.
  • macOS or Linux for the native sinks (os_log, journald). Everywhere else, including Windows, rlg writes to a file or stdout.

Quick Start

rust
use rlg::log::Log;
use rlg::log_format::LogFormat;

fn main() {
    // Keep the guard for the life of the program: dropping it flushes
    // pending records and stops the background thread.
    let _guard = rlg::init().unwrap();

    Log::info("User authenticated")
        .component("auth-service")
        .with("user_id", 42)
        .format(LogFormat::JSON)
        .fire();
}

fire() checks the level, pushes the record into a ring buffer and returns; the flusher thread formats it as JSON and writes it to the platform sink. This block is compiled and run by cargo test.


The rlg ecosystem

Ten crates at lockstep version 0.0.15, released together.

ComponentPurposeUse case
rlgThe engine: 65,536-slot ring buffer, background flusher, 14 formats, native sinksStructured logging in any Rust program
rlg-cliThe rlg binary: filter by level, component or attribute, convert between formatsmy-service | rlg --min-level error --format ecs
rlg-reportThe rlg-report binary and library: counts by level and component, top messages, latency percentilesOn-call triage, daily error digests
rlg-mcpMCP server: four tools, one prompt, two resources over stdio, streamable HTTP or HTTP+SSEAI agents reading production logs
rlg-otlpOTLP/HTTP exporter to a local OpenTelemetry CollectorHoneycomb, Datadog, Grafana through a Collector
rlg-redactScrubs cards, JWTs, bearer tokens, emails, IPv4 addresses and AWS keys in one passGDPR and audit-trail safety
rlg-towertower::Layer emitting one access-log record per requestaxum, hyper and other tower services
rlg-testCapture records in a test and assert on themLibraries testing their own log output
rlg-wasmwasm-bindgen bindings and a WASI 0.2 component interfaceBrowsers, Deno, Workers, wasmtime hosts
rlg-ebpfProcess enrichment, portable; an eBPF enricher scaffold on LinuxHost context on every record

Capabilities at a glance

AreaCapabilityStatus
IngestionAtomic level filter, ring-buffer push, no lock on the caller's threadStable
FormatsJSON, NDJSON, ECS, GELF, Logstash, OTLP, MCP, logfmt, CLF, CEF, ELF, W3C, Apache, Log4j XMLStable
Sinksos_log (macOS), journald (Linux), file, stdoutStable
Sinksio_uring file sink (Linux, uring feature)Scaffold
ConfigurationTOML load, validation, polling hot-reload (tokio feature)Stable
Bridgeslog facade via rlg::init(); tracing layer (tracing-layer feature)Stable
ExportOTLP/HTTP to a local Collector (rlg-otlp)Stable
AgentsMCP server over stdio, streamable HTTP and HTTP+SSE (rlg-mcp)Stable
EnrichmenteBPF kernel context (rlg-ebpf, Linux)Scaffold

Ecosystem comparison

rlg trades tracing's span model for an event-only engine that keeps formatting and I/O off the application thread and ships native sinks, many formats and an agent interface in the box.

ProjectFormatting off the caller's threadBuilt-in formatsNative journald / os_log
rlgyes14yes
tracing + tracing-subscriberadd-ontext, JSONadd-on
slogadd-onadd-onadd-on
log + env_loggernotextno

See docs/COMPARISON.md for the evidence and complete matrix.


Benchmarks

The competitive_bench suite times rlg's fire() against tracing::info! and log::info! for single records, records with attributes, 10,000-record bursts and latency distribution. It runs in CI on every release tag, and its results are published as workflow artifacts.

ScenarioResultEnvironment
rlg fire(), one record598 nsGitHub-hosted ubuntu-latest, release profile
tracing::info! to a discarding writer591 nssame run
rlg fire() with 3 attributes947 ns (tracing: 1,117 ns)same run

On the calling thread rlg now costs about what tracing costs, without formatting there; what it buys is that the caller never waits on the sink's I/O.

See docs/BENCHMARKS.md for methodology and full results.


Features

Everything optional is off by default.

FeatureCrateAdds
tokiorlgConfig::load_async and polling hot-reload
tuirlgA live terminal dashboard, started with RLG_TUI=1
tracing-layerrlgRlgLayer, a tracing_subscriber::Layer
fast-queuerlgAn eight-shard ring buffer for many concurrent producers
uringrlgThe io_uring file sink on Linux
asyncrlg-otlpAsyncOtlpExporter on Tokio

Configuration

Config loads from TOML, validates, and creates the log paths it needs.

toml
# rlg.toml
version              = "1.0"
profile              = "production"
log_file_path        = "/var/log/rlg.log"
log_level            = "INFO"
logging_destinations = [
    { type = "File", value = "/var/log/rlg.log" },
    { type = "Stdout" },
]
log_rotation         = { Size = 10485760 }  # 10 MiB

Load it with Config::load(Some("rlg.toml")), or with the tokio feature Config::load_async, and follow edits with Config::hot_reload_async. RUST_LOG sets the level too. The crate README lists every field.


Examples

ExampleShowsRun
example_log_formatAll 14 formats side by sidecargo run -p rlg --example example_log_format
example_configTOML config, async load, hot-reloadcargo run -p rlg --example example_config --features tokio
example_macrosThe logging macroscargo run -p rlg --example example_macros
serve_a_sessionA full MCP session against rlg-mcpcargo run -p rlg-mcp --example serve_a_session
honeycombExporting through a local Collectorcargo run -p rlg-otlp --example honeycomb

CI runs every example on each pull request (examples-smoke.yml), except example_config and example_utils, async demos whose behaviour the crate's own tests cover.


When not to use rlg

  • Low volume. Below about a hundred records a second, a background thread and a 65k-slot buffer buy nothing a synchronous logger does not already give you.
  • Spans are your model. rlg records events. If hierarchical spans are what you analyse, use tracing directly; rlg's layer only bridges its events.
  • Windows Event Log. There is no native Windows sink; rlg writes to a file or stdout there.
  • Every record must survive a crash. Records wait in memory until the flusher writes them; a process killed before the FlushGuard drops loses what is still buffered.
  • You need a stable API. rlg is at 0.0.x: any release may break, and it has one maintainer.

Development

bash
make verify   # everything CI runs on a pull request
make demo     # re-render .github/demo.gif from .github/demo.tape

DEVELOPMENT.md lists every gate with its local command: Miri, Loom and Kani for the engine's concurrency and memory safety, four fuzz targets, cargo-deny and cargo-vet for the dependency tree, cargo-semver-checks, a 95% coverage floor and complexity ceilings. Contribution and signing rules are in CONTRIBUTING.md and AGENTS.md.


Security

  • Reporting: privately, by email or GitHub's advisory form; never in a public issue. The process and response time are in SECURITY.md.
  • Memory safety: unsafe is denied across the workspace except the documented macOS os_log FFI in crates/rlg/src/sink.rs. The engine runs under Miri on every push.
  • Resource limits: the ring buffer is bounded at 65,536 records and evicts the oldest when full; rlg-otlp caps a collector's response headers at 16 KiB and times out every request.
  • Fuzzing: four cargo-fuzz targets (record parsing, format names, config loading, redaction) run on every pull request; see docs/OSS-FUZZ.md for OSS-Fuzz status.
  • Supply chain: every dependency passes cargo-deny and cargo-vet; releases publish through crates.io Trusted Publishing with sigstore-signed SBOMs (pkg/VERIFY.md).

Report vulnerabilities according to SECURITY.md.


Documentation

DocumentFor
User manualTutorials, how-to guides, architecture, ADRs (source)
API referenceEvery public item, per crate on docs.rs
DEVELOPMENT.mdToolchain, local gates, test layout, release model
docs/ARCHITECTURE.mdHow the engine and satellites fit together
CHANGELOG.mdWhat changed in each release
Migration guidesComing from log, slog or tracing

Stability guarantees

  • SemVer axis: rlg is at 0.0.x, so under Cargo's rules every release may be breaking. Breaking changes are marked Breaking in the CHANGELOG, and cargo-semver-checks runs on every pull request so none slips through unannounced.
  • Output stability: the bytes a format produces are an interface. A change to them for the same record is breaking even when no signature moves, and is recorded the same way.
  • Minimum toolchain: Rust 1.88.0, enforced in CI; a rise is its own CHANGELOG entry with the reason. docs/POLICIES.md has the full policy.

License

Dual-licensed under either of

at your option. Unless you state otherwise, any contribution you submit for inclusion in rlg is dual-licensed as above, without additional terms.

Similar modules

Browse Application monitoring