slog-scope

Thread-local logging scopes for slog-rs, so you can log without manually threading Logger objects through every function call.

Library
Cargo
v4.4.1
14stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
24/100Needs Attention
Development Activity4
Maintenance0
Community20
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
61/100Good
Architecture65
Code Quality55
Innovation55
Learning Curve70

slog-scope is a small companion crate for slog-rs that lets Rust applications log through a global or thread-local Logger without passing that logger explicitly through every function signature. You set a global logger once at startup (typically in main), and from then on any code can call slog_scope::logger() or the crate’s info!/error!/debug! macros to log through whatever Logger is active for the current scope.

Logging scopes can be nested via slog_scope::scope(), which pushes a thread-local Logger for the duration of a closure and pops it on drop, making the mechanism panic-safe. The crate is explicitly framed by its own maintainers as an ergonomics escape hatch for application code (main functions, top-level handlers) rather than something to depend on inside reusable libraries, where slog’s usual philosophy of explicitly passing a Logger down the call stack is preferred.

What You Get

  • A global logger slot (set_global_logger) returning a GlobalLoggerGuard that resets logging to a panicking drain on drop, so forgetting to hold the guard fails loudly instead of silently swallowing logs.
  • Thread-local logging scopes (scope()) that let you push a child Logger for the duration of a closure, enabling nested contextual logging without changing function signatures.
  • logger() and with_logger() accessors — the former clones the current scope’s Logger, the latter borrows it for a callback when avoiding a clone matters for performance.
  • Drop-in macros (crit!, error!, warn!, info!, debug!, trace!) that log through the current scope logger without needing to import or hold a Logger reference at the call site.

Common Use Cases

  • Application entry points that want to set up structured logging once in main and have it available everywhere without passing a Logger through every layer.
  • Request or job handlers that push a scoped logger enriched with request-specific key-value context (request ID, user ID) for the duration of handling one unit of work.
  • Retrofitting slog-based structured logging into existing code that wasn’t written with explicit Logger parameters, without a large refactor.

Under The Hood

Architecture: The crate is a single ~250-line lib.rs with no submodules. It holds two pieces of state: a process-wide lazy_static! GLOBAL_LOGGER: ArcSwap<slog::Logger> that defaults to a Discard drain, and a thread_local! TL_SCOPES: RefCell<Vec<*const slog::Logger>> stack per thread. logger()/with_logger() check the thread-local stack first and fall back to the global logger; scope() pushes a raw pointer onto that stack via an RAII ScopeGuard and pops it on drop (using unsafe to dereference the pointer, since the borrow is guaranteed valid for the closure’s lifetime by construction). set_global_logger() swaps the ArcSwap and returns a GlobalLoggerGuard that, unless cancel_reset() is called, resets the global logger to a drain that panics on any log call when dropped — a deliberate design choice to surface “logger torn down but still being used” bugs immediately rather than silently discarding.

Tech Stack: Pure Rust, no async runtime dependency. Core dependencies are slog 2.4 (the logging framework this crate augments), lazy_static 1.2 (for the global logger cell), and arc-swap 1.1 (lock-free atomic swapping of the global Logger). Dev-dependencies (slog-term, slog-async) are only used in the example under examples/compact-color.rs. The crate targets stable Rust and has no feature flags.

Code Quality: There is no dedicated test suite in the repository — no tests/ directory and no #[test] functions in lib.rs; correctness is exercised only via the single runnable example and the doctest embedded in the crate-level doc comment (which itself sets up a global logger and a nested scope). The unsafe pointer dereference in logger()/with_logger() is narrowly scoped and justified by the RAII guard’s lifetime discipline, but is unverified by any test. #![warn(missing_docs)] is set and every public item carries a doc comment, which is a genuine quality signal despite the missing tests. Naming is consistent with the rest of the slog-rs ecosystem (slog_info, slog_error, etc. re-exported alongside scope-aware info!/error! macros).

API Design: The public surface is intentionally tiny: set_global_logger, scope, logger, with_logger, and six logging macros. Getting started requires exactly one call (set_global_logger) plus holding onto its guard; from there, logging calls read identically to plain slog macros. The crate’s own documentation is unusually candid about when not to use it (library code, as opposed to applications), which is good API stewardship even though it constrains the crate’s applicability.

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