slog

The core crate of a structured, contextual, composable logging ecosystem for Rust.

Library
Cargo
v2.8.2
1,709stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
51/100Fair
Development Activity24
Maintenance24
Community56
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
77/100Good
Architecture82
Code Quality80
Innovation70
Learning Curve75

slog is the core crate behind slog-rs, an ecosystem of reusable components for structured, extensible, and composable logging in Rust. Rather than shipping one monolithic logger, slog defines a small set of open traits — Drain, Logger, Record, Serializer — that let applications assemble exactly the logging pipeline they need, then publish independent feature crates (slog-term, slog-json, slog-async, slog-syslog) on top of that shared core.

Its defining feature is the tree-structured Logger: child loggers inherit and extend the key-value context of their parent, so request IDs, connection info, or module names attach once and propagate automatically to every log statement beneath them, instead of being repeated at each call site. Values are captured lazily through closures and retain type information end to end, so the same log record can be rendered as a colorized terminal line, machine-readable JSON, or a syslog message without re-deriving the data. The project is stable and widely used, though its own README now points newer users toward tracing for async-heavy codebases while noting slog remains the better fit when async isn’t a concern or a mature, unchanging API matters more.

What You Get

  • Tree-structured Logger objects that inherit and extend key-value context down a hierarchy, so contextual data attaches once and flows to every descendant logger.
  • An open Drain trait for composing output backends — terminal, JSON, async, syslog, journald, and more — each published as an independent feature crate rather than bundled into the core.
  • Lazy value evaluation via closures (FnValue), so expensive-to-compute log fields are only evaluated when a record actually needs to be emitted.
  • Compile-time log-level filtering through Cargo feature flags (max_level_*, release_max_level_*), making disabled trace/debug statements effectively free in release builds.
  • Named format-argument macros (e.g. info!(logger, "printed {line_count} lines", line_count = 2)) that bridge human-readable and machine-readable output from a single call site.
  • Optional integrations behind Cargo features: serde-based nested value logging, anyhow::Error support, and parking_lot Mutex drains, each versioned independently to avoid dependency conflicts.

Common Use Cases

  • Adding structured, contextual logging to a Rust service where request-scoped fields (user ID, trace ID, route) should propagate automatically through nested loggers.
  • Building a library that wants to emit optional log output without forcing every downstream consumer to depend on a specific logging backend.
  • Emitting the same log stream to multiple destinations at once — colorized terminal output during development and JSON or syslog output in production — by swapping Drain implementations.
  • Embedded or no_std Rust projects that need a logging core without pulling in the standard library by default.
  • Teams that need a mature, stable logging API and are comfortable trading tracing’s async-span ergonomics for slog’s simpler, long-established trait design.

Under The Hood

Architecture slog’s execution model centers on three open traits defined in src/lib.rs: Drain consumes a Record and a Serializer-visited set of key-value pairs and decides what to do with them (format, forward, filter, or fan out); Logger is a cheap-to-clone handle that pairs a Drain with an accumulated chain of key-value context (OwnedKVList) built up via Logger::new/o!; and Record/RecordStatic carry the per-call message, level, and source-location metadata. Because child loggers wrap and extend their parent’s OwnedKVList rather than copying or replacing it, context composes down a tree with O(1) attach cost per level, and the crate ships zero built-in output backends — slog-term, slog-json, slog-async, and friends implement Drain externally, keeping the core dependency-free.

Tech Stack The crate targets Rust edition 2018 with an MSRV of 1.61 and is #![no_std]-capable, gating the standard library behind an opt-out std feature. Its dependency surface is entirely optional and feature-gated: serde_core for nested structured values, anyhow for Error value support, erased-serde (pinned to the 0.3 line for public-API stability) for object-safe serialization, and versioned parking_lot_N features (e.g. parking_lot_0_12) that let multiple parking_lot majors coexist without conflict. A build.rs plus the rustversion crate handle conditional compilation across supported compiler versions, and the key-handling logic is isolated under src/key/ with separate static.rs/dynamic.rs implementations selected by the dynamic-keys feature.

Code Quality The crate enables #![warn(missing_docs)] and related lint groups at the top of lib.rs, and its public surface (91+ public traits/structs/enums/fns) is documented extensively with inline /// doc comments and runnable examples throughout the ~4,270-line lib.rs. Test coverage lives in a dedicated src/tests.rs (28 #[test] functions covering macro expansion, drain composition, and level filtering) plus integration tests under tests/ for regression issues and prelude-import conflicts; no unsafe blocks were found in the core logic. Compile-time feature combinations (nothreads, dynamic-keys, no_std) add real-world testing surface beyond a single default build.

API Design The macro-driven front end (o!, info!, debug!, crit!, log!) supports named format arguments that double as both the human-readable message and structured key-value fields in one call, which is ergonomic once learned but represents a genuinely larger surface than log’s simple macros — the project’s own README acknowledges the steeper learning curve and points readers to a Getting started wiki and a sloggers convenience wrapper for users who want less ceremony. Root drains must resolve error handling explicitly via .fuse() or .ignore_res(), which is a deliberate but non-obvious API requirement newcomers hit immediately.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search