Skip to content

Recorder Report Node

mchristegh edited this page Jul 14, 2026 · 1 revision

flight-recorder-report — the post-mortem archiver. Wire it to any recorder output; it auto-detects what arrives and renders it human-readable, optionally landing files on disk. The classic setup: tap with auto-error on → report node with a directory → every error becomes a dated post-mortem file, automatically.

It is stateless — a pure formatter with file-landing — and produces up to two artifacts per incident:

  • the report — the rendered document, to the message and/or a file
  • the raw JSON evidence — the untouched incident, bit for bit, as a companion file sharing the same filename stem

Input — auto-detected

Arriving payload Rendered as
Incident Summary + timeline report; can be filed.
Query snapshot Status report; can be filed (filename token {trigger} renders as status).
Recorder event (envelope with recorderEvent) A one-line entry. Message only — never filed.
Anything else A one-line "not a recorder payload" note; the original is preserved untouched.

Because detection is automatic, "which output do I wire this to?" has a simple answer: any of them. Wiring the events output turns the report node into a readable activity log; incident copies arriving there render as full reports.

Reading an incident report

 FLIGHT RECORDER INCIDENT · ERROR
 store / incident / at / runtime          ← identity and provenance
 cause "..." from: worker [function]      ← error triggers: failure front and center
 47 records · span 1m 34s · median gap 2.0s
 wraps 12 · truncated 0 · dropped while paused 0
  SEQ    +TIME     GAP   SOURCE           PAYLOAD
  ...one line per record...

Timeline notation: +TIME is relative to the first record; GAP is the delta since the previous capture; gaps ≥ 3× the median are flagged (the median is in the stats line, so the flag is interpretable); truncated records are marked . Annotation marks (── MARK ──), mute boundaries (── MUTED ── / ── UNMUTED ──), and persistence restore boundaries (── RESTART ──) appear as full-width rules in sequence position — the report tells the recording's story, including its gaps. The runtime line (package/Node-RED/node versions, hostname) appears when the incident carries meta.

Configuration

Field Default Meaning
Format text text (monospace-aligned — sidebar and logs), Markdown (files, chats, issues), HTML (a single self-contained file, inline styles, no external resources — opens straight from disk).
Send to message message only, file only, or message + file.
Directory (empty) Where files land; created on demand. Required for any file output.
Filename {date}_{time}_{trigger}_{storeId} Template; tokens below.
Raw JSON off Also save the untouched incident/snapshot as .json, paired by stem. Requires file output — the editor greys the box out otherwise, and the runtime independently enforces it.
Retention 100 Newest N incidents kept; 0 = unlimited. Prunes report + JSON as a pair, and only ever files matching this node's own template — foreign files are never touched.
Preview 60 Payload preview width in the timeline.

Filename tokens

{date} (2026-07-13), {time} (14-32-07 — filesystem-safe), {trigger} (manual / error / watermark / status), {storeId}, {incidentId} (short 8-char form), {format}. Incident filenames use the incident's own trigger timestamp; token values are sanitized so hostile ids can't escape the directory. Collisions get -2/-3 suffixes — an archiver never overwrites evidence.

Output message

msg.payload is the rendered document — or, in file-only mode, a confirmation line naming what was written. Everything else lives in msg.report:

{
  "kind": "incident",
  "format": "html",
  "source": { ...the original payload, untouched... },
  "files": [
    { "kind": "report", "path": "/share/.../..._error_tap1.html", "bytes": 8412, "ok": true },
    { "kind": "raw",    "path": "/share/.../..._error_tap1.json", "bytes": 21033, "ok": true }
  ]
}

Failures report per-file with a reason — a partial write (disk filled between the pair) is never invisible.

Misconfiguration behavior

File output requested without a directory, or Raw JSON with a message-only destination: the node warns once at deploy, disables the affected output for the session, and keeps rendering to the message where possible. Configuration problems degrade; they never throw.

The debug sidebar and long reports

The sidebar truncates displayed strings at 1000 characters by default (debugMaxLength in settings.js). Reports are longer. The report itself is always complete — raise the limit, or use file output to read full reports. There's a reminder of this in the node's edit dialog.

Status

Green incident ✓ · saved ×2 on success; red write failed when any file write fails (details in msg.report.files).

Clone this wiki locally