kamu-logging
Opinionated tracing setup for PT IMMER services. One-line init for the
zero-config path; a builder for everything else (JSON output, custom env
vars, OTLP export, correlation ids).
Install
[]
= "1"
MSRV: Rust 1.88 (edition 2024).
Features
| Feature | Default | What it enables |
|---|---|---|
systemd |
yes | TTY-aware console + journald sink, RUST_LOG, log → tracing bridge |
with-actix-web |
yes | Correlation-enriched Actix Web middleware |
with-otlp |
no | OpenTelemetry OTLP exporter (HTTP/protobuf) |
wasm32 |
no | Cloudflare Worker / web console + panic hook (mutually exclusive) |
Quickstart
init() picks a sensible default for the target: pretty TTY output when
stdout is a terminal, journald when not, and RUST_LOG for filtering.
Configuration
For anything beyond the default path, build an InitOptions:
use ;
init_with?;
Builder methods (all consume self, all return Self):
| Method | Purpose |
|---|---|
with_service_name(n) |
Attach service.name to the startup event + OTLP Resource |
with_default_filter(f) |
Filter directive used when the env var is unset |
with_env_var(v) |
Env var read for the filter (default RUST_LOG) |
with_format(f) |
Auto / Compact / Pretty / Json |
with_sink(s) |
Auto / Stdout / Stderr / Journald |
idempotent(true) |
Treat duplicate init as Ok(()) (test harnesses, embedded runs) |
with_otlp(cfg) |
(with-otlp) Add an OTLP exporter layer |
Env-var triggers (no code change)
| Variable | Values | Effect |
|---|---|---|
RUST_LOG |
tracing-subscriber directive | Filter directive (overridable per init) |
KAMU_LOG_FORMAT |
auto, compact, pretty, json |
Sets Format when the option is Auto |
KAMU_LOG_SINK |
auto, stdout, stderr, journald |
Sets Sink when the option is Auto |
JSON output for log aggregators
use ;
init_with?;
Or set KAMU_LOG_FORMAT=json KAMU_LOG_SINK=stdout at the process level
for zero-code adoption. Each event is one line of JSON suitable for
Vector, Promtail, Fluent Bit, or the Datadog Agent.
Actix Web
use ;
use get_actix_web_logger;
async
get_actix_web_logger() uses an EnrichedRootSpanBuilder that adds a
correlation_id field to the root span by extracting (in order):
X-Request-ID, X-Correlation-ID, traceparent. For a custom builder,
use get_actix_web_logger_with::<MyBuilder>().
Correlation outside HTTP
For queue consumers, scheduled tasks, or any non-HTTP entry point:
use ;
with_id;
The header-chain extractor is reusable for any framework — pass a closure that fetches a header by name:
let id = extract_from_headers;
OTLP export
Enable the with-otlp feature and attach an OtlpConfig:
use ;
init_with?;
Uses a synchronous SimpleSpanProcessor so no async runtime is required.
High-throughput services should replace the exporter with a batch
processor configured against their runtime — open an issue if you want a
built-in option.
WASM
[]
= { = "1", = false, = ["wasm32"] }
init() on wasm32 installs console_error_panic_hook and a
tracing-subscriber console writer suitable for Cloudflare Workers Logs.
Format::Auto resolves to JSON, while Sink::Auto, Sink::Stdout, and
Sink::Stderr all write to the JavaScript console. The function is
idempotent on this target by design; subsequent calls are no-ops.
Cloudflare Workers
Use workers-rs as usual, disable default features, and enable wasm32:
[]
= { = "1", = false, = ["wasm32"] }
= "0.8"
The repository includes a standalone Worker app in
examples/cloudflare-worker/. For setup, Wrangler config, Workers Logs, and
correlation-id examples, see the Cloudflare Workers guide.
Idempotence
init()returnsErr(Error::AlreadyInitialized)on a second call. Surfaces library double-init as a bug.init_or_skip()returnsOk(())on a second call. Use from test harnesses and embedded CLI runs.InitOptions::idempotent(true)does the same thing via the builder.
Re-exported tracing items
So you can avoid a separate tracing import for the basics:
use ;
Troubleshooting
| Symptom | Fix |
|---|---|
| No logs in container | Set KAMU_LOG_SINK=stdout — default routes non-TTY to journald |
Error::IO at init in a container |
journald socket unavailable; use KAMU_LOG_SINK=stdout |
Tests hang at init() |
Use init_or_skip() per-test or InitOptions::idempotent(true) |
| OTLP exporter slow | SimpleSpanProcessor is synchronous; high-volume needs a batch processor |
service.name missing from fmt output |
Only attached to startup event + OTLP Resource; aggregators add it from infra metadata |
SemVer policy
1.x.y — breaking changes only on major bumps. Additive changes ship as
minor releases. Bug fixes ship as patches. The Error enum is
#[non_exhaustive]; new variants are not breaking.
License
MIT — see LICENSE.