Logs
tracing-subscriber setup, log levels, structured logging, and the per-crate defaults.
Krishiv uses tracing + tracing-subscriber. By default the CLI and daemons emit human-readable FMT logs to stderr; set KRISHIV_LOG_FORMAT=json for structured JSON.
Log filter
Standard tracing-subscriber env-filter. Examples:
# Default: info globally, debug in the scheduler
RUST_LOG="info,sqlx=warn,rdkafka=warn,hyper=warn,krishiv_scheduler=debug" krishiv coordinator
# Quiet everything but the dataflow
RUST_LOG="warn,krishiv_dataflow=info" krishiv sql --query "SELECT 1"
The CLI sets a default filter of info,sqlx=warn,rdkafka=warn,hyper=warn so routine SQL noise stays out of the way.
Format
Two formats, chosen at init:
| Format | Use |
|---|---|
Fmt (default) | Human-readable, color-aware. Best for local dev and journald. |
Json | One JSON object per line. Best for log shippers (Fluent Bit, Vector, Loki). |
What you'll see in a log line
2026-04-12T18:33:21.124Z INFO krishiv_scheduler::coordinator: job_id=my-pipeline epoch=42 attempt=1 message="task succeeded" duration_ms=87
Every log line carries the standard tracing fields. Crate-specific fields are documented with the event that emits them.
Instrumentation guide for contributors
- Use
#[tracing::instrument(skip_all, fields(job_id, task_id))]on functions; the macro emits enter/exit events with the field set. - For hot paths, prefer
tracing::trace!ordebug!and let the user turn them on. - Include the units in field names where ambiguous (
duration_ms,bytes,rows). - Avoid logging in tight loops. Use a counter or sample instead.
Log shipper integration
Two common patterns:
- JSON to stdout, ship from there: set
KRISHIV_LOG_FORMAT=json, let journald / Docker / your runtime pick the lines up. - OTLP logs: enable
opentelemetry-otlpwith logs enabled; traces and logs share the same pipeline.