Open History to see the last commit
1# Resource telemetry
2
3Process counters come from a [standalone Rust monitor](../../native/resource-monitor/src/main.rs)
4using `sysinfo`. Electron main supplies host power and Electron process metrics.
5Keeping native collection outside Node isolates collector crashes and avoids a
6Node/Electron addon ABI matrix. Desktop and CLI servers use the same child-process
7protocol. A missing or failed collector leaves the server running.
8
9## Collection cost
10
11The native child owns sampling and bounded in-memory history. It samples on a timer
12only while diagnostics has live subscribers. With none, the server sends a sample
13interval of 0 and the child samples only on request, so an idle server never walks
14the process table. The exception is OTLP metrics export: a server exporting metrics
15requests one sample a minute and exports process totals by group
16([`ProcessGroupMetrics`](../../apps/server/src/resourceTelemetry/ProcessGroupMetrics.ts)),
17because the user asked for continuous telemetry. Groups are a fixed set named after
18the server's direct children, never process IDs or threads, so the series count
19stays bounded as agents come and go. History therefore covers only time with a live
20subscriber, plus on-demand and export samples. Consuming host power for background scheduling must not retain
21live diagnostics. There is no telemetry database or recurring shell-probe fallback.
22
23History has independent bounds for age, snapshot count, process rows, and retained
24bytes. A count limit alone cannot bound memory when command lines vary in size.
25Large process trees therefore shorten the available history window. Linux task
26enumeration is disabled because walking every `/proc/<pid>/task/<tid>` directory
27makes sampling itself expensive.
28
29Electron power updates travel over private inherited pipes, independent of the
30renderer connection. Power events and slow heartbeats continue with diagnostics
31closed; `app.getAppMetrics()` runs only on live demand. The receiver's stale deadline
32must exceed the slowest configured heartbeat plus scheduling grace, or intentional
33idle polling makes background policy oscillate between constrained and
34unconstrained states. Headless servers leave unavailable power data unknown.
35
36## Measurement traps
37
38- Process identity includes start time because operating systems reuse PIDs.
39 Electron and native start times have different precision, so merging allows a
40 small tolerance. Process signaling rechecks the native identity with a fresh
41 sample.
42- Snapshot sequence numbers belong to a monitor generation. Comparing them across
43 restarts would discard the new monitor's samples until its sequence caught up.
44- Sampling can miss a process that starts and exits between samples. Cumulative
45 counters still yield deltas for processes observed across samples.
46- Windows process I/O includes more than disk traffic. Unix counters report storage
47 I/O, which can differ from logical application reads and writes because of OS
48 caching. Keep instrumented logical I/O separate from these counters.
49- Group totals accumulate observed deltas since telemetry started. Per-process
50 cumulative counters cover the operating system's lifetime for that process.
51- Historical replay uses native samples without current Electron CPU or memory
52 metrics. Merging the latest Electron values would overwrite the past.
53
54A WSL backend needs a Linux monitor even though Electron runs on Windows. Windows
55desktop packages currently supply only the Windows executable, so native process
56telemetry for the WSL backend is unavailable. The inherited Electron power feed
57still works.