-
-
Notifications
You must be signed in to change notification settings - Fork 0
Recorder Tap Node
flight-recorder-tap — an ambient recorder. It observes messages flowing through other nodes via Node-RED's messaging hooks, without touching their wires. The flows being recorded need no modification and no redeploy; a tap on a dedicated tab can shadow your whole runtime.
| Port | Carries |
|---|---|
| Input | Commands only — this node receives no traffic. Payload-addressed commands are accepted here as a convenience; the control node is the canonical path. |
| Output 1 — incidents | Incidents: manual dumps, watermark hits, and automatic error dumps. |
| Output 2 — query | Status snapshots (with tap extras — active mutes, scope counters). |
| Output 3 — events | Everything, tagged with msg.recorderEvent, including the tap-specific muted / unmuted / muteIgnored. |
Selection is a simple algebra: (flows ∪ nodes ∪ types) − exclusions.
| Field | Meaning |
|---|---|
| All flows | Record every node in the runtime. Overrides the three selectors below. |
| Flows | Flow (tab) ids, comma-separated. The clickable list under the field shows every workspace by label — click to add or remove, no need to know ids. |
| Nodes | Individual node ids. |
| Types | Node types, e.g. mqtt in, http request — powerful for cross-cutting concerns like "record every external I/O point". |
| Exclude nodes / types | Always win over any selector — e.g. "the whole Production tab, except that chatty poll loop". |
Recorders never record recorders. All four flight-recorder node types are hard-excluded from every scope, unconditionally — even under All flows, even if explicitly named. This prevents feedback loops (a tap capturing its own incident emissions) by construction.
Scope membership is evaluated lazily per source node and cached, so a node added to a watched flow by a partial deploy is picked up the first time it sends — no tap redeploy needed. One known edge: a node moved between flows keeps its cached verdict until the tap itself is redeployed.
Subflows: nodes inside a subflow instance report types like subflow:<subflow-id>, so type-based scoping of subflow contents is unintuitive — scope by flow or node id instead.
Hooks observe messages between nodes: each record is a message some node sent. The tap cannot see inside a function node's logic, nor messages a node swallows without sending — though a swallowed message shows up honestly as a gap in that source's cadence. A message fanning out to several wires is recorded once (deduplicated per emission), with the emitting node and its output port in the record's source.
With auto-dump on errors enabled, an error reported by any in-scope node triggers dump("error", …) — the incident's context carries the error (structured, stack capped), the erroring node, and the message it was handling. The cooldown applies, so an error loop can't flood your outputs; each suppressed dump emits incidentSuppressed.
Honesty notes: this relies on nodes reporting errors properly (node.error(err, msg)) — well-behaved nodes do, some older contrib nodes swallow errors. And a hard runtime crash fires no hook at all; persistence is the recovery story for that case, which is precisely why the feature exists.
Scope membership is static configuration; muting is the runtime knob. mute / unmute commands (with a target: { "node": "<id>" }, { "type": "mqtt in" }, or { "flow": "<tab id>" }) silence one channel while everything else keeps recording — for when a flapping sensor is drowning the buffer and you need to see everything else.
A muted gap is never invisible:
- Suppressed messages are counted per target; the counts appear in
queryresults and theunmutedevent. - Muting and unmuting each lay an annotation mark on the tape, in sequence position — an incident spanning a mute window shows exactly where the gap begins and ends.
- A muted source's errors still auto-dump. You muted its chatter, not its failures.
Mutes are deliberately ephemeral: they reset on deploy and restart (a mute silently outliving a restart is a trap). Permanent silences belong in the exclusion config. A mute targeting a node the tap has already seen and rejected as out-of-scope is refused with a muteIgnored event rather than silently accepted.
Capacity, capture mode, max bytes, redaction, cooldown, persistence, and the watermark all behave exactly as on the inline recorder — one shared engine, two capture modes. The watermark is evaluated against every in-scope message the tap captures.
Like the inline node's, plus an active-mute count: ● 87/100 (2 muted).
Every in-scope message is cloned and encoded. For most flows this is negligible; for a genuinely chatty source (a high-frequency MQTT firehose), prefer summary capture mode, keep Max bytes modest, exclude or mute the loudest sources, and remember this is a diagnostic tool, not a message historian. Two taps with overlapping scopes each keep their own buffer — memory doubles. With persistence on under sustained traffic, the write debounce means regular disk writes; on flash-based hosts (Raspberry Pi, Home Assistant Yellow eMMC) that's worth knowing.
Flight Recorder
Node Reference
Reference
Guides
Testing