r/nim • u/cryo2010 • 14h ago
lumber: A JSON logger with CLI
Hi all! I've just released lumber, a JSON logger for Nim inspired by pino, and I'd love for you to try it out. I hope to incorporate some feedback before freezing the API for v1.0.0.
Highlights
- Compile-time log elimination: build with -d:lumberLevel=INFO and calls below the threshold vanish from the binary entirely; runtime-filtered calls never evaluate their arguments either
- Structured logging: named fields (logger.info("login", user="alice")), per-logger context, child loggers, and thread-local scoped context
- Exception logging: pass an exception as an argument and its message, type, and stack trace become structured fields
- Thread-safe: share one module-level logger across threads
- Flexible outputs: size/time-based file rotation, buffering with level-triggered flush, and a background-thread async writer
- Middleware: rate limiting, sampling, and redaction (including nested fields) built in, or write your own
- CLI prettifier: pipe JSON logs through the lumber binary for colored human-readable output with level/field filtering, regex highlighting, and timezone conversion
- Minimal dependencies: stdlib plus one pure-Nim package, no C libraries
Example
import std/strformat
import lumber
type
User = object
name: string
var logger = newLogger(name = "demo")
var user = User(name: "Alice")
logger.trace("This is a trace")
logger.debug(user)
logger.info(&"{user.name} logged in")
logger.warn("Disk usage high", partition="/dev/sda1", usage=92)
proc loadConfig() =
raise newException(IOError, "file not found: config.toml")
proc initApp() =
loadConfig()
try:
initApp()
except IOError as e:
logger.error("Failed to load config", e)
logger.fatal("Game over")
Output
Raw output
{"timestamp":"2026-07-22T05:03:27.833Z","level":"TRACE","name":"demo","filename":"minimal.nim","line":18,"message":"This is a trace"}
{"timestamp":"2026-07-22T05:03:27.833Z","level":"DEBUG","name":"demo","filename":"minimal.nim","line":19,"message":"User(name: \"Alice\")"}
{"timestamp":"2026-07-22T05:03:27.833Z","level":"INFO","name":"demo","filename":"minimal.nim","line":20,"message":"Alice logged in"}
{"timestamp":"2026-07-22T05:03:27.833Z","level":"WARN","name":"demo","filename":"minimal.nim","line":21,"message":"Disk usage high","extra":{"partition":"/dev/sda1","usage":92}}
{"timestamp":"2026-07-22T05:03:27.833Z","level":"ERROR","name":"demo","filename":"minimal.nim","line":32,"message":"Failed to load config","extra":{"error":"file not found: config.toml","errorType":"IOError","stackTrace":"/Users/cryo/projects/nim/nim-lumber/examples/minimal.nim(30) minimal\n/Users/cryo/projects/nim/nim-lumber/examples/minimal.nim(27) initApp\n/Users/cryo/projects/nim/nim-lumber/examples/minimal.nim(24) loadConfig\n"}}
{"timestamp":"2026-07-22T05:03:27.833Z","level":"FATAL","name":"demo","filename":"minimal.nim","line":34,"message":"Game over"}
Piped through the CLI
2026-07-21T22:04:45.613-07:00 PDT [TRACE] (minimal.nim:18) demo: This is a trace
2026-07-21T22:04:45.613-07:00 PDT [DEBUG] (minimal.nim:19) demo: User(name: "Alice")
2026-07-21T22:04:45.613-07:00 PDT [INFO ] (minimal.nim:20) demo: Alice logged in
2026-07-21T22:04:45.613-07:00 PDT [WARN ] (minimal.nim:21) demo: Disk usage high
partition: "/dev/sda1"
usage: 92
2026-07-21T22:04:45.613-07:00 PDT [ERROR] (minimal.nim:32) demo: Failed to load config
error: "file not found: config.toml"
errorType: "IOError"
stackTrace:
/Users/cryo/projects/nim/nim-lumber/examples/minimal.nim(30) minimal
/Users/cryo/projects/nim/nim-lumber/examples/minimal.nim(27) initApp
/Users/cryo/projects/nim/nim-lumber/examples/minimal.nim(24) loadConfig
2026-07-21T22:04:45.613-07:00 PDT [FATAL] (minimal.nim:34) demo: Game over
---
More docs and examples are available in the README.
All feedback is very welcome: ergonomics, missing features, performance, or anything that feels un-Nim-like.




