Log events¶
stdout is the only output, and it is an event stream: one event per line. Nothing is written to disk.
Formats¶
BLASTIT_LOG_FORMAT |
What it prints |
|---|---|
json (the default) |
one JSON object per line, for a collector and for blastit-manifest fold |
pretty |
the same events as coloured, aligned lines, for debugging by hand |
Every event carries ts, level, event and component, plus route and
request_id when they apply. BLASTIT_LOG_LEVEL sets the minimum level
printed. Lines are cut at 2048 bytes, and the cut fields are listed in
truncated; a long app line becomes several app.output events carrying part
and parts.
{"ts":"2026-10-25T14:02:11.384Z","level":"info","event":"request","component":"scheduler","request_id":"01JB9…","method":"GET","path":"/products/42/","route":"product-detail","rule":0,"status":200,"outcome":"ok","queued_ms":0.1,"duration_ms":18.4,"bytes_in":0,"bytes_out":5120,"cost_ns":18400000,"cpu_ns":9100000,"remote_addr":"203.0.113.7"}
The events¶
| Event | When | Key fields |
|---|---|---|
request |
once per request, at the end — the routing decision | request_id, method, path, route (null if unmatched), rule, status, outcome, queued_ms, duration_ms, bytes_in, bytes_out, cost_ns, cpu_ns, remote_addr |
sql.denied |
a statement was rejected | route, pid, proxy, kind, sql (normalised), sqlstate, in_transaction, reason |
pg.refused |
a connection to a proxy was refused | route, proxy, reason (credentials_mismatch, upstream_unreachable, …) |
http.rejected |
a request was refused before the scheduler | remote_addr, status (400, 413, 431, 501…), reason |
process.spawned / process.exited / process.retired |
view process lifecycle | route, pid, uid, fork_ms, status or signal, reason (idle, max_requests, stuck_threads, memory_pressure) |
process.cap |
the measured cost or the live cap changed | estimate_bytes, cap |
app.output |
the app or a library printed something | stream, line, part, parts |
boot, ready, shutdown |
the server's lifecycle | see below |
manifest.warning |
the manifest is usable but has a problem | message |
outcome is one of ok, unmatched, queue_full, queue_timeout, timeout,
view_died, client_gone. cost_ns is what the request was charged for fair
queuing; cpu_ns is null when the view had no thread clock to report.
The three boot lines¶
Startup prints one boot event per phase, so a log with all three is readable on
its own.
stage0— before anything can fail: theseccompsetting as read, theprivilegemode (rootorcapabilities), thebounding_set, and the rootlesscapabilities.presetis alwaysnullhere. Written in the formatBLASTIT_LOG_FORMATnames — this line waits for the settings — or as JSON when the settings do not parse.config— as soon as the configuration parsed, before the manifest:presetin force (ornull),preset_settingswith the preset's own values, andpreset_overridden, the names an explicit variable overrode.preload— what the app cost before the fork:immortalize, itsimmortalize_reasonwhen skipped,immortalize_ms, and the memory the view-process cap came from —mem_total,mem_used,max_view_processes.
ready follows with stage: "serving", the route count, the worker budget, and
the names of the output variables per proxy, never their values. shutdown
reports the phase (drain, stopped, or <component>-died) and why a component
went away.
What is never logged¶
Query strings, header values, request and response bodies, and SQL parameter
values. path is the routed PATH_INFO, without the query string. This is an
API guarantee: those fields cannot be expressed in the event model.
Correlation¶
dbproxy never sees a request id, because the app opens its own database
connections. sql.denied carries the route and the view pid, which together
with ts line it up with request events.