Expand description
Runtime observability.
ADR 0001 asks the runtime to trace host calls, capability use, and task
lifecycle “without language-specific application hooks” — a program does
not opt in to being traced, and it cannot opt out of being traceable. This
module defines the event shape and where events go; crate::host and
(in a later pass) the interpreter are the only places that produce them.
A trace is also the input to cove replay, which reproduces a run’s Host
API interactions without calling a host. That is why TraceEvent::HostCall
carries the call’s arguments and its result and not only its shape: a
trace that says a call happened is enough to inspect a run, and not enough
to reproduce one.
§JSON schema
JsonlSink writes one JSON object per line, and every Duration field
is rendered as an integer count of nanoseconds under a key ending in
_ns. The first line is a header declaring TRACE_FORMAT_VERSION, so a
reader that does not know the version can reject the trace rather than
misread it. These keys are a stable, documented interface — a trace format
that changes silently breaks whatever reads it:
{"event":"trace_header","version":<u32>,"backend":"ast"|"vm","values":"full"|"redacted","entry":<string>,"args":[<string>...]}
{"event":"task_spawned","id":<u64>,"parent":<u64|null>,"scope":<string>}
{"event":"task_completed","id":<u64>,"cpu_ns":<u64>}
{"event":"task_cancelled","id":<u64>}
{"event":"host_call","task":<u64>,"module":<string>,"op":<string>,"capability":<string>,"wait_ns":<u64>,"granted":<bool>,"args":[<value>...],"outcome":<outcome>|null}
{"event":"entry_enter","module":<string>,"function":<string>}
{"event":"entry_exit","module":<string>,"function":<string>,"cpu_ns":<u64>,"wait_ns":<u64>}
{"event":"heap_collected","task":<u64>,"allocated":<u64>,"freed":<u64>,"live_objects":<u64>,"live_bytes":<u64>,"pause_ns":<u64>}
{"event":"heap_summary","collections":<u64>,"object_count":<u64>|null,"allocated_bytes":<u64>|null,"live_bytes":<u64>|null,"peak_bytes":<u64>|null,"pause_ns":<u64>|null,"allocated_words":<u64>|null,"capacity_words":<u64>|null,"live_words":<u64>|null}
{"event":"run_ended","outcome":<outcome-name>,"message":<string>|null}A task is the id of the task that did the thing, and the entry’s own id
is crate::runtime::ENTRY_TASK: the entry is not a spawned task, so it
takes the one id the run never hands out. An <outcome-name> is one of
the names RunOutcome::as_str writes.
An <outcome> is null for a call that never reached the host, and
otherwise one of:
{"kind":"value","value":<value>}
{"kind":"error","message":<string>}
{"kind":"not_recordable"}A <value> is a tagged encoding of one Value, covering the shapes
that cross the Host API boundary:
{"type":"unit"}
{"type":"bool","value":<bool>}
{"type":"int","value":<i64>}
{"type":"float","value":<number>}
{"type":"duration","ns":<i64>}
{"type":"string","value":<string>}
{"type":"array","items":[<value>...]}
{"type":"enum","name":<string>,"case":<string>,"payload":[<value>...]}
{"type":"struct","name":<string>,"fields":[{"name":<string>,"value":<value>}...]}
{"type":"resource","name":<string>,"id":<i64>}
{"type":"redacted","of":<string>}
{"type":"opaque","of":<string>,"shown":<string>}redacted is what ValueCapture::Redacted writes in place of every
recorded value; opaque is what a value the encoding cannot represent —
a vector, a closure, a task handle — leaves behind. Both are readable and
neither can be replayed, which is exactly the distinction cove replay
reports.
§What an event may carry
An event is produced by whichever task made the call and written by the
one sink the run shares, so every event crosses a thread boundary. What
may cross one is what the Language Card’s task-safety rule allows, which
cove_runtime::task::Transfer both decides and carries — so that is the
form a RecordedValue keeps a value in. A value that may not cross
keeps instead what a trace could have said about it anyway: what it was
and what it printed as, which is the opaque the format already writes
for a vector. The two features agree by construction: a value a task
could not have carried is a value a replay could not have reproduced.
Structs§
- Jsonl
Sink - Writes one JSON object per line to
W, flushing after every event so a trace is visible as it happens rather than only at exit. - Null
Sink - Discards every event. The default when a run is not being traced.
- Timing
- Accumulates wait time separately from total elapsed time, so a caller can
report CPU as
elapsed - wait. - Trace
Header - What a trace declares about itself before its first event.
Enums§
- Host
Outcome - What a host call produced, when the trace records it.
- Recorded
Value - One value as a trace records it.
- Recording
Backend - Which backend produced a recording.
- RunOutcome
- How a run ended.
- Trace
Event - One recorded runtime event.
- Value
Capture - How much of a host call’s arguments and results a trace records.
Constants§
- RUNTIME_
VERSION - The version of the
cove-runtimecrate a program ran against —CARGO_PKG_VERSIONat build time, and nothing more than that. - TRACE_
FORMAT_ VERSION - The version of the JSONL trace format this build writes, and the only one it reads.
Traits§
- Trace
Sink - Where trace events go.
Functions§
- create_
trace_ file - Creates the file a trace is written to, readable only by its owner where the platform can say so.
- value_
to_ json - Renders one
Valuein the trace’s value encoding, honouringcapture.