@inteli.city/node-red-plugin-telemetry
v1.1.5
Published
Node-RED editor sidebar for system telemetry — recent issues, node hotspots, and node-type usage, with persistent on-disk history.
Readme
@inteli.city/node-red-plugin-telemetry
A Node-RED editor sidebar that surfaces the health of your running flows: recent errors and warnings, the nodes and flows that fail most, slow synchronous deliveries, and which node types are actually used (and which installed custom nodes are not). History is persisted to disk so it survives restarts.
The plugin adds a single Telemetry tab to the Node-RED sidebar. It does not add any palette nodes — there is nothing to drag onto a flow.
Features
- Issues view — time-bucketed activity (Today / Last 7 days / Last 4 months), top failing nodes, recent grouped issues, and a per-flow scope selector. Click any node/flow to open a detail panel with its timeline.
- Usage view — current node-type placement merged with runtime execution counts for the selected range, plus a list of installed custom node types that are not used in any flow. Click an instance to reveal it in the editor.
- Persistent history — recent events, hourly aggregates, and daily aggregates are written to disk and reloaded on restart.
- Slow-delivery detection — synchronous deliveries slower than a configurable threshold are recorded as warnings.
All data is collected passively from Node-RED's own log handler and message delivery hooks. The plugin never stores raw message payloads — only the fields the UI renders (node id/type/name, flow id, severity, a truncated message, and timing).
Installation
Install into an existing Node-RED instance from your Node-RED user directory
(~/.node-red by default):
cd ~/.node-red
npm install @inteli.city/node-red-plugin-telemetryThen restart Node-RED. The plugin is discovered automatically — there is no manual registration step. Open the editor and select the Telemetry tab (heartbeat icon) in the right-hand sidebar.
You can also install it from the Manage palette dialog in the editor by
searching for @inteli.city/node-red-plugin-telemetry.
This is a scoped package. If you fork and publish your own copy, remember that scoped packages publish privately by default — use
npm publish --access public.
Supported versions
| Component | Supported |
|-----------|-----------|
| Node-RED | >= 3.0.0 (declared in the package node-red.version field) |
| Node.js | >= 16.0.0 (engines.node). Node 18 LTS or newer is recommended, and is required if you run Node-RED 4.x. |
The plugin uses only Node-RED's public editor/runtime APIs
(RED.plugins, RED.sidebar, RED.httpAdmin, RED.auth, RED.hooks,
RED.log, RED.nodes) and the Node core fs/path modules. It declares no
third-party runtime dependencies.
Configuration
All configuration is optional. Add a telemetry block to your
Node-RED settings.js to override defaults:
// settings.js
module.exports = {
// ...
telemetry: {
// Synchronous delivery slower than this (ms) is recorded as a warning.
slowThresholdMs: 250,
persistence: {
maxSamplesPerIssue: 50, // example messages kept PER issue fingerprint
eventsRetentionHours: 24, // how long raw example samples are kept
hourlyRetentionDays: 7, // retention for hourly aggregate buckets
dailyRetentionDays: 180, // retention for daily aggregate buckets
maxPersistedEvents: 2000, // global backstop on total retained samples
flushIntervalSeconds: 30 // how often dirty state is written to disk
}
}
};Two retention layers — counts vs. examples. Occurrence counts are exact
and live in the hourly/daily aggregate buckets (hourlyRetentionDays /
dailyRetentionDays), so totals like "500 occurrences" always reflect the full
selected range. Raw example messages are bounded per issue fingerprint
(maxSamplesPerIssue) so one noisy issue can't evict every other issue's
samples; eventsRetentionHours ages them out and maxPersistedEvents is a
global backstop on the total. The UI labels these examples "latest N samples ·
M total" — they're the most recent, not a slice of the whole range.
| Key | Default | Meaning |
|-----|---------|---------|
| slowThresholdMs | 250 | Threshold for flagging slow synchronous executions. |
| persistence.maxSamplesPerIssue | 50 | Raw example messages kept per issue fingerprint (counts are unaffected). |
| persistence.eventsRetentionHours | 24 | Age cutoff for raw example samples. |
| persistence.hourlyRetentionDays | 7 | Age cutoff for hourly buckets (exact counts). |
| persistence.dailyRetentionDays | 180 | Age cutoff for daily buckets (exact counts; ≥ the 126-day "Last 4 months" window so old days keep exact counts). |
| persistence.maxPersistedEvents | 2000 | Global backstop on total retained samples. |
| persistence.flushIntervalSeconds | 30 | Interval between deferred disk flushes. |
Storage scope
The plugin owns exactly one directory and writes nothing outside it:
<userDir>/.telemetry/
├── issues.json # per-fingerprint bounded sample store (grouped issues)
├── hourly.json # hourly aggregate buckets
└── daily.json # daily aggregate buckets<userDir> is RED.settings.userDir (typically ~/.node-red), falling back
to the process working directory only if userDir is unset. The directory
name and the three filenames are fixed constants — no value from an HTTP
request, query string, or flow ever influences a filesystem path. There is no
file-browsing, upload, download, or arbitrary-path capability in this plugin,
so there is no path-traversal surface to exploit.
To relocate telemetry data, point Node-RED's userDir at a different
location; the plugin follows it.
Permissions and access control
The plugin registers three admin HTTP endpoints under
/telemetry/*, each guarded by RED.auth.needsPermission:
| Endpoint | Method | Required permission |
|----------|--------|---------------------|
| /telemetry/history | GET | telemetry.read |
| /telemetry/usage | GET | telemetry.read |
| /telemetry/clear | POST | telemetry.write |
When Node-RED's adminAuth is disabled (the default for a local
instance), these endpoints behave like every other editor admin route and are
open to anyone who can reach the editor.
When adminAuth is enabled, access follows your configured permissions:
- Users granted
*(full access) can read telemetry and clear it. - To grant read-only access, include
telemetry.readin a user's permissions; to allow clearing data as well, also granttelemetry.write. - A user with only
read(the standard Node-RED read scope) will be able to view telemetry but the Clear button will fail with a permission error — which is the intended behaviour.
Because telemetry can reveal node names, flow names, and error messages from
your deployment, treat telemetry.read as you would any other admin
read scope and restrict it accordingly in multi-user setups.
Security considerations
- No payload capture. Events store only rendered metadata and a truncated
(≤ 2000 char) message string. Raw
msgpayloads are never persisted. - No arbitrary file access. See Storage scope — all paths are constant; there is no user-controlled path input.
- No command execution. This plugin does not spawn processes, install packages, or run shell commands.
- No outbound network calls. Data stays on the local disk and is only served back to authenticated editor sessions.
- Error responses are minimal. Server-side failures (e.g. a disk write error) are logged to the Node-RED log, not returned to the browser, so filesystem details are not exposed to clients.
Reliability
- Missing/corrupt state files are handled gracefully — each store file falls back to an empty dataset if it cannot be read or parsed.
- Atomic writes — each file is written to a
.tmpsibling and renamed into place, so a crash mid-write cannot leave a half-written store. - Bounded growth — retention pruning and a hard event cap run periodically; in-memory timing state is capped and self-clears.
- Startup is non-fatal. If the store directory cannot be created or read, the plugin logs a warning and continues with empty data — Node-RED starts normally either way.
- Graceful shutdown. Pending state is flushed synchronously on
beforeExit,SIGINT, andSIGTERM.
Upgrade safety
- The on-disk format is append-and-default: new fields (such as per-node
executions) default to0for older buckets, so upgrading in place keeps your existing history. No migration step is required. - Upgrade with
npm install @inteli.city/node-red-plugin-telemetry@latestfrom your user directory and restart Node-RED. The.telemetrydirectory is untouched by install/uninstall. - Breaking changes, if any, will be listed in
CHANGELOG.md. There are none in the current1.xline.
To start fresh, use the Clear button in the sidebar (requires
telemetry.write) or delete the <userDir>/.telemetry
directory while Node-RED is stopped.
Automated tests
Run npm install then npm test (Vitest). Covers the layout-mode breakpoints,
detail open/close state, Issues/Usage rendering, backend route contracts, and a
regression guard that fails if the plugin ever mutates Node-RED's host layout.
See TESTING.md for details and coverage notes.
Validation / smoke test
To verify a clean install end to end:
- In an empty user dir:
cd /tmp/nr-test && npm install @inteli.city/node-red-plugin-telemetry(ornpm install /path/to/this/checkout). - Start Node-RED with
--userDir /tmp/nr-test. - Confirm the log line
[telemetry] ready — ...appears. - Open the editor → Telemetry sidebar tab. Both
style.jsandplugin.jsshould load fromresources/@inteli.city/node-red-plugin-telemetry/telemetry/*(check the browser network tab — no 404s). - Deploy a flow that throws an error; confirm it appears under Issues.
- Switch to Usage; confirm deployed node types are listed.
- Restart Node-RED; confirm history persists.
- (Auth) Set
adminAuthwith a read-only user and confirm Clear is rejected while the views still load.
