incident
Freezes the perishable evidence of a live run — journal segments, trace logs, the resolved run profile, the last engine snapshot and a redacted environment — into one timestamped bundle.
A live node's forensic trail is scattered across stores that overwrite themselves. The write-ahead command journal is mmap segments that prune. The JSON trace log rolls daily and can be size-capped. The resolved run profile is a file somebody can edit between runs. The process environment is gone the instant the process exits. When something goes wrong at 03:00 the operator needs a single artifact that pins all of it to the moment of the incident, before any of it rots.
incident is that artifact's collector. The binary is
crates/vike-run/src/bin/incident.rs; the collection itself is crates/vike-run/src/incident.rs's
run_incident. It is feature-free — no venue or native dependencies — so it builds in the default
lane like any ordinary target.
incident --since 2h
incident --since 30m --out /var/vike/incidents
incident --since 1d --journal-dir data/journal --profile run.toml--since is the one required flag and takes a Vike interval — 30s, 15m, 2h, 1d. A
malformed value is an error, not a zero-length window: an empty bundle would read as "there was no
evidence". vike-run incident … also works — one leading incident token is accepted and dropped,
a second is not. The bundle's directory path is printed on stdout.
What it collects
Into incident-<UTC>/:
- the journal segment files whose last write overlaps the window, gzipped;
- the trace-log files from the resolved log directory whose last write overlaps the window, gzipped;
- the resolved
RunProfileTOML plus its FNV-1a64 hash, so a later edit to that file is detectable; - the latest
EngineSnapshotand itsstate_hash, taken from the journal's lastSnap; - git SHA and build info;
- a redacted dump of the process environment.
Selection is select_overlapping: a file is in when its last write is at or after now - since,
with the subtraction saturating so a huge window cannot overflow.
The archive is per-file gzip in a directory alongside a plain manifest.json rather than one
.tar.gz. The module doc is explicit that this is a deliberate fallback — a single tarball needs a
tar crate the crate cannot compile-check in its current build lane — and that bundling the
directory afterwards is a trivial follow-up.
Safe to run against a live node
incident is a read-only collector. It opens the journal through
vike_core::journal::CommandJournal's read_all — the lock-free entry point the journal module
blesses for offline inspection tooling — never the writer. Nothing in the mount path calls it, the
live core is untouched, and no existing struct gains a field for it.
Redaction
The environment dump is masked exactly the way the signers' manual Debug implementations mask
their secrets (crates/vike-bridge-core/src/signer.rs): redact_secret_value returns ***
followed by the last four characters, and nothing else. A value shorter than four characters gets
the bare mask.
Which keys get masked is is_secret_key, and its doc states the bias: a generous, case-insensitive
substring match, because over-redaction is safe — it costs an operator a non-secret flag — while a
miss leaks a credential. It covers every credential shape the workspace uses (*_API_KEY,
*_API_SECRET, *_API_PASSPHRASE, *_PRIVATE_KEY, the Polymarket PK family) plus tokens,
mnemonics, seeds and signatures. Most VIKE_* runtime flags carry none of those needles and pass
through verbatim. The ones whose names do are masked: the genuine secrets
(VIKE_TRADEHUB_CONTROL_KEY, VIKE_TELEGRAM_BOT_TOKEN and their family) as intended, and
VIKE_ALLOW_WITHDRAW_KEYS — an ordinary flag whose _KEYS suffix trips the _KEY needle — as
over-redaction, which is the safe direction. build_manifest redacts internally, so the artifact
is safe to share by construction.
Where the sources come from, and where the bundle lands
Every source is resolved the way a live node resolves it, never re-derived:
- profile —
--profile, elseVIKE_RUN_PROFILE, throughvike_core::run_profile'sresolve_profile_path, so this bin cannot silently diverge from the resolver the node uses; - journal directory —
--journal-dir, elseVIKE_JOURNAL_DIR, else the loaded profile's journal sink; - log directory — the same four-layer precedence
vike_log::resolve_log_dirgives a node (VIKE_LOG_DIR, then the flag, then the project's ownsettings/state/logs, then<exe_dir>). Before the project layer existed this resolved to<exe_dir>/logsand would now miss every log the collector was built to freeze; - output —
--out, else the project'ssettings/state/incidents, else<exe_dir>.
The bundle is not scratch
The output default is deliberately not a temporary directory. A bundle is frozen post-mortem evidence — written precisely so it can be read after the thing that produced it is gone — so an owned scratch directory that deletes on drop, or a swept root that prunes to a bounded newest-N, would each destroy the only artifact this binary exists to make. It used to default to a fixed name under the system temp directory, which failed twice over: inside a container that directory is not the host's and does not survive a restart, and on a shared box whoever created it first owned it permanently.
File logging is switched off for this process, so the collector never writes into the very log directory it is about to freeze.
The parser rules worth knowing
A valued flag must be given a value, and a token beginning with -- is a flag, never a value.
That rule closed a real defect: --out --profile used to parse cleanly and write the post-mortem
bundle into a directory literally named --profile. A collector whose evidence lands somewhere
nobody looks is the same as no collector. It is -- and not a bare -, so a negative number stays
a legal value.
-h/--help exits 0 to stdout — it used to exit 1, which breaks set -e and any wrapper that
checks a status. A --help in a value slot (--out --help) is still refused as a swallow,
because succeeding there would silently discard the --out the operator typed. A repeated flag
takes the last value, silently.
See the command journal for what the segments contain, and replay-journal for replaying them deterministically afterwards.
collector_supervisor
The always-on supervisor that keeps a declared set of history-store series fresh and heals their historical holes, instead of an operator re-running one-shot collectors by hand.
Venue setup tools
Two one-off operator binaries that arrange something at a venue before trading — cTrader's OAuth catcher and Hyperliquid's builder-fee grant.