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