rigscope 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +4 -4
- package/.next/build-manifest.json +2 -2
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/administration/page_client-reference-manifest.js +1 -1
- package/.next/server/app/administration.html +1 -1
- package/.next/server/app/administration.rsc +2 -2
- package/.next/server/app/administration.segments/_full.segment.rsc +2 -2
- package/.next/server/app/administration.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/administration.segments/administration/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/alerts/page_client-reference-manifest.js +1 -1
- package/.next/server/app/alerts.html +1 -1
- package/.next/server/app/alerts.rsc +2 -2
- package/.next/server/app/alerts.segments/_full.segment.rsc +2 -2
- package/.next/server/app/alerts.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/connections/page_client-reference-manifest.js +1 -1
- package/.next/server/app/connections.html +1 -1
- package/.next/server/app/connections.rsc +2 -2
- package/.next/server/app/connections.segments/_full.segment.rsc +2 -2
- package/.next/server/app/connections.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/history/page.js +2 -2
- package/.next/server/app/history/page_client-reference-manifest.js +1 -1
- package/.next/server/app/history.html +1 -1
- package/.next/server/app/history.rsc +5 -5
- package/.next/server/app/history.segments/_full.segment.rsc +5 -5
- package/.next/server/app/history.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +5 -5
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +2 -2
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +1 -1
- package/.next/server/app/login.rsc +2 -2
- package/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/machines/[machineId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/processes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/processes.html +1 -1
- package/.next/server/app/processes.rsc +2 -2
- package/.next/server/app/processes.segments/_full.segment.rsc +2 -2
- package/.next/server/app/processes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +2 -2
- package/.next/server/app-paths-manifest.json +4 -4
- package/.next/server/chunks/168.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/408-351fe4a1e9a2d556.js +1 -0
- package/.next/static/chunks/app/history/page-adc25194b30c689d.js +3 -0
- package/.next/static/css/{f5d3162842dcac31.css → 2abef6d49c1c2970.css} +1 -1
- package/ARCHITECTURE.md +25 -9
- package/CHANGELOG.md +35 -0
- package/README.md +10 -3
- package/dist/cli.cjs +106 -2
- package/dist/collector.cjs +23 -6
- package/dist/hub.cjs +3441 -1457
- package/dist/ops.cjs +1196 -896
- package/dist/system.cjs +65 -0
- package/docs/configuration.md +33 -1
- package/docs/installation.md +3 -3
- package/docs/monitoring.md +57 -17
- package/docs/operations.md +38 -9
- package/docs/releasing.md +12 -12
- package/docs/telemetry-storage.md +187 -0
- package/package.json +3 -1
- package/.next/static/chunks/408-9fdba9e4e956ef08.js +0 -1
- package/.next/static/chunks/app/history/page-a25ba8fab7bd7cb9.js +0 -3
- /package/.next/static/{9SHY6v87ulfunqR2e84n9 → Jlbibe2_iFCljUO4-BUK7}/_buildManifest.js +0 -0
- /package/.next/static/{9SHY6v87ulfunqR2e84n9 → Jlbibe2_iFCljUO4-BUK7}/_ssgManifest.js +0 -0
package/dist/system.cjs
CHANGED
|
@@ -789,6 +789,13 @@ async function enrollCollector(path, connectUrl, enrollmentToken, sharing, repla
|
|
|
789
789
|
// src/hub/config.ts
|
|
790
790
|
var import_node_net = require("node:net");
|
|
791
791
|
var import_node_path3 = require("node:path");
|
|
792
|
+
|
|
793
|
+
// src/contracts/telemetry.ts
|
|
794
|
+
var MAX_PERSISTENT_FLUSH_MS = 5e3;
|
|
795
|
+
var MIN_EPOCH = Date.parse("2000-01-01T00:00:00Z");
|
|
796
|
+
var MAX_EPOCH = Date.parse("2200-01-01T00:00:00Z");
|
|
797
|
+
|
|
798
|
+
// src/hub/config.ts
|
|
792
799
|
var MAX_HUB_COLLECTORS_BYTES = 1024 * 1024;
|
|
793
800
|
var MAX_COLLECTOR_ID_LENGTH = 128;
|
|
794
801
|
var MAX_MACHINE_ID_LENGTH = 128;
|
|
@@ -816,6 +823,7 @@ function parseHubConfig(env) {
|
|
|
816
823
|
maxCollectorConnections = parsed;
|
|
817
824
|
}
|
|
818
825
|
const connectionBudget = maxCollectorConnections === void 0 ? {} : { maxCollectorConnections };
|
|
826
|
+
const history = parseHistoryConfig(env);
|
|
819
827
|
if (publicOrigin === void 0 !== (socketPath === void 0)) {
|
|
820
828
|
throw new HubConfigError(
|
|
821
829
|
"HUB_PUBLIC_ORIGIN and HUB_SOCKET_PATH must be set together: remote mode needs both the exact HTTPS origin and the Unix socket path"
|
|
@@ -835,6 +843,7 @@ function parseHubConfig(env) {
|
|
|
835
843
|
collectors,
|
|
836
844
|
development,
|
|
837
845
|
remote: parseRemoteConfig(publicOrigin, socketPath),
|
|
846
|
+
history,
|
|
838
847
|
...connectionBudget
|
|
839
848
|
};
|
|
840
849
|
}
|
|
@@ -844,9 +853,65 @@ function parseHubConfig(env) {
|
|
|
844
853
|
collectors,
|
|
845
854
|
development,
|
|
846
855
|
remote: null,
|
|
856
|
+
history,
|
|
847
857
|
...connectionBudget
|
|
848
858
|
};
|
|
849
859
|
}
|
|
860
|
+
var DEFAULT_MEMORY_BUDGET_BYTES = 128 * 1024 * 1024;
|
|
861
|
+
var DEFAULT_PERSISTENT_FLUSH_MS = MAX_PERSISTENT_FLUSH_MS;
|
|
862
|
+
var DEFAULT_RECORDING_MAX_DURATION_MS = 60 * 6e4;
|
|
863
|
+
var DEFAULT_RECORDING_MAX_BYTES = 64 * 1024 * 1024;
|
|
864
|
+
var DEFAULT_RECORDING_BACKLOG_MS = 10 * 6e4;
|
|
865
|
+
var DEFAULT_MAX_ACTIVE_RECORDINGS = 4;
|
|
866
|
+
var HOUR_MS = 36e5;
|
|
867
|
+
var DAY_MS = 864e5;
|
|
868
|
+
function parseHistoryConfig(env) {
|
|
869
|
+
const modeValue = env.HUB_TELEMETRY_MODE ?? "memory";
|
|
870
|
+
if (modeValue !== "memory" && modeValue !== "persistent") {
|
|
871
|
+
throw new HubConfigError("HUB_TELEMETRY_MODE must be memory or persistent");
|
|
872
|
+
}
|
|
873
|
+
const memoryBudgetBytes = envInteger(
|
|
874
|
+
env.HUB_HISTORY_MEMORY_BYTES,
|
|
875
|
+
DEFAULT_MEMORY_BUDGET_BYTES,
|
|
876
|
+
1 * 1024 * 1024,
|
|
877
|
+
16 * 1024 * 1024 * 1024,
|
|
878
|
+
"HUB_HISTORY_MEMORY_BYTES"
|
|
879
|
+
);
|
|
880
|
+
const flushIntervalMs = envInteger(
|
|
881
|
+
env.HUB_TELEMETRY_FLUSH_MS,
|
|
882
|
+
DEFAULT_PERSISTENT_FLUSH_MS,
|
|
883
|
+
1e3,
|
|
884
|
+
MAX_PERSISTENT_FLUSH_MS,
|
|
885
|
+
"HUB_TELEMETRY_FLUSH_MS"
|
|
886
|
+
);
|
|
887
|
+
const retention = {
|
|
888
|
+
rawMs: envInteger(env.HUB_RETENTION_RAW_MS, 2 * DAY_MS, 0, 400 * DAY_MS, "HUB_RETENTION_RAW_MS"),
|
|
889
|
+
tenSecondMs: envInteger(env.HUB_RETENTION_10S_MS, 2 * HOUR_MS, 0, 30 * DAY_MS, "HUB_RETENTION_10S_MS"),
|
|
890
|
+
oneMinuteMs: envInteger(env.HUB_RETENTION_1M_MS, 30 * DAY_MS, 0, 400 * DAY_MS, "HUB_RETENTION_1M_MS"),
|
|
891
|
+
oneHourMs: envInteger(env.HUB_RETENTION_1H_MS, 400 * DAY_MS, 0, 800 * DAY_MS, "HUB_RETENTION_1H_MS"),
|
|
892
|
+
receiptsMs: envInteger(env.HUB_RECEIPT_RETENTION_MS, 7 * DAY_MS, HOUR_MS, 400 * DAY_MS, "HUB_RECEIPT_RETENTION_MS"),
|
|
893
|
+
gapsMs: envInteger(env.HUB_GAP_RETENTION_MS, 400 * DAY_MS, 0, 800 * DAY_MS, "HUB_GAP_RETENTION_MS")
|
|
894
|
+
};
|
|
895
|
+
const recordings = {
|
|
896
|
+
directory: nonEmpty(env.HUB_RECORDINGS_DIR) ?? null,
|
|
897
|
+
maxDurationMs: envInteger(env.HUB_RECORDING_MAX_DURATION_MS, DEFAULT_RECORDING_MAX_DURATION_MS, 1e3, 24 * 60 * 6e4, "HUB_RECORDING_MAX_DURATION_MS"),
|
|
898
|
+
maxBytes: envInteger(env.HUB_RECORDING_MAX_BYTES, DEFAULT_RECORDING_MAX_BYTES, 64 * 1024, 1024 * 1024 * 1024, "HUB_RECORDING_MAX_BYTES"),
|
|
899
|
+
backlogMs: envInteger(env.HUB_RECORDING_BACKLOG_MS, DEFAULT_RECORDING_BACKLOG_MS, 0, 24 * 60 * 6e4, "HUB_RECORDING_BACKLOG_MS"),
|
|
900
|
+
maxActive: envInteger(env.HUB_RECORDING_MAX_ACTIVE, DEFAULT_MAX_ACTIVE_RECORDINGS, 1, 32, "HUB_RECORDING_MAX_ACTIVE")
|
|
901
|
+
};
|
|
902
|
+
return { mode: modeValue, memoryBudgetBytes, flushIntervalMs, retention, recordings };
|
|
903
|
+
}
|
|
904
|
+
function envInteger(raw, fallback, min, max, name) {
|
|
905
|
+
if (raw === void 0 || raw === "") return fallback;
|
|
906
|
+
if (!/^\d+$/.test(raw)) {
|
|
907
|
+
throw new HubConfigError(`${name} must be a nonnegative integer`);
|
|
908
|
+
}
|
|
909
|
+
const value = Number(raw);
|
|
910
|
+
if (!Number.isSafeInteger(value) || value < min || value > max) {
|
|
911
|
+
throw new HubConfigError(`${name} must be between ${min} and ${max}`);
|
|
912
|
+
}
|
|
913
|
+
return value;
|
|
914
|
+
}
|
|
850
915
|
function nonEmpty(value) {
|
|
851
916
|
return value === void 0 || value === "" ? void 0 : value;
|
|
852
917
|
}
|
package/docs/configuration.md
CHANGED
|
@@ -17,7 +17,21 @@ configuration files at `0600`; do not commit them.
|
|
|
17
17
|
| --- | --- |
|
|
18
18
|
| `HUB_HOST`, `HUB_PORT` | Local listener: `127.0.0.1:8081`. Only literal loopback addresses are accepted. Port `0` selects an unused port for tests. |
|
|
19
19
|
| `HUB_PUBLIC_ORIGIN`, `HUB_SOCKET_PATH` | Remote access: set both the exact HTTPS origin and an absolute Unix socket path in a private directory. The hub then has no TCP listener. |
|
|
20
|
-
| `HUB_DATABASE_PATH` | SQLite database for
|
|
20
|
+
| `HUB_DATABASE_PATH` | SQLite database for control state (users, alerts and the collector registry) and, only when enabled, telemetry history. Defaults beside `HUB_STATE_FILE`, or under `$XDG_STATE_HOME/rigscope/hub/` (falling back to `~/.local/state`). |
|
|
21
|
+
| `HUB_TELEMETRY_MODE` | `memory` (default) keeps bounded history in RAM and writes no routine telemetry rows. `persistent` opts into compact SQLite summaries. See [telemetry storage](telemetry-storage.md). |
|
|
22
|
+
| `HUB_HISTORY_MEMORY_BYTES` | Global RAM budget for memory history. Default `134217728` (128 MiB). |
|
|
23
|
+
| `HUB_TELEMETRY_FLUSH_MS` | Persistent-mode write interval. Default and maximum `5000` ms (5 seconds); allowed 1000–5000. The bound keeps one commit inside the 64-batch collector window at the fastest supported 100 ms cadence and well below the collector's 30 s ack timeout. |
|
|
24
|
+
| `HUB_RETENTION_RAW_MS` | Persistent raw-mode retention. Default 2 days. Persistent summary mode does not write raw rows. |
|
|
25
|
+
| `HUB_RETENTION_10S_MS` | Ten-second summary retention in persistent mode. Default 2 hours. |
|
|
26
|
+
| `HUB_RETENTION_1M_MS` | One-minute rollup retention. Default 30 days. |
|
|
27
|
+
| `HUB_RETENTION_1H_MS` | One-hour rollup retention. Default 400 days. |
|
|
28
|
+
| `HUB_RECEIPT_RETENTION_MS` | Deduplication receipt lifetime, independent of chart retention. Default 7 days. |
|
|
29
|
+
| `HUB_GAP_RETENTION_MS` | Explicit collector gap retention. Default 400 days. |
|
|
30
|
+
| `HUB_RECORDINGS_DIR` | Private directory for explicit recordings. Default `recordings/` beside the hub database (0700 directory, 0600 files). |
|
|
31
|
+
| `HUB_RECORDING_MAX_DURATION_MS` | Maximum recording duration. Default 1 hour; maximum 24 hours. |
|
|
32
|
+
| `HUB_RECORDING_MAX_BYTES` | Maximum recording file size. Default 64 MiB; maximum 1 GiB. |
|
|
33
|
+
| `HUB_RECORDING_BACKLOG_MS` | Recent RAM history a new recording may include. Default 10 minutes. |
|
|
34
|
+
| `HUB_RECORDING_MAX_ACTIVE` | Concurrent active recordings. Default 4; maximum 32. |
|
|
21
35
|
| `HUB_BROWSER_USERS` | First-run users as JSON: `{username,passwordHash,machineIds,admin?}`. `machineIds` is `"*"` or a list; `[]` allows no machines. |
|
|
22
36
|
| `HUB_ADMIN_USERS` | Comma-separated usernames to make administrators during first import. If omitted, an existing bootstrap account named `owner` becomes an administrator. Other users need an explicit `admin:true`. |
|
|
23
37
|
| `HUB_COLLECTORS` | First-run collector credentials as JSON: `{collectorId,machineId,token}`. The limit applies to JSON bytes, not a fixed machine count. |
|
|
@@ -25,6 +39,24 @@ configuration files at `0600`; do not commit them.
|
|
|
25
39
|
| `HUB_STATE_FILE` | Private enrollment file to import from an existing installation; also enables enrollment. Keep it with the deployment configuration for recovery. |
|
|
26
40
|
| `HUB_ENROLLMENT_GRANTS` | Initial grants as JSON: `{token,expiresAt}`. Expiry must be within 15 minutes. Used grants stay consumed after import and restart. |
|
|
27
41
|
|
|
42
|
+
### Telemetry history mode
|
|
43
|
+
|
|
44
|
+
The default `HUB_TELEMETRY_MODE=memory` keeps recent charts in a bounded RAM
|
|
45
|
+
budget and deliberately loses telemetry history when the hub restarts. Users,
|
|
46
|
+
credentials, enrollment, settings and alert records remain in SQLite.
|
|
47
|
+
|
|
48
|
+
Set `HUB_TELEMETRY_MODE=persistent` to keep compact ten-second summaries, with
|
|
49
|
+
one transaction roughly every `HUB_TELEMETRY_FLUSH_MS` (five seconds by
|
|
50
|
+
default). Collectors still acknowledge only after that transaction commits, so
|
|
51
|
+
the flush interval cannot exceed the collector's 64-batch in-flight window at
|
|
52
|
+
its advertised cadence; the hub rejects values above five seconds. See
|
|
53
|
+
[telemetry storage](telemetry-storage.md) for aggregation, deduplication,
|
|
54
|
+
recording and reset details.
|
|
55
|
+
|
|
56
|
+
Switching an existing installation to memory mode does not automatically delete
|
|
57
|
+
old telemetry rows. They are ignored, but can be reclaimed explicitly with
|
|
58
|
+
`ops reset-telemetry` after stopping the hub (see [operations](operations.md)).
|
|
59
|
+
|
|
28
60
|
### First-run users and credentials
|
|
29
61
|
|
|
30
62
|
The database imports bootstrap users and collector credentials once. Later
|
package/docs/installation.md
CHANGED
|
@@ -27,7 +27,7 @@ install or source checkout is needed. The launcher and services use the installe
|
|
|
27
27
|
runtime, so removing the npx cache does not break them.
|
|
28
28
|
|
|
29
29
|
Releases are on [npm](https://www.npmjs.com/package/rigscope). `@latest` selects
|
|
30
|
-
the current stable release; replace it with `@0.
|
|
30
|
+
the current stable release; replace it with `@0.2.0` to select that exact version.
|
|
31
31
|
|
|
32
32
|
### Installation options
|
|
33
33
|
|
|
@@ -53,7 +53,7 @@ For a downloaded package or one built from source, run from the directory
|
|
|
53
53
|
containing the archive, or give its absolute path:
|
|
54
54
|
|
|
55
55
|
```sh
|
|
56
|
-
npx --yes --package ./rigscope-0.
|
|
56
|
+
npx --yes --package ./rigscope-0.2.0.tgz rigscope install --boot
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
The same installation options apply. npm still needs registry access or cached
|
|
@@ -295,7 +295,7 @@ settings and collector identities.
|
|
|
295
295
|
|
|
296
296
|
| Alternative | Command |
|
|
297
297
|
| --- | --- |
|
|
298
|
-
| Select an exact published version | `rigscope upgrade --from rigscope@0.
|
|
298
|
+
| Select an exact published version | `rigscope upgrade --from rigscope@0.2.0` |
|
|
299
299
|
| Install a local archive | `rigscope upgrade --from ./rigscope-VERSION.tgz` |
|
|
300
300
|
| Return to the retained previous runtime | `rigscope rollback` |
|
|
301
301
|
|
package/docs/monitoring.md
CHANGED
|
@@ -20,22 +20,58 @@ driver and readable counters; see [Hardware](installation.md#hardware) and
|
|
|
20
20
|
|
|
21
21
|
## History and delivery
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
History is **RAM-only by default**. Live readings update immediately, recent
|
|
24
|
+
charts come from a bounded memory budget, and telemetry history disappears when
|
|
25
|
+
the hub restarts. Users, credentials, enrollment, settings, alert records,
|
|
26
|
+
machine names/tags and inventory remain persistent.
|
|
27
|
+
|
|
28
|
+
In memory mode the collector's acknowledgement means the hub accepted the sample
|
|
29
|
+
into RAM. The collector keeps the same durable outbox and retries after a
|
|
30
|
+
disconnect; it does not gain extra disk work from the hub's choice. Deduplication
|
|
31
|
+
uses a compact per-run interval set for the hub process lifetime. Because both
|
|
32
|
+
history and receipts disappear together on restart, a replay cannot double-count
|
|
33
|
+
restored chart data.
|
|
34
|
+
|
|
35
|
+
Set `HUB_TELEMETRY_MODE=persistent` to opt into disk history. The hub buffers a
|
|
36
|
+
five-second window, publishes live state immediately, writes one compact
|
|
37
|
+
transaction, and only then acknowledges. Replay deduplication uses durable
|
|
38
|
+
receipts whose lifetime is independent of chart retention (default seven days).
|
|
26
39
|
Replayed samples fill History without replacing current live readings or opening
|
|
27
|
-
alerts for past threshold crossings.
|
|
40
|
+
alerts for past threshold crossings. A graceful shutdown flushes pending
|
|
41
|
+
summaries; after a crash the collector replays anything that was never committed.
|
|
28
42
|
|
|
29
|
-
Default
|
|
43
|
+
Default memory history:
|
|
30
44
|
|
|
31
45
|
| Resolution | Kept for |
|
|
32
46
|
| --- | --- |
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
| One-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
| 1-second detail | 2 minutes |
|
|
48
|
+
| 10-second summaries | 1 hour |
|
|
49
|
+
| One-minute summaries | 24 hours |
|
|
50
|
+
| One-hour summaries | 7 days |
|
|
51
|
+
|
|
52
|
+
Per-core CPU keeps less detail; machine-wide and capacity metrics keep more.
|
|
53
|
+
Persistent mode writes compact ten-second summaries and folds them into
|
|
54
|
+
one-minute and one-hour tiers; it does not write a raw row per reading. It keeps
|
|
55
|
+
10-second summaries for 2 hours, one-minute summaries for 30 days and hourly
|
|
56
|
+
summaries for 400 days by default. Both modes retain minimum and maximum values,
|
|
57
|
+
so short spikes remain visible, and both preserve explicit unavailable readings
|
|
58
|
+
and gaps.
|
|
59
|
+
|
|
60
|
+
RAM history is bounded by `HUB_HISTORY_MEMORY_BYTES` (default 128 MiB) across all
|
|
61
|
+
machines. When the budget fills, the oldest fine-grained tiers are dropped first
|
|
62
|
+
and new cardinality beyond the sustainable budget is rejected with visible
|
|
63
|
+
pressure. History queries limit points, series, scanned rows and elapsed time;
|
|
64
|
+
the UI marks partial results.
|
|
65
|
+
|
|
66
|
+
### Recording
|
|
67
|
+
|
|
68
|
+
Use **History → Recording** to start an explicit capture for the current
|
|
69
|
+
machine and selected metrics. Choose a resolution from 1 second to 1 hour,
|
|
70
|
+
a duration and whether to include recent RAM history. The capture is bounded by
|
|
71
|
+
duration and bytes, survives restart through its private persisted output, and
|
|
72
|
+
can be downloaded by its creator. Recording also works when chart history is
|
|
73
|
+
temporary, which is the intended way to keep an incident snapshot. See
|
|
74
|
+
[telemetry storage](telemetry-storage.md#recording).
|
|
39
75
|
|
|
40
76
|
Hover over a History or Overview recent-usage chart to inspect a recorded time
|
|
41
77
|
and its bucket averages. The time marker follows across charts in the same view;
|
|
@@ -49,11 +85,12 @@ Each collector queue keeps up to ten minutes or 64 MiB of queued JSON per hub,
|
|
|
49
85
|
with a 256 MiB total JSON limit. Physical SQLite files, including WAL files,
|
|
50
86
|
have separate limits of 80 MiB per hub and 640 MiB across eight hubs.
|
|
51
87
|
|
|
52
|
-
|
|
53
|
-
Retention protects the newest hour
|
|
54
|
-
free enough space, the hub stops acknowledging new samples and collectors
|
|
55
|
-
Existing oversized databases report pressure; startup does not run a
|
|
56
|
-
cleanup.
|
|
88
|
+
In persistent mode the hub's default database limit is 2 GiB, including WAL and
|
|
89
|
+
all control tables. Retention protects the newest hour; if old-data cleanup
|
|
90
|
+
cannot free enough space, the hub stops acknowledging new samples and collectors
|
|
91
|
+
retry. Existing oversized databases report pressure; startup does not run a
|
|
92
|
+
destructive cleanup. In memory mode old historical rows may still occupy the
|
|
93
|
+
file until you run `ops reset-telemetry`; they are not read or updated.
|
|
57
94
|
|
|
58
95
|
These are application limits, not filesystem quotas. A transaction can briefly
|
|
59
96
|
grow the WAL before checkpointing. Blocked checkpoints stop further ingestion
|
|
@@ -92,7 +129,10 @@ credentials persist in SQLite. Browser sessions stay in memory, expire after
|
|
|
92
129
|
Alerts support above/below thresholds, durations, unavailable readings, missing
|
|
93
130
|
receipts, maintenance and recovery. Value, unavailable and stale-receipt rules
|
|
94
131
|
apply to the machines tracked by that hub. Replayed samples do not open past
|
|
95
|
-
incidents.
|
|
132
|
+
incidents. Alert rules, incidents and pending notifications stay durable in both
|
|
133
|
+
history modes; with no rules configured, live ingestion does not write per-sample
|
|
134
|
+
alert progress. Enabling rules may write alert state on evaluation, which is
|
|
135
|
+
operational state rather than telemetry history.
|
|
96
136
|
|
|
97
137
|
In **Alerts**, configure one HTTPS webhook channel. Its URL, headers and HMAC
|
|
98
138
|
secret are write-only. Loopback HTTP is allowed for controlled test sinks.
|
package/docs/operations.md
CHANGED
|
@@ -10,6 +10,7 @@ building and deploying from source.
|
|
|
10
10
|
| Reset a lost password | [Password recovery](#password-recovery) |
|
|
11
11
|
| Change localhost/HTTPS access | [Access changes](#access-changes) |
|
|
12
12
|
| Back up or restore a database | [Database commands](#database-commands) |
|
|
13
|
+
| Discard old telemetry history only | [Database commands](#database-commands) |
|
|
13
14
|
| Plan what to back up | [Consistent backup set](#consistent-backup-set) |
|
|
14
15
|
| Handle a full database or queue | [Storage pressure recovery](#storage-budgets-and-pressure-recovery) |
|
|
15
16
|
|
|
@@ -369,6 +370,11 @@ node dist/ops.cjs restore \
|
|
|
369
370
|
--database /path/telemetry.sqlite \
|
|
370
371
|
--replace --confirm-stopped
|
|
371
372
|
|
|
373
|
+
# Discard only telemetry history, preserving users/enrollment/settings/alerts.
|
|
374
|
+
node dist/ops.cjs reset-telemetry \
|
|
375
|
+
--database /path/telemetry.sqlite \
|
|
376
|
+
--backup-dir /path/private-backups --confirm-stopped
|
|
377
|
+
|
|
372
378
|
# Offline managed-user recovery; password comes from a private 0600 file.
|
|
373
379
|
node dist/ops.cjs recover-admin \
|
|
374
380
|
--database /path/telemetry.sqlite \
|
|
@@ -408,8 +414,9 @@ release must never be pointed at a newer schema. `inspect` reports this state.
|
|
|
408
414
|
|
|
409
415
|
The database backup is not the whole installation. A restorable set is:
|
|
410
416
|
|
|
411
|
-
1. Hub SQLite database: `telemetry.sqlite` (includes registry/admin/alerts
|
|
412
|
-
Use `ops backup`; do not copy the main file
|
|
417
|
+
1. Hub SQLite database: `telemetry.sqlite` (includes registry/admin/alerts and
|
|
418
|
+
any opt-in persistent history). Use `ops backup`; do not copy the main file
|
|
419
|
+
alone while the hub is running.
|
|
413
420
|
2. Enrollment/config state when configured: `HUB_STATE_FILE` (for
|
|
414
421
|
example `hub/enrollment.json`, the import source for previously enrolled
|
|
415
422
|
collectors) and the private hub environment file. These
|
|
@@ -420,6 +427,9 @@ The database backup is not the whole installation. A restorable set is:
|
|
|
420
427
|
deduplicates by collector/run/sequence.
|
|
421
428
|
5. Optional operational metadata: `install-state.json`, units and the built
|
|
422
429
|
release. Keep the release matching the database schema for rollback.
|
|
430
|
+
6. Explicit recordings: the private `HUB_RECORDINGS_DIR` (default
|
|
431
|
+
`<hub database directory>/recordings`) if you want downloadable captures to
|
|
432
|
+
survive a restore. They are user output, not part of the database backup.
|
|
423
433
|
|
|
424
434
|
For a consistent set, prefer stopping both services cleanly, then run the online
|
|
425
435
|
database backup and copy the other private files. For an online backup, the SQLite
|
|
@@ -486,7 +496,18 @@ node dist/ops.cjs measure --machines 2 --batches 30 --records-per-batch 5 \
|
|
|
486
496
|
It writes synthetic records through the real `TelemetryStore` into a
|
|
487
497
|
temporary private database and reports accepted/rejected/busy counts, ingestion
|
|
488
498
|
latency, event-loop delay/utilization, RSS, database/WAL size, store queue and
|
|
489
|
-
flush counters, and one history-query latency.
|
|
499
|
+
flush counters, and one history-query latency.
|
|
500
|
+
|
|
501
|
+
For the history-mode tradeoff, use the repeatable RAM-vs-persistent benchmark.
|
|
502
|
+
It measures process-attributed disk writes, latency, RSS and rows:
|
|
503
|
+
|
|
504
|
+
```sh
|
|
505
|
+
npm run benchmark:telemetry -- --machines 2 --seconds 120
|
|
506
|
+
npm run benchmark:telemetry -- --machines 10 --seconds 60 --json
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Use `--dir` on a real filesystem; tmpfs does not account storage writes in
|
|
510
|
+
`/proc/self/io`. See [telemetry storage](telemetry-storage.md#benchmark). The output is labelled synthetic.
|
|
490
511
|
Defaults are intentionally small; upper bounds are 1,000 machines, 2,000 batches,
|
|
491
512
|
32 records per batch and 100,000 records total. It never opens a service socket
|
|
492
513
|
or contacts a hub. `--keep` retains the temporary directory for inspection. The
|
|
@@ -536,12 +557,20 @@ cadence, inventory and metadata through Sample ingestion while retaining a
|
|
|
536
557
|
disconnected state until an authenticated Collector reconnects.
|
|
537
558
|
|
|
538
559
|
The default hub main-file plus WAL budget is 2 GiB, shared by every SQLite table.
|
|
539
|
-
The main file has a page-count limit; WAL reserves up to 128 MiB inside that budget
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
560
|
+
The main file has a page-count limit; WAL reserves up to 128 MiB inside that budget
|
|
561
|
+
and automatic checkpointing waits for a meaningful 32–64 MiB reserve where the
|
|
562
|
+
budget permits. Persistent-mode writes return busy on pressure or SQLITE_FULL,
|
|
563
|
+
with no receipt/ack for a failed transaction. Retention reclaims old raw or
|
|
564
|
+
ten-second points and one-minute rollups in bounded chunks while preserving the
|
|
565
|
+
newest hour; hourly rollups retain their configured age window. A full
|
|
566
|
+
newest-hour working set must fit the deployment's budget. Outboxes retry while
|
|
567
|
+
the operator frees space or provisions a larger supported configuration.
|
|
568
|
+
|
|
569
|
+
Memory mode keeps only a bounded RAM budget (`HUB_HISTORY_MEMORY_BYTES`, default
|
|
570
|
+
128 MiB). It does not write routine telemetry rows, but existing historical rows
|
|
571
|
+
from an older installation still occupy the database until removed with
|
|
572
|
+
`ops reset-telemetry` while the hub is stopped. That command preserves users,
|
|
573
|
+
credentials, enrollment, settings, alert state, metadata and inventory.
|
|
545
574
|
|
|
546
575
|
Collector defaults are 64 MiB logical JSON and 80 MiB physical main+WAL per hub,
|
|
547
576
|
256 MiB logical and 640 MiB physical across eight destinations. Physical pressure
|
package/docs/releasing.md
CHANGED
|
@@ -5,7 +5,7 @@ The first public version, `0.1.0`, is published on
|
|
|
5
5
|
[GitHub](https://github.com/Triet1402/rigscope). The package includes MIT licensing,
|
|
6
6
|
dependency notices, the security policy and [release notes](../CHANGELOG.md).
|
|
7
7
|
|
|
8
|
-
The commands below use `0.1.
|
|
8
|
+
The commands below use `0.1.8` as an example. For a new release, substitute its
|
|
9
9
|
new version everywhere; do not attempt to republish an already published version.
|
|
10
10
|
Documentation edits can be committed and pushed to GitHub independently. The published archive and
|
|
11
11
|
its bundled documentation stay unchanged; ship updated package documentation
|
|
@@ -21,7 +21,7 @@ with the next version. Keep each release tag on the revision used to build it.
|
|
|
21
21
|
4. Run the publish dry run, check the npm account, and publish the verified archive.
|
|
22
22
|
5. Verify the registry version and install it into a disposable test installation.
|
|
23
23
|
Check sign-in, fresh telemetry and the installed command.
|
|
24
|
-
6. Tag the exact source revision as `v0.1.
|
|
24
|
+
6. Tag the exact source revision as `v0.1.8`, push the tag, and create a GitHub
|
|
25
25
|
Release with the release notes, verified archive and checksum. Announce it
|
|
26
26
|
after the registry installation works.
|
|
27
27
|
|
|
@@ -45,14 +45,14 @@ npm pack --pack-destination out/release
|
|
|
45
45
|
`npm pack` runs `prepack`, which regenerates dependency notices, builds fresh
|
|
46
46
|
runtime/UI artifacts and verifies them. If notice generation changes a tracked
|
|
47
47
|
file, include that change in the release commit before producing the final
|
|
48
|
-
archive. Reuse the archive for every check below. Replace `0.1.
|
|
48
|
+
archive. Reuse the archive for every check below. Replace `0.1.8` in these
|
|
49
49
|
commands when releasing another version.
|
|
50
50
|
|
|
51
51
|
## Verify the exact archive
|
|
52
52
|
|
|
53
53
|
```sh
|
|
54
|
-
node scripts/verify-package.cjs ./out/release/rigscope-0.1.
|
|
55
|
-
npm run verify:installed -- --archive ./out/release/rigscope-0.1.
|
|
54
|
+
node scripts/verify-package.cjs ./out/release/rigscope-0.1.8.tgz
|
|
55
|
+
npm run verify:installed -- --archive ./out/release/rigscope-0.1.8.tgz
|
|
56
56
|
npm test
|
|
57
57
|
node scripts/test-runtime.cjs
|
|
58
58
|
node scripts/test.cjs --suite development
|
|
@@ -69,9 +69,9 @@ create disposable installations with separate state, launchers, ports and unit
|
|
|
69
69
|
names, then remove their services. They do not select an existing installation.
|
|
70
70
|
|
|
71
71
|
```sh
|
|
72
|
-
RIGSCOPE_TEST_ARCHIVE="$PWD/out/release/rigscope-0.1.
|
|
72
|
+
RIGSCOPE_TEST_ARCHIVE="$PWD/out/release/rigscope-0.1.8.tgz" \
|
|
73
73
|
node --import tsx --test tests/cli-install.integration.ts tests/cli-reset.integration.ts
|
|
74
|
-
node scripts/verify-operations.cjs ./out/release/rigscope-0.1.
|
|
74
|
+
node scripts/verify-operations.cjs ./out/release/rigscope-0.1.8.tgz
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
These cover installation, pairing, independent component controls, bootstrap
|
|
@@ -93,7 +93,7 @@ Record the final checksum after verification:
|
|
|
93
93
|
|
|
94
94
|
```sh
|
|
95
95
|
cd out/release
|
|
96
|
-
sha256sum rigscope-0.1.
|
|
96
|
+
sha256sum rigscope-0.1.8.tgz > SHA256SUMS
|
|
97
97
|
sha256sum --check SHA256SUMS
|
|
98
98
|
```
|
|
99
99
|
|
|
@@ -110,7 +110,7 @@ then verify the account and preview the exact archive:
|
|
|
110
110
|
```sh
|
|
111
111
|
npm login --registry=https://registry.npmjs.org
|
|
112
112
|
npm whoami --registry=https://registry.npmjs.org
|
|
113
|
-
npm publish ./out/release/rigscope-0.1.
|
|
113
|
+
npm publish ./out/release/rigscope-0.1.8.tgz --access public --tag latest \
|
|
114
114
|
--registry=https://registry.npmjs.org --dry-run
|
|
115
115
|
```
|
|
116
116
|
|
|
@@ -120,12 +120,12 @@ to publish or complete two-factor authentication.
|
|
|
120
120
|
When releasing, this command actually publishes the verified archive publicly:
|
|
121
121
|
|
|
122
122
|
```sh
|
|
123
|
-
npm publish ./out/release/rigscope-0.1.
|
|
123
|
+
npm publish ./out/release/rigscope-0.1.8.tgz --access public --tag latest \
|
|
124
124
|
--registry=https://registry.npmjs.org
|
|
125
|
-
npm view rigscope@0.1.
|
|
125
|
+
npm view rigscope@0.1.8 version dist.integrity --registry=https://registry.npmjs.org
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
Then use `npx --yes rigscope@0.1.
|
|
128
|
+
Then use `npx --yes rigscope@0.1.8 install` with a disposable `--state-dir`, an
|
|
129
129
|
unused `--port` and an isolated `XDG_BIN_HOME` for the registry installation
|
|
130
130
|
check. Uninstall that test installation afterward. Use the same isolation
|
|
131
131
|
settings for all test commands so the check does not select a real installation.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Telemetry storage, history and recording
|
|
2
|
+
|
|
3
|
+
Rigscope has two explicit telemetry-history modes. The default is RAM-only.
|
|
4
|
+
Persistent history is opt-in and writes compact summaries, not one row per
|
|
5
|
+
collector reading.
|
|
6
|
+
|
|
7
|
+
> "No persistent telemetry history" is accurate for memory mode. It is not a
|
|
8
|
+
> promise of zero disk writes: hub logs, SQLite control state, alert state,
|
|
9
|
+
> recordings and operating-system swap may still write.
|
|
10
|
+
|
|
11
|
+
Configuration and non-history state always remain in SQLite: users, password
|
|
12
|
+
hashes, sessions' audit records, collector enrollment and credentials, grants,
|
|
13
|
+
alert rules/incidents/jobs/webhook settings, machine display names/tags, and
|
|
14
|
+
inventory. Only telemetry history is ephemeral by default.
|
|
15
|
+
|
|
16
|
+
## Modes
|
|
17
|
+
|
|
18
|
+
| | `HUB_TELEMETRY_MODE=memory` (default) | `HUB_TELEMETRY_MODE=persistent` |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Live readings | Updated immediately in RAM | Updated immediately in RAM |
|
|
21
|
+
| Recent charts | Bounded typed-array RAM rings | Compact worst-case summaries in SQLite |
|
|
22
|
+
| Ack meaning | Accepted into hub RAM; intentional loss on restart | Committed transaction; durable delivery |
|
|
23
|
+
| Restart | History and latest snapshots disappear | Summaries and latest snapshots restore |
|
|
24
|
+
| Routine telemetry writes | None | One transaction roughly every 5 seconds |
|
|
25
|
+
| Deduplication | Per-run in-RAM interval set | `sample_receipts` with an independent 7-day TTL |
|
|
26
|
+
|
|
27
|
+
The hub sends `delivery: "memory"` or `"durable"` in `welcome`. Collectors keep
|
|
28
|
+
the same durable per-destination outbox, retry and in-flight behavior in both
|
|
29
|
+
cases, so delayed acknowledgements do not move sustained writes from the hub to
|
|
30
|
+
the collectors.
|
|
31
|
+
|
|
32
|
+
### Memory history defaults
|
|
33
|
+
|
|
34
|
+
The RAM budget is `HUB_HISTORY_MEMORY_BYTES` (default **128 MiB**) for the whole
|
|
35
|
+
hub, not per machine. Within it, each series keeps:
|
|
36
|
+
|
|
37
|
+
| Tier | Default retention | Purpose |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| 1 second | 2 minutes | Short incident lead-up |
|
|
40
|
+
| 10 seconds | 1 hour | Recent troubleshooting |
|
|
41
|
+
| 1 minute | 24 hours | Medium-term history |
|
|
42
|
+
| 1 hour | 7 days | Longer-term trends |
|
|
43
|
+
|
|
44
|
+
Per-core CPU uses shorter detail: 10-second buckets for 10 minutes, 1-minute for
|
|
45
|
+
6 hours and 1-hour for 2 days. Other metrics use the table above.
|
|
46
|
+
|
|
47
|
+
Each reading updates the current bucket of each applicable tier. Buckets keep
|
|
48
|
+
`min`, `max`, `sum`, non-null `count` and an explicit unavailable `nullCount`, so
|
|
49
|
+
a one-second spike is still represented after it is aggregated into a minute or
|
|
50
|
+
hour. This is aggregation, not "keep every tenth sample". Empty buckets are
|
|
51
|
+
omitted; an all-unavailable bucket renders as unknown, never zero.
|
|
52
|
+
|
|
53
|
+
All current metrics are gauges or already-derived rates: the collector computes
|
|
54
|
+
network/disk bytes per second from monotonic counters before sending, so the hub
|
|
55
|
+
never averages a cumulative counter and does not need first/last values for rate
|
|
56
|
+
reconstruction. If a cumulative counter metric is added later, it needs an
|
|
57
|
+
explicit delta/first-last aggregation policy rather than this gauge path.
|
|
58
|
+
|
|
59
|
+
When a new series would exceed the global budget, the least-recently-seen series
|
|
60
|
+
lose their finest tiers first, then whole series are evicted. New cardinality
|
|
61
|
+
that still does not fit is rejected and reported as pressure. This makes the
|
|
62
|
+
budget finite even for a machine that adds hundreds of disks or cores.
|
|
63
|
+
|
|
64
|
+
### Persistent summary history
|
|
65
|
+
|
|
66
|
+
Persistent mode buffers ingestion and commits all series for roughly five
|
|
67
|
+
seconds in one transaction. It writes `points_10s` plus folded one-minute and
|
|
68
|
+
one-hour rollups. It does **not** write `points_raw` unless an operator
|
|
69
|
+
explicitly constructs the store in raw mode (used by tests and measurement).
|
|
70
|
+
|
|
71
|
+
- Live publication is decoupled from the commit, so the dashboard is not one
|
|
72
|
+
flush behind.
|
|
73
|
+
- A sample is acknowledged only after `COMMIT` returns with `synchronous=FULL`.
|
|
74
|
+
- Retries are deduplicated by `(collectorId, runId, sequence)` before any
|
|
75
|
+
point/rollup side effect. Committed records cannot be counted twice.
|
|
76
|
+
- After a crash, uncommitted buffered samples are replayed by the collector
|
|
77
|
+
because they were never acknowledged. Committed samples have receipts.
|
|
78
|
+
- A graceful shutdown flushes pending summaries before closing within the hub's
|
|
79
|
+
bounded shutdown window.
|
|
80
|
+
- Late/replayed samples extend the correct immutable summary bucket; the
|
|
81
|
+
one-minute and one-hour rows receive only the new delta, never a recomputed
|
|
82
|
+
total. Out-of-order samples inside the retained RAM ring update the matching
|
|
83
|
+
completed bucket; samples older than the retained window are counted as late
|
|
84
|
+
and dropped rather than corrupting a newer bucket.
|
|
85
|
+
- Buckets use absolute minute/hour boundaries. A query includes the current
|
|
86
|
+
partial window once, and a later query recomputes only that bucket from the
|
|
87
|
+
same summaries, so completed data is not double-counted.
|
|
88
|
+
- Flush failures resolve pending batches as retry/busy, so collectors keep the
|
|
89
|
+
data and back off. The queue is bounded (`HUB` storage queue and the
|
|
90
|
+
collector's in-flight window) and does not grow without limit.
|
|
91
|
+
- The collector's local in-flight window and the hub's welcome window are both
|
|
92
|
+
64 batches, the wire maximum. The hub's persistent flush interval is capped
|
|
93
|
+
at five seconds, which fits that window at the fastest supported 100 ms
|
|
94
|
+
cadence (6.4 s of coverage) and leaves 1.4 s for COMMIT/ack latency; it is
|
|
95
|
+
also far below the collector's 30-second per-batch ack timeout. The
|
|
96
|
+
collector reserves enough slots for a full flush window of live samples,
|
|
97
|
+
plus two samples of headroom, and drains a waiting live
|
|
98
|
+
record as soon as an acknowledgement frees capacity. Its durable outbox
|
|
99
|
+
keeps the existing 10-minute/64 MiB per-destination bounds, so delayed acks
|
|
100
|
+
do not turn into sustained collector writes or silent data movement.
|
|
101
|
+
|
|
102
|
+
Dedup receipts default to **7 days** and are independent of chart retention.
|
|
103
|
+
Shortening raw/10-second history can no longer let a replayed sample recreate
|
|
104
|
+
expired chart data.
|
|
105
|
+
|
|
106
|
+
### Which readers exist
|
|
107
|
+
|
|
108
|
+
Charts, exports and recordings all use the same bounded history query interface,
|
|
109
|
+
so memory and persistent modes do not have separate chart code. Query work is
|
|
110
|
+
bounded by series count, scanned rows, elapsed time and output points. The
|
|
111
|
+
finest tier whose retention covers the requested range is selected; an empty
|
|
112
|
+
finer tier falls through to the next one (for example after upgrading an
|
|
113
|
+
existing database).
|
|
114
|
+
|
|
115
|
+
## Recording
|
|
116
|
+
|
|
117
|
+
A recording is an explicit, bounded capture and is separate from chart history.
|
|
118
|
+
|
|
119
|
+
- Start/stop from **History → Recording**.
|
|
120
|
+
- Choose the current machine, selected metrics, resolution (1s, 10s, 1m, 5m or
|
|
121
|
+
1h), duration, and whether to include recent RAM history (the lead-up).
|
|
122
|
+
- The hub writes private JSON-lines data under `HUB_RECORDINGS_DIR`
|
|
123
|
+
(default `<hub database directory>/recordings`, mode 0700 files 0600).
|
|
124
|
+
- Recordings are bounded by `HUB_RECORDING_MAX_DURATION_MS` (default 1 hour) and
|
|
125
|
+
`HUB_RECORDING_MAX_BYTES` (default 64 MiB). A duration or size limit ends the
|
|
126
|
+
capture with an explicit reason.
|
|
127
|
+
- Metadata survives restart. A capture active during a restart is marked
|
|
128
|
+
interrupted and its partial file stays downloadable.
|
|
129
|
+
- Download/list/delete are authenticated and authorized to the creating account
|
|
130
|
+
(administrators can see all) and to the caller's current machine scope. The
|
|
131
|
+
browser names an opaque recording id; it can never name a filesystem path.
|
|
132
|
+
|
|
133
|
+
Recordings are not part of a database-only backup. If they matter, include the
|
|
134
|
+
recordings directory in the same private backup set as the hub database.
|
|
135
|
+
|
|
136
|
+
## Reset old history
|
|
137
|
+
|
|
138
|
+
Switching an existing installation to memory mode does not read or rewrite old
|
|
139
|
+
telemetry rows, but they still occupy the database. To discard them explicitly
|
|
140
|
+
while preserving users, enrollment, settings and alert state:
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
rigscope stop
|
|
144
|
+
node dist/ops.cjs reset-telemetry \
|
|
145
|
+
--database /path/to/telemetry.sqlite \
|
|
146
|
+
--backup-dir /path/to/private-backups \
|
|
147
|
+
--confirm-stopped
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The command deletes only `points_raw`, `points_10s`, `points_1m`, `points_1h`,
|
|
151
|
+
`sample_receipts`, `gaps`, `machine_latest` and `series`. It refuses without
|
|
152
|
+
`--confirm-stopped` and while the hub lock exists. It never drops the database
|
|
153
|
+
file, users, collector registry, alert rules/incidents, metadata, inventory or
|
|
154
|
+
recordings. `--backup-dir` is optional but recommended; a consistent backup is
|
|
155
|
+
taken first when supplied.
|
|
156
|
+
|
|
157
|
+
## Benchmark
|
|
158
|
+
|
|
159
|
+
`npm run benchmark:telemetry -- --machines 2 --seconds 120` drives the real
|
|
160
|
+
stores with a realistic ~186-series-per-machine, one-second payload. It reports
|
|
161
|
+
process-attributed `/proc/self/io` write bytes (not database size), ingestion
|
|
162
|
+
enqueue/commit latency, history-query latency, RSS, row counts and database
|
|
163
|
+
size. `--json` prints machine-readable output; `--dir` selects a real filesystem
|
|
164
|
+
because tmpfs does not account storage writes in `/proc/self/io`.
|
|
165
|
+
|
|
166
|
+
One development-host result for **2 machines × 60 simulated seconds** (186
|
|
167
|
+
series each) was:
|
|
168
|
+
|
|
169
|
+
| Mode | Steady writes | Close/checkpoint | DB size | Commit p95 | History query |
|
|
170
|
+
| --- | --- | --- | --- | --- | --- |
|
|
171
|
+
| memory | **0.00 MiB** | 248 KiB | 0.3 MiB | 42 ms | 3.0 ms |
|
|
172
|
+
| persistent summaries | **0.98 MiB** | 264 KiB | 1.2 MiB | 35 ms | 5.9 ms |
|
|
173
|
+
| legacy raw, per-batch commit | 21.66 MiB | 692 KiB | 21.6 MiB | 15 ms | 6.8 ms |
|
|
174
|
+
|
|
175
|
+
That run measured persistent summaries at about **0.05×** the legacy write
|
|
176
|
+
volume (roughly 22× less) and memory mode at zero sustained ingestion writes.
|
|
177
|
+
|
|
178
|
+
A second run with **10 machines** (1,860 series) and the default 128 MiB RAM
|
|
179
|
+
budget reported `RAM 128/128 MiB pressure` while keeping all series readable
|
|
180
|
+
through the coarser tiers: memory wrote 0.00 MiB, persistent summaries 4.05 MiB,
|
|
181
|
+
and legacy raw 104.76 MiB of steady ingestion-phase writes. RSS peaks include
|
|
182
|
+
the Node baseline and temporary query/flush allocations, so they are higher than
|
|
183
|
+
the history-array budget.
|
|
184
|
+
|
|
185
|
+
These numbers are development-host measurements, not a promised multiplier or
|
|
186
|
+
capacity guarantee. Re-run on the deployment host and payload before choosing
|
|
187
|
+
retention or budgets.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rigscope",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=26.0.0"
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"test": "node scripts/test.cjs",
|
|
23
23
|
"test:runtime": "npm run build:runtime && node scripts/test-runtime.cjs",
|
|
24
24
|
"test:dev": "npm run build:runtime && node scripts/test.cjs --suite development",
|
|
25
|
+
"benchmark:telemetry": "tsx scripts/telemetry-benchmark.ts",
|
|
25
26
|
"validate:https": "node scripts/validate-https.cjs",
|
|
26
27
|
"build:ui": "next build --webpack",
|
|
27
28
|
"rigscope": "node bin/rigscope.cjs",
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"docs/system-installation.md",
|
|
71
72
|
"docs/configuration.md",
|
|
72
73
|
"docs/monitoring.md",
|
|
74
|
+
"docs/telemetry-storage.md",
|
|
73
75
|
"docs/operations.md",
|
|
74
76
|
"docs/bottlenecks.md",
|
|
75
77
|
"docs/exports.md",
|