facett-trace 0.1.11

facett — a structured JSONL event sink (the machine-readable sibling of an action log): emit typed IN/OUT/END/EVENT payloads (generic over serde::Serialize) one JSON object per line to $FACETT_TRACE, so an external agent reads back exactly the data the UI rendered. Adopted from nornir's viz trace.
Documentation

facett-trace — a structured event trace: the machine-readable sibling of a free-form action log.

An action log is a human free-form trail (tab=Bench, reload … → 3 release(s)). This is its typed counterpart: every instrumented operation emits its INPUT parameters and its OUTPUT data as real JSON payloads, so an external agent (or a headless test matrix) can read back exactly the data the UI rendered — the bubble table, the bench rows, the server response — not a summary and not a screenshot.

Adopted verbatim from nornir's src/viz/trace.rs; it was already zero-coupling (generic over serde::Serialize). The only change is the output-path env var: $FACETT_TRACE (default /tmp/facett_trace.jsonl), truncated on launch.

One JSON object per line (JSONL):

{"seq":7,"ts_ms":1733961825678,"stamp":"01:23:45.678",
 "span":"knowledge.scan","phase":"in","data":{"workspace_root":"","repos":["njord"]}}
{"seq":8,...,"span":"knowledge.scan.repo","phase":"end","data":{"repo":"njord","symbols":642,}}
{"seq":9,...,"span":"knowledge.scan","phase":"out","data":{"repos_ok":1,"repos_total":1,"ms":83}}
{"seq":10,...,"span":"knowledge.render","phase":"end","data":{"bubbles":[{"repo":"njord",}]}}

The contract

  • span — the operation name (knowledge.scan, ui.tab, server.reload).
  • phasein (params accepted), out (result produced), end (a unit of work finished), or event (a point-in-time fact, e.g. a tab switch). Pair an in with its later out/end of the same span by adjacency — the UI is single-threaded, so within one operation they don't interleave.
  • data — the real, structured payload. Emit typed structs (serialized via serde), never a pre-formatted string, so the consumer parses fields.

Cheap by design: a Mutex<File> writeln! + a global atomic seq. Call sites only emit on edge-triggered events (a scan, a click, an RPC), never per-frame.