@camstack/system 1.2.456 → 1.2.457
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/dist/addon-runner.js +96 -10
- package/dist/addon-runner.mjs +96 -10
- package/dist/{agent-https-fm4AR8XL.mjs → agent-https-CK9Z4sSR.mjs} +2 -2
- package/dist/{agent-https-yjxdfJDA.js → agent-https-CoyOZ3pC.js} +2 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +2 -2
- package/dist/builtins/alerts/alerts.addon.mjs +2 -2
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/console-destination.d.ts +1 -2
- package/dist/builtins/console-logging/index.js +1 -4
- package/dist/builtins/console-logging/index.mjs +1 -4
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-history/capture/capture-engine.d.ts +6 -0
- package/dist/builtins/device-history/device-history.addon.js +441 -83
- package/dist/builtins/device-history/device-history.addon.mjs +441 -83
- package/dist/builtins/device-history/query/history-query.d.ts +35 -9
- package/dist/builtins/device-history/query/point-shape.d.ts +33 -0
- package/dist/builtins/device-history/retention/retention.d.ts +1 -1
- package/dist/builtins/device-history/rollup/rollup-engine.d.ts +2 -0
- package/dist/builtins/device-history/rollup/rollup-math.d.ts +6 -0
- package/dist/builtins/device-history/store/history-store.d.ts +7 -0
- package/dist/builtins/device-history/store/series-registry.d.ts +26 -1
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +1 -2
- package/dist/builtins/hub-forwarder/index.js +1 -4
- package/dist/builtins/hub-forwarder/index.mjs +1 -4
- package/dist/builtins/keychain/index.js +4 -4
- package/dist/builtins/keychain/index.mjs +4 -4
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +3 -3
- package/dist/builtins/local-auth/local-auth.addon.mjs +3 -3
- package/dist/builtins/local-network/local-network.addon.js +2 -2
- package/dist/builtins/local-network/local-network.addon.mjs +2 -2
- package/dist/builtins/loki-logging/index.js +323 -7
- package/dist/builtins/loki-logging/index.mjs +323 -7
- package/dist/builtins/loki-logging/loki-destination.d.ts +20 -3
- package/dist/builtins/loki-logging/loki-read.d.ts +51 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +290 -112
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +290 -112
- package/dist/builtins/native-metrics/node-metrics-history-recorder.d.ts +106 -35
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/record-entries/index.js +1 -1
- package/dist/builtins/record-entries/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
- package/dist/builtins/storage-orchestrator/location-history-recorder.d.ts +76 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +9 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +144 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +144 -1
- package/dist/builtins/system-config/system-config.addon.js +3 -3
- package/dist/builtins/system-config/system-config.addon.mjs +3 -3
- package/dist/builtins/winston-logging/index.js +165 -3
- package/dist/builtins/winston-logging/index.mjs +165 -3
- package/dist/builtins/winston-logging/log-file-cursor.d.ts +12 -0
- package/dist/builtins/winston-logging/log-file-index-store.d.ts +11 -0
- package/dist/builtins/winston-logging/log-file-index.d.ts +77 -0
- package/dist/builtins/winston-logging/log-file-read-client.d.ts +44 -0
- package/dist/builtins/winston-logging/log-file-read-protocol.d.ts +41 -0
- package/dist/builtins/winston-logging/log-file-read-worker.d.ts +1 -0
- package/dist/builtins/winston-logging/log-file-reader.d.ts +51 -0
- package/dist/builtins/winston-logging/winston-destination.d.ts +20 -2
- package/dist/{composition-sources-Ds0Vr6eD.mjs → composition-sources-B_jeZDRJ.mjs} +1 -1
- package/dist/{composition-sources-gB4coDJR.js → composition-sources-qKyvMAvc.js} +1 -1
- package/dist/{constants-CavyKfHZ.js → constants-B_X9cWEK.js} +1 -1
- package/dist/{constants-i5oD_gLB.mjs → constants-cxKcZRMi.mjs} +1 -1
- package/dist/{device-ca-qz1Pmeu1.mjs → device-ca-BB6nHAL5.mjs} +1 -1
- package/dist/{device-ca-bpoEr0zG.js → device-ca-CVK3YcR_.js} +1 -1
- package/dist/{dist-BpqA2CT0.js → dist-C89nqNnn.js} +471 -47
- package/dist/{dist-BSF_C8W2.mjs → dist-Dhux90yB.mjs} +454 -48
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/{hub-mdns-ciao-CHaGDzyz.mjs → hub-mdns-ciao-B8olZqqd.mjs} +2 -2
- package/dist/{hub-mdns-ciao-CZlZRxxA.js → hub-mdns-ciao-DB1Y9agt.js} +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +135 -20
- package/dist/index.mjs +129 -21
- package/dist/kernel/config-schema.d.ts +5 -0
- package/dist/kernel/moleculer/accessory-prune-gate.d.ts +55 -0
- package/dist/log-file-read-protocol-B7M3X3bT.mjs +785 -0
- package/dist/log-file-read-protocol-D0WcLbIV.js +817 -0
- package/dist/log-file-read-worker.js +64 -0
- package/dist/log-file-read-worker.mjs +64 -0
- package/dist/log-read-filter-Bi066jwU.js +134 -0
- package/dist/log-read-filter-D7Ev3zm-.mjs +93 -0
- package/dist/logging/log-manager.d.ts +10 -6
- package/dist/logging/log-read-filter.d.ts +43 -0
- package/dist/{phase6-declare-gate-n-IZRklX.js → phase6-declare-gate-BO-_jLh_.js} +1 -1
- package/dist/{phase6-declare-gate-B4yfsf2n.mjs → phase6-declare-gate-x9ZCbQJP.mjs} +1 -1
- package/dist/{restore-archive-B4QG7XmX.js → restore-archive-4DOUR5Gu.js} +1 -1
- package/dist/{restore-archive-BGUM4FKf.mjs → restore-archive-DyOaPeAr.mjs} +1 -1
- package/dist/{wal-maintenance-AerF4XE6.mjs → wal-maintenance-BMiX6UIa.mjs} +0 -0
- package/dist/{wal-maintenance-CNEs_I94.js → wal-maintenance-DVN-DiVP.js} +0 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Gn as metricsProviderCapability, Hi as createEvent, Oa as EventCategory, _t as UNATTRIBUTED_BUCKET_KEY, gn as foldSnapshotByFunction, lr as resolveBucketMs, ni as BaseAddon, or as reducePoints, rt as ROOT_BUCKET_KEY, ti as errMsg } from "../../dist-Dhux90yB.mjs";
|
|
2
2
|
import { access, readFile, readdir } from "node:fs/promises";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import * as os$1 from "node:os";
|
|
@@ -1020,16 +1020,107 @@ function mergeLoadSeries(input) {
|
|
|
1020
1020
|
}
|
|
1021
1021
|
//#endregion
|
|
1022
1022
|
//#region src/builtins/native-metrics/node-metrics-history-recorder.ts
|
|
1023
|
+
/**
|
|
1024
|
+
* Node load history via device-history (D850, LTS P4) — hub only: the hub's
|
|
1025
|
+
* bus carries every node's snapshots, so the hub's writer is the cluster's.
|
|
1026
|
+
*
|
|
1027
|
+
* Per RUNNER, never per PID. A series was once scoped by process id, and a pid
|
|
1028
|
+
* changes on every runner restart: the hub held ~11.8k node series, most of
|
|
1029
|
+
* them one restart long, and no chart could follow a runner across a respawn.
|
|
1030
|
+
* The scope is now the fold's own function key (`load-series-fold.ts`): the
|
|
1031
|
+
* runner's addon id, or `__root__` / `__unattributed__`, so a runner keeps ONE
|
|
1032
|
+
* series for life and the cold tier folds exactly like the hot ring. The old
|
|
1033
|
+
* `process-*` keys are no longer written; their rows age out by retention.
|
|
1034
|
+
*
|
|
1035
|
+
* Node TOTALS ride the resources snapshot: CPU %, memory %, CPU temperature
|
|
1036
|
+
* and, when the node has one, GPU utilisation and temperature. A reading the
|
|
1037
|
+
* node did not take (`null`) is no point — never 0 (D393).
|
|
1038
|
+
*
|
|
1039
|
+
* The in-memory rings still serve the last hour for charts.
|
|
1040
|
+
*/
|
|
1023
1041
|
var ADDON_ID = "metrics-native";
|
|
1024
|
-
var
|
|
1025
|
-
|
|
1026
|
-
|
|
1042
|
+
var MIB = 1048576;
|
|
1043
|
+
function keyOf(name) {
|
|
1044
|
+
return `addon:${ADDON_ID}/${name}`;
|
|
1045
|
+
}
|
|
1046
|
+
/** Per-runner series (scope = the fold key). */
|
|
1047
|
+
var RUNNER_CPU_MAIN_KEY = keyOf("runner-cpu-main-percent");
|
|
1048
|
+
var RUNNER_CPU_GC_KEY = keyOf("runner-cpu-gc-percent");
|
|
1049
|
+
var RUNNER_CPU_LIFETIME_KEY = keyOf("runner-cpu-lifetime-percent");
|
|
1050
|
+
var RUNNER_RSS_KEY = keyOf("runner-rss-mib");
|
|
1051
|
+
var RUNNER_PROCESSES_KEY = keyOf("runner-processes");
|
|
1052
|
+
/** Node totals (scope ''). */
|
|
1053
|
+
var NODE_CPU_KEY = keyOf("node-cpu-percent");
|
|
1054
|
+
var NODE_MEMORY_KEY = keyOf("node-memory-percent");
|
|
1055
|
+
var NODE_CPU_TEMPERATURE_KEY = keyOf("node-cpu-temperature");
|
|
1056
|
+
var NODE_GPU_KEY = keyOf("node-gpu-percent");
|
|
1057
|
+
var NODE_GPU_TEMPERATURE_KEY = keyOf("node-gpu-temperature");
|
|
1058
|
+
var NODE_CONTAINER_CURRENT_KEY = keyOf("container-current-mib");
|
|
1059
|
+
keyOf("process-cpu-percent");
|
|
1060
|
+
keyOf("process-rss-mib");
|
|
1061
|
+
var DECLARATIONS = [
|
|
1062
|
+
{
|
|
1063
|
+
name: "runner-cpu-main-percent",
|
|
1064
|
+
displayName: "Runner CPU % (main thread)",
|
|
1065
|
+
unit: "%"
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
name: "runner-cpu-gc-percent",
|
|
1069
|
+
displayName: "Runner CPU % (GC)",
|
|
1070
|
+
unit: "%"
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
name: "runner-cpu-lifetime-percent",
|
|
1074
|
+
displayName: "Runner CPU % (lifetime average)",
|
|
1075
|
+
unit: "%"
|
|
1076
|
+
},
|
|
1077
|
+
{
|
|
1078
|
+
name: "runner-rss-mib",
|
|
1079
|
+
displayName: "Runner RSS (MiB)",
|
|
1080
|
+
unit: "MiB"
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
name: "runner-processes",
|
|
1084
|
+
displayName: "Runner processes",
|
|
1085
|
+
unit: "count"
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
name: "node-cpu-percent",
|
|
1089
|
+
displayName: "Node CPU %",
|
|
1090
|
+
unit: "%"
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
name: "node-memory-percent",
|
|
1094
|
+
displayName: "Node memory %",
|
|
1095
|
+
unit: "%"
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
name: "node-cpu-temperature",
|
|
1099
|
+
displayName: "Node CPU temperature",
|
|
1100
|
+
unit: "°C"
|
|
1101
|
+
},
|
|
1102
|
+
{
|
|
1103
|
+
name: "node-gpu-percent",
|
|
1104
|
+
displayName: "Node GPU %",
|
|
1105
|
+
unit: "%"
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
name: "node-gpu-temperature",
|
|
1109
|
+
displayName: "Node GPU temperature",
|
|
1110
|
+
unit: "°C"
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
name: "container-current-mib",
|
|
1114
|
+
displayName: "Container memory current (MiB)",
|
|
1115
|
+
unit: "MiB"
|
|
1116
|
+
}
|
|
1117
|
+
];
|
|
1027
1118
|
function nodeMetricsHistoryClient(api) {
|
|
1028
1119
|
return {
|
|
1029
1120
|
declareSeries: (input) => api.declareSeries.mutate(input),
|
|
1030
1121
|
record: (input) => api.record.mutate({ points: [...input.points] }),
|
|
1031
1122
|
queryNode: async (input) => {
|
|
1032
|
-
return { series: (await api.queryNode.query(input)).series.map((s) => ({
|
|
1123
|
+
return { series: (await api.queryNode.query({ ...input })).series.map((s) => ({
|
|
1033
1124
|
scope: s.scope,
|
|
1034
1125
|
points: s.points.map((p) => ({
|
|
1035
1126
|
t: p.t,
|
|
@@ -1045,78 +1136,112 @@ function refusalCounts(result) {
|
|
|
1045
1136
|
for (const r of result.refused) counts[r.reason] = (counts[r.reason] ?? 0) + r.count;
|
|
1046
1137
|
return counts;
|
|
1047
1138
|
}
|
|
1139
|
+
/** The fold's function key of a process: the same rule as `foldSnapshotByFunction`. */
|
|
1140
|
+
function runnerScopeOf(process) {
|
|
1141
|
+
if (process.addonId !== null) return process.addonId;
|
|
1142
|
+
return process.classification === "root" ? ROOT_BUCKET_KEY : UNATTRIBUTED_BUCKET_KEY;
|
|
1143
|
+
}
|
|
1144
|
+
function round1(value) {
|
|
1145
|
+
return Math.round(value * 10) / 10;
|
|
1146
|
+
}
|
|
1048
1147
|
var NodeMetricsHistoryRecorder = class {
|
|
1049
1148
|
deps;
|
|
1050
1149
|
declared = false;
|
|
1150
|
+
lastTotalsAt = /* @__PURE__ */ new Map();
|
|
1151
|
+
/** A not-ready skip was logged and device-history has not been ready since. */
|
|
1152
|
+
waitLogged = false;
|
|
1051
1153
|
constructor(deps) {
|
|
1052
1154
|
this.deps = deps;
|
|
1053
1155
|
}
|
|
1054
1156
|
async declare() {
|
|
1055
1157
|
if (this.declared) return;
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
name: "process-cpu-percent",
|
|
1158
|
+
for (const d of DECLARATIONS) await this.deps.deviceHistory.declareSeries({
|
|
1159
|
+
name: d.name,
|
|
1059
1160
|
subjectKind: "node",
|
|
1060
1161
|
kind: "gauge",
|
|
1061
|
-
displayName:
|
|
1162
|
+
displayName: d.displayName,
|
|
1062
1163
|
ingest: "points",
|
|
1063
|
-
unit:
|
|
1064
|
-
});
|
|
1065
|
-
await deviceHistory.declareSeries({
|
|
1066
|
-
name: "process-rss-mib",
|
|
1067
|
-
subjectKind: "node",
|
|
1068
|
-
kind: "gauge",
|
|
1069
|
-
displayName: "Process RSS (MiB)",
|
|
1070
|
-
ingest: "points",
|
|
1071
|
-
unit: "MiB"
|
|
1072
|
-
});
|
|
1073
|
-
await deviceHistory.declareSeries({
|
|
1074
|
-
name: "container-current-mib",
|
|
1075
|
-
subjectKind: "node",
|
|
1076
|
-
kind: "gauge",
|
|
1077
|
-
displayName: "Container memory current (MiB)",
|
|
1078
|
-
ingest: "points",
|
|
1079
|
-
unit: "MiB"
|
|
1164
|
+
unit: d.unit
|
|
1080
1165
|
});
|
|
1081
1166
|
this.declared = true;
|
|
1082
1167
|
}
|
|
1168
|
+
/** One process snapshot: per-runner sums plus the container's memory. */
|
|
1083
1169
|
async recordSample(nodeId, atMs, processes, containerMemory) {
|
|
1084
|
-
|
|
1085
|
-
|
|
1170
|
+
const subject = {
|
|
1171
|
+
kind: "node",
|
|
1172
|
+
nodeId
|
|
1173
|
+
};
|
|
1174
|
+
const point = (key, scope, value) => ({
|
|
1175
|
+
key,
|
|
1176
|
+
subject,
|
|
1177
|
+
scope,
|
|
1178
|
+
ts: atMs,
|
|
1179
|
+
value
|
|
1180
|
+
});
|
|
1181
|
+
const byRunner = /* @__PURE__ */ new Map();
|
|
1086
1182
|
for (const p of processes) {
|
|
1087
|
-
const scope =
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1183
|
+
const scope = runnerScopeOf(p);
|
|
1184
|
+
const t = byRunner.get(scope) ?? {
|
|
1185
|
+
main: 0,
|
|
1186
|
+
gc: 0,
|
|
1187
|
+
splitKnown: true,
|
|
1188
|
+
lifetime: 0,
|
|
1189
|
+
rss: 0,
|
|
1190
|
+
count: 0
|
|
1191
|
+
};
|
|
1192
|
+
const known = p.cpuMainPercent !== null && p.cpuGcPercent !== null;
|
|
1193
|
+
byRunner.set(scope, {
|
|
1194
|
+
main: t.main + (p.cpuMainPercent ?? 0),
|
|
1195
|
+
gc: t.gc + (p.cpuGcPercent ?? 0),
|
|
1196
|
+
splitKnown: t.splitKnown && known,
|
|
1197
|
+
lifetime: t.lifetime + p.cpuPercent,
|
|
1198
|
+
rss: t.rss + p.memoryRssBytes,
|
|
1199
|
+
count: t.count + 1
|
|
1097
1200
|
});
|
|
1201
|
+
}
|
|
1202
|
+
const points = [];
|
|
1203
|
+
for (const [scope, t] of byRunner) {
|
|
1204
|
+
if (t.splitKnown) {
|
|
1205
|
+
points.push(point(RUNNER_CPU_MAIN_KEY, scope, round1(t.main)));
|
|
1206
|
+
points.push(point(RUNNER_CPU_GC_KEY, scope, round1(t.gc)));
|
|
1207
|
+
}
|
|
1208
|
+
points.push(point(RUNNER_CPU_LIFETIME_KEY, scope, round1(t.lifetime)));
|
|
1209
|
+
points.push(point(RUNNER_RSS_KEY, scope, Math.round(t.rss / MIB)));
|
|
1210
|
+
points.push(point(RUNNER_PROCESSES_KEY, scope, t.count));
|
|
1211
|
+
}
|
|
1212
|
+
if (containerMemory !== null) points.push(point(NODE_CONTAINER_CURRENT_KEY, "", Math.round(containerMemory.currentBytes / MIB)));
|
|
1213
|
+
await this.write(nodeId, atMs, points);
|
|
1214
|
+
}
|
|
1215
|
+
/** One resources snapshot: the node's totals, at most every {@link NODE_TOTALS_MIN_INTERVAL_MS}. */
|
|
1216
|
+
async recordTotals(nodeId, atMs, snapshot) {
|
|
1217
|
+
const last = this.lastTotalsAt.get(nodeId);
|
|
1218
|
+
if (last !== void 0 && atMs >= last && atMs - last < 15e3) return;
|
|
1219
|
+
this.lastTotalsAt.set(nodeId, atMs);
|
|
1220
|
+
const subject = {
|
|
1221
|
+
kind: "node",
|
|
1222
|
+
nodeId
|
|
1223
|
+
};
|
|
1224
|
+
const points = [];
|
|
1225
|
+
const add = (key, value) => {
|
|
1226
|
+
if (value === null || !Number.isFinite(value)) return;
|
|
1098
1227
|
points.push({
|
|
1099
|
-
key
|
|
1100
|
-
subject
|
|
1101
|
-
|
|
1102
|
-
nodeId
|
|
1103
|
-
},
|
|
1104
|
-
scope,
|
|
1228
|
+
key,
|
|
1229
|
+
subject,
|
|
1230
|
+
scope: "",
|
|
1105
1231
|
ts: atMs,
|
|
1106
|
-
value:
|
|
1232
|
+
value: round1(value)
|
|
1107
1233
|
});
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
value: Math.round(containerMemory.currentBytes / 1048576)
|
|
1118
|
-
});
|
|
1234
|
+
};
|
|
1235
|
+
add(NODE_CPU_KEY, snapshot.cpu.total);
|
|
1236
|
+
add(NODE_MEMORY_KEY, snapshot.memory.percent);
|
|
1237
|
+
add(NODE_CPU_TEMPERATURE_KEY, snapshot.cpuTemperature);
|
|
1238
|
+
add(NODE_GPU_KEY, snapshot.gpu?.utilization ?? null);
|
|
1239
|
+
add(NODE_GPU_TEMPERATURE_KEY, snapshot.gpu?.temperature ?? null);
|
|
1240
|
+
await this.write(nodeId, atMs, points);
|
|
1241
|
+
}
|
|
1242
|
+
async write(nodeId, atMs, points) {
|
|
1119
1243
|
if (points.length === 0) return;
|
|
1244
|
+
if (!await this.ensureDeclared()) return;
|
|
1120
1245
|
try {
|
|
1121
1246
|
const result = await this.deps.deviceHistory.record({ points });
|
|
1122
1247
|
if (result.refused.length > 0) {
|
|
@@ -1138,7 +1263,7 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1138
1263
|
async readContainerPoints(nodeId, sinceMs, maxPoints) {
|
|
1139
1264
|
if (!await this.ensureDeclared()) return [];
|
|
1140
1265
|
const result = await this.deps.deviceHistory.queryNode({
|
|
1141
|
-
nodeId,
|
|
1266
|
+
forNodeId: nodeId,
|
|
1142
1267
|
key: NODE_CONTAINER_CURRENT_KEY,
|
|
1143
1268
|
from: sinceMs + 1,
|
|
1144
1269
|
to: Date.now(),
|
|
@@ -1151,7 +1276,7 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1151
1276
|
out.push({
|
|
1152
1277
|
atMs: p.t,
|
|
1153
1278
|
source: "cgroup-v2",
|
|
1154
|
-
currentBytes: p.value *
|
|
1279
|
+
currentBytes: p.value * MIB,
|
|
1155
1280
|
limitBytes: null,
|
|
1156
1281
|
anonBytes: null,
|
|
1157
1282
|
fileBytes: null,
|
|
@@ -1162,63 +1287,46 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1162
1287
|
}
|
|
1163
1288
|
return out.toSorted((a, b) => a.atMs - b.atMs);
|
|
1164
1289
|
}
|
|
1290
|
+
/**
|
|
1291
|
+
* The cold tier as process samples the fold reads like the hot ring's. A
|
|
1292
|
+
* runner's sums come back as `processes` equal rows (sums preserved, count
|
|
1293
|
+
* right); its CPU split is `null` where it was not recorded.
|
|
1294
|
+
*/
|
|
1165
1295
|
async readProcessSamples(nodeId, sinceMs, maxPoints) {
|
|
1166
1296
|
if (!await this.ensureDeclared()) return [];
|
|
1167
1297
|
const to = Date.now();
|
|
1168
|
-
const
|
|
1169
|
-
nodeId,
|
|
1170
|
-
key
|
|
1298
|
+
const read = (key) => this.deps.deviceHistory.queryNode({
|
|
1299
|
+
forNodeId: nodeId,
|
|
1300
|
+
key,
|
|
1171
1301
|
from: sinceMs + 1,
|
|
1172
1302
|
to,
|
|
1173
1303
|
resolution: "raw",
|
|
1174
1304
|
maxPoints
|
|
1175
|
-
})
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
let perPid = byAt.get(p.t);
|
|
1191
|
-
if (perPid === void 0) {
|
|
1192
|
-
perPid = /* @__PURE__ */ new Map();
|
|
1193
|
-
byAt.set(p.t, perPid);
|
|
1194
|
-
}
|
|
1195
|
-
const base = perPid.get(pid) ?? {
|
|
1196
|
-
pid,
|
|
1197
|
-
addonId: null,
|
|
1198
|
-
classification: "managed",
|
|
1199
|
-
cpuPercent: 0,
|
|
1200
|
-
memoryRssBytes: 0,
|
|
1201
|
-
cpuMainPercent: null,
|
|
1202
|
-
cpuGcPercent: null
|
|
1203
|
-
};
|
|
1204
|
-
perPid.set(pid, field === "cpuPercent" ? {
|
|
1205
|
-
...base,
|
|
1206
|
-
cpuPercent: p.value
|
|
1207
|
-
} : {
|
|
1208
|
-
...base,
|
|
1209
|
-
memoryRssBytes: p.value * 1048576
|
|
1210
|
-
});
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
};
|
|
1214
|
-
ingest(cpuResult.series, "cpuPercent");
|
|
1215
|
-
ingest(rssResult.series, "memoryRssBytes");
|
|
1216
|
-
return [...byAt.entries()].toSorted((a, b) => a[0] - b[0]).map(([atMs, perPid]) => ({
|
|
1217
|
-
atMs,
|
|
1218
|
-
processes: [...perPid.values()]
|
|
1219
|
-
}));
|
|
1305
|
+
});
|
|
1306
|
+
const [main, gc, lifetime, rss, count] = await Promise.all([
|
|
1307
|
+
read(RUNNER_CPU_MAIN_KEY),
|
|
1308
|
+
read(RUNNER_CPU_GC_KEY),
|
|
1309
|
+
read(RUNNER_CPU_LIFETIME_KEY),
|
|
1310
|
+
read(RUNNER_RSS_KEY),
|
|
1311
|
+
read(RUNNER_PROCESSES_KEY)
|
|
1312
|
+
]);
|
|
1313
|
+
return assembleRunnerSamples({
|
|
1314
|
+
main,
|
|
1315
|
+
gc,
|
|
1316
|
+
lifetime,
|
|
1317
|
+
rss,
|
|
1318
|
+
count
|
|
1319
|
+
});
|
|
1220
1320
|
}
|
|
1221
1321
|
async ensureDeclared() {
|
|
1322
|
+
if (this.deps.historyReady !== void 0 && !this.deps.historyReady()) {
|
|
1323
|
+
if (!this.waitLogged) {
|
|
1324
|
+
this.waitLogged = true;
|
|
1325
|
+
this.deps.logger.info("node metrics history waits for device-history — samples until it is ready are not stored");
|
|
1326
|
+
}
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
this.waitLogged = false;
|
|
1222
1330
|
try {
|
|
1223
1331
|
await this.declare();
|
|
1224
1332
|
return true;
|
|
@@ -1228,6 +1336,55 @@ var NodeMetricsHistoryRecorder = class {
|
|
|
1228
1336
|
}
|
|
1229
1337
|
}
|
|
1230
1338
|
};
|
|
1339
|
+
/** `atMs -> scope -> value` of one key's answer, finite values only. */
|
|
1340
|
+
function indexAnswer(answer) {
|
|
1341
|
+
const out = /* @__PURE__ */ new Map();
|
|
1342
|
+
for (const s of answer.series) for (const p of s.points) {
|
|
1343
|
+
if (p.value === null || !Number.isFinite(p.value)) continue;
|
|
1344
|
+
const at = out.get(p.t) ?? /* @__PURE__ */ new Map();
|
|
1345
|
+
at.set(s.scope, p.value);
|
|
1346
|
+
out.set(p.t, at);
|
|
1347
|
+
}
|
|
1348
|
+
return out;
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Per-runner cold points back into process rows. A sample exists where the
|
|
1352
|
+
* runner's lifetime CPU and RSS were both recorded (always written together).
|
|
1353
|
+
*/
|
|
1354
|
+
function assembleRunnerSamples(answers) {
|
|
1355
|
+
const main = indexAnswer(answers.main);
|
|
1356
|
+
const gc = indexAnswer(answers.gc);
|
|
1357
|
+
const rss = indexAnswer(answers.rss);
|
|
1358
|
+
const count = indexAnswer(answers.count);
|
|
1359
|
+
const samples = [];
|
|
1360
|
+
for (const [atMs, lifetimeByScope] of indexAnswer(answers.lifetime)) {
|
|
1361
|
+
const processes = [];
|
|
1362
|
+
for (const [scope, lifetime] of lifetimeByScope) {
|
|
1363
|
+
const rssMib = rss.get(atMs)?.get(scope);
|
|
1364
|
+
if (rssMib === void 0) continue;
|
|
1365
|
+
const n = Math.max(1, Math.round(count.get(atMs)?.get(scope) ?? 1));
|
|
1366
|
+
const m = main.get(atMs)?.get(scope);
|
|
1367
|
+
const g = gc.get(atMs)?.get(scope);
|
|
1368
|
+
const split = m !== void 0 && g !== void 0;
|
|
1369
|
+
const isRoot = scope === ROOT_BUCKET_KEY;
|
|
1370
|
+
const isUnattributed = scope === UNATTRIBUTED_BUCKET_KEY;
|
|
1371
|
+
for (let i = 0; i < n; i += 1) processes.push({
|
|
1372
|
+
pid: 0,
|
|
1373
|
+
addonId: isRoot || isUnattributed ? null : scope,
|
|
1374
|
+
classification: isRoot ? "root" : isUnattributed ? "system" : "managed",
|
|
1375
|
+
cpuPercent: lifetime / n,
|
|
1376
|
+
memoryRssBytes: rssMib * MIB / n,
|
|
1377
|
+
cpuMainPercent: split ? m / n : null,
|
|
1378
|
+
cpuGcPercent: split ? g / n : null
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
if (processes.length > 0) samples.push({
|
|
1382
|
+
atMs,
|
|
1383
|
+
processes
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
return samples.toSorted((a, b) => a.atMs - b.atMs);
|
|
1387
|
+
}
|
|
1231
1388
|
//#endregion
|
|
1232
1389
|
//#region src/builtins/native-metrics/gpu-probe.ts
|
|
1233
1390
|
/**
|
|
@@ -2191,6 +2348,8 @@ var ThreadCpuTracker = class {
|
|
|
2191
2348
|
};
|
|
2192
2349
|
//#endregion
|
|
2193
2350
|
//#region src/builtins/native-metrics/native-metrics.addon.ts
|
|
2351
|
+
/** The hub's node id — `isHub` below is the same test; device-history lives there. */
|
|
2352
|
+
var HUB_NODE_ID = "hub";
|
|
2194
2353
|
/**
|
|
2195
2354
|
* Cadence for the per-node metric snapshot bus events. ~5 s matches
|
|
2196
2355
|
* the existing UI polling cadence (ProcessesTab, ProcessResources)
|
|
@@ -2312,7 +2471,7 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
2312
2471
|
}
|
|
2313
2472
|
/** Is this the hub? The same test every other addon uses (`addon-ai`). */
|
|
2314
2473
|
get isHub() {
|
|
2315
|
-
return (this.ctx.kernel.cluster?.broker?.nodeID ??
|
|
2474
|
+
return (this.ctx.kernel.cluster?.broker?.nodeID ?? HUB_NODE_ID) === HUB_NODE_ID;
|
|
2316
2475
|
}
|
|
2317
2476
|
/** Process rows observed across the whole fleet, for the cost projection. */
|
|
2318
2477
|
observedFleetRows() {
|
|
@@ -2363,19 +2522,38 @@ var NativeMetricsAddon = class NativeMetricsAddon extends BaseAddon {
|
|
|
2363
2522
|
};
|
|
2364
2523
|
this.applyLoadSeriesConfig();
|
|
2365
2524
|
if (this.isHub) {
|
|
2366
|
-
|
|
2525
|
+
const historyScope = {
|
|
2526
|
+
type: "node",
|
|
2527
|
+
nodeId: HUB_NODE_ID
|
|
2528
|
+
};
|
|
2529
|
+
const historyHandle = this.ctx.useCapability("device-history", historyScope);
|
|
2530
|
+
const recorder = new NodeMetricsHistoryRecorder({
|
|
2367
2531
|
deviceHistory: nodeMetricsHistoryClient(this.ctx.api.deviceHistory),
|
|
2368
|
-
logger: this.ctx.logger.child("NodeMetricsHistory")
|
|
2369
|
-
|
|
2370
|
-
this.metricsHistory.declare().catch((err) => {
|
|
2371
|
-
this.ctx.logger.warn("node metrics history declare failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
2532
|
+
logger: this.ctx.logger.child("NodeMetricsHistory"),
|
|
2533
|
+
historyReady: () => historyHandle.isReady
|
|
2372
2534
|
});
|
|
2535
|
+
this.metricsHistory = recorder;
|
|
2536
|
+
const declareNow = () => {
|
|
2537
|
+
recorder.declare().catch((err) => {
|
|
2538
|
+
this.ctx.logger.warn("node metrics history declare failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
2539
|
+
});
|
|
2540
|
+
};
|
|
2541
|
+
this.ctx.addDisposer(this.ctx.onCapabilityStateChange("device-history", historyScope, (state) => {
|
|
2542
|
+
if (state === "ready") declareNow();
|
|
2543
|
+
}));
|
|
2544
|
+
if (historyHandle.isReady) declareNow();
|
|
2373
2545
|
}
|
|
2374
2546
|
this.memoryProbe = new ContainerMemoryProbe({ logger: this.ctx.logger.child("ContainerMemory") });
|
|
2375
2547
|
this.pidsProbe = new ContainerPidsProbe({ logger: this.ctx.logger.child("ContainerPids") });
|
|
2376
2548
|
if (this.snapshotTimer) clearInterval(this.snapshotTimer);
|
|
2377
2549
|
this.snapshotTimer = setInterval(() => this.runTick("resources snapshot", () => this.emitResourcesSnapshot()), METRICS_SNAPSHOT_INTERVAL_MS);
|
|
2378
2550
|
this.startProcessSnapshotTimer();
|
|
2551
|
+
if (this.metricsHistory !== null) {
|
|
2552
|
+
const history = this.metricsHistory;
|
|
2553
|
+
this.ctx.addDisposer(this.ctx.eventBus.subscribe({ category: EventCategory.MetricsNodeResourcesSnapshot }, (event) => {
|
|
2554
|
+
history.recordTotals(event.data.nodeId, event.data.timestamp, event.data.snapshot);
|
|
2555
|
+
}));
|
|
2556
|
+
}
|
|
2379
2557
|
this.ctx.addDisposer(this.ctx.eventBus.subscribe({ category: EventCategory.MetricsNodeProcessesSnapshot }, (event) => this.retainSnapshot(event.data.nodeId, event.data.timestamp, event.data.processes, event.data.containerMemory)));
|
|
2380
2558
|
return [{
|
|
2381
2559
|
capability: metricsProviderCapability,
|
|
@@ -1,15 +1,79 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Node
|
|
2
|
+
* Node load history via device-history (D850, LTS P4) — hub only: the hub's
|
|
3
|
+
* bus carries every node's snapshots, so the hub's writer is the cluster's.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* Per RUNNER, never per PID. A series was once scoped by process id, and a pid
|
|
6
|
+
* changes on every runner restart: the hub held ~11.8k node series, most of
|
|
7
|
+
* them one restart long, and no chart could follow a runner across a respawn.
|
|
8
|
+
* The scope is now the fold's own function key (`load-series-fold.ts`): the
|
|
9
|
+
* runner's addon id, or `__root__` / `__unattributed__`, so a runner keeps ONE
|
|
10
|
+
* series for life and the cold tier folds exactly like the hot ring. The old
|
|
11
|
+
* `process-*` keys are no longer written; their rows age out by retention.
|
|
12
|
+
*
|
|
13
|
+
* Node TOTALS ride the resources snapshot: CPU %, memory %, CPU temperature
|
|
14
|
+
* and, when the node has one, GPU utilisation and temperature. A reading the
|
|
15
|
+
* node did not take (`null`) is no point — never 0 (D393).
|
|
16
|
+
*
|
|
17
|
+
* The in-memory rings still serve the last hour for charts.
|
|
6
18
|
*/
|
|
7
|
-
import type
|
|
19
|
+
import { type AddonApi, type ContainerMemoryPoint, type ContainerMemorySnapshot, type DeviceHistoryIngestResult, type IScopedLogger, type SystemResourceSnapshot } from "@camstack/types";
|
|
8
20
|
import type { RetainedProcess, RetainedSample } from "./load-series-types.js";
|
|
9
21
|
declare const ADDON_ID: "metrics-native";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export declare const
|
|
22
|
+
type MetricsKey<N extends string> = `addon:${typeof ADDON_ID}/${N}`;
|
|
23
|
+
/** Per-runner series (scope = the fold key). */
|
|
24
|
+
export declare const RUNNER_CPU_MAIN_KEY: MetricsKey<"runner-cpu-main-percent">;
|
|
25
|
+
export declare const RUNNER_CPU_GC_KEY: MetricsKey<"runner-cpu-gc-percent">;
|
|
26
|
+
export declare const RUNNER_CPU_LIFETIME_KEY: MetricsKey<"runner-cpu-lifetime-percent">;
|
|
27
|
+
export declare const RUNNER_RSS_KEY: MetricsKey<"runner-rss-mib">;
|
|
28
|
+
export declare const RUNNER_PROCESSES_KEY: MetricsKey<"runner-processes">;
|
|
29
|
+
/** Node totals (scope ''). */
|
|
30
|
+
export declare const NODE_CPU_KEY: MetricsKey<"node-cpu-percent">;
|
|
31
|
+
export declare const NODE_MEMORY_KEY: MetricsKey<"node-memory-percent">;
|
|
32
|
+
export declare const NODE_CPU_TEMPERATURE_KEY: MetricsKey<"node-cpu-temperature">;
|
|
33
|
+
export declare const NODE_GPU_KEY: MetricsKey<"node-gpu-percent">;
|
|
34
|
+
export declare const NODE_GPU_TEMPERATURE_KEY: MetricsKey<"node-gpu-temperature">;
|
|
35
|
+
export declare const NODE_CONTAINER_CURRENT_KEY: MetricsKey<"container-current-mib">;
|
|
36
|
+
/**
|
|
37
|
+
* The PID-scoped keys of the earlier build. NOT written any more; kept only so
|
|
38
|
+
* the one-shot split-database migration (`scripts/ops/split-databases`) still
|
|
39
|
+
* names what it once wrote.
|
|
40
|
+
*/
|
|
41
|
+
export declare const NODE_PROCESS_CPU_KEY: MetricsKey<"process-cpu-percent">;
|
|
42
|
+
export declare const NODE_PROCESS_RSS_KEY: MetricsKey<"process-rss-mib">;
|
|
43
|
+
/**
|
|
44
|
+
* Node totals are written at most this often per node. The resources snapshot
|
|
45
|
+
* fires on any coarse change (every 5 s at worst) and device-history refuses a
|
|
46
|
+
* point closer than 10 s to the previous one of its series (`rate`).
|
|
47
|
+
*/
|
|
48
|
+
export declare const NODE_TOTALS_MIN_INTERVAL_MS = 15e3;
|
|
49
|
+
export interface NodeHistoryPoint {
|
|
50
|
+
readonly key: string;
|
|
51
|
+
readonly subject: {
|
|
52
|
+
readonly kind: "node";
|
|
53
|
+
readonly nodeId: string;
|
|
54
|
+
};
|
|
55
|
+
readonly scope: string;
|
|
56
|
+
readonly ts: number;
|
|
57
|
+
readonly value: number;
|
|
58
|
+
}
|
|
59
|
+
export interface NodeHistoryQueryInput {
|
|
60
|
+
readonly forNodeId: string;
|
|
61
|
+
readonly key: string;
|
|
62
|
+
readonly from: number;
|
|
63
|
+
readonly to: number;
|
|
64
|
+
readonly resolution: "raw";
|
|
65
|
+
readonly maxPoints?: number;
|
|
66
|
+
}
|
|
67
|
+
export interface NodeHistoryQueryAnswer {
|
|
68
|
+
readonly series: ReadonlyArray<{
|
|
69
|
+
readonly scope: string;
|
|
70
|
+
readonly points: ReadonlyArray<{
|
|
71
|
+
t: number;
|
|
72
|
+
value: number | null;
|
|
73
|
+
samples: number;
|
|
74
|
+
}>;
|
|
75
|
+
}>;
|
|
76
|
+
}
|
|
13
77
|
export interface NodeMetricsHistoryClient {
|
|
14
78
|
declareSeries(input: {
|
|
15
79
|
name: string;
|
|
@@ -22,49 +86,56 @@ export interface NodeMetricsHistoryClient {
|
|
|
22
86
|
key: string;
|
|
23
87
|
}>;
|
|
24
88
|
record(input: {
|
|
25
|
-
points:
|
|
26
|
-
key: string;
|
|
27
|
-
subject: {
|
|
28
|
-
kind: "node";
|
|
29
|
-
nodeId: string;
|
|
30
|
-
};
|
|
31
|
-
scope: string;
|
|
32
|
-
ts: number;
|
|
33
|
-
value: number;
|
|
34
|
-
}>;
|
|
89
|
+
points: readonly NodeHistoryPoint[];
|
|
35
90
|
}): Promise<DeviceHistoryIngestResult>;
|
|
36
|
-
queryNode(input:
|
|
37
|
-
nodeId: string;
|
|
38
|
-
key: string;
|
|
39
|
-
from: number;
|
|
40
|
-
to: number;
|
|
41
|
-
resolution: "raw";
|
|
42
|
-
maxPoints?: number;
|
|
43
|
-
}): Promise<{
|
|
44
|
-
series: ReadonlyArray<{
|
|
45
|
-
scope: string;
|
|
46
|
-
points: ReadonlyArray<{
|
|
47
|
-
t: number;
|
|
48
|
-
value: number | null;
|
|
49
|
-
samples: number;
|
|
50
|
-
}>;
|
|
51
|
-
}>;
|
|
52
|
-
}>;
|
|
91
|
+
queryNode(input: NodeHistoryQueryInput): Promise<NodeHistoryQueryAnswer>;
|
|
53
92
|
}
|
|
54
|
-
import type { AddonApi } from "@camstack/types";
|
|
55
93
|
export declare function nodeMetricsHistoryClient(api: AddonApi["deviceHistory"]): NodeMetricsHistoryClient;
|
|
56
94
|
export interface NodeMetricsHistoryRecorderDeps {
|
|
57
95
|
readonly deviceHistory: NodeMetricsHistoryClient;
|
|
58
96
|
readonly logger: IScopedLogger;
|
|
97
|
+
/**
|
|
98
|
+
* The registry's answer to "is device-history up?" — read without blocking.
|
|
99
|
+
* While it is not, a sample is not stored (logged once per wait) and no
|
|
100
|
+
* declare is attempted: a declare against an absent provider is a failure
|
|
101
|
+
* line per sample, not a wait. Omitted ⇒ always ready (specs).
|
|
102
|
+
*/
|
|
103
|
+
readonly historyReady?: () => boolean;
|
|
59
104
|
}
|
|
105
|
+
/** The fold's function key of a process: the same rule as `foldSnapshotByFunction`. */
|
|
106
|
+
export declare function runnerScopeOf(process: RetainedProcess): string;
|
|
60
107
|
export declare class NodeMetricsHistoryRecorder {
|
|
61
108
|
private readonly deps;
|
|
62
109
|
private declared;
|
|
110
|
+
private readonly lastTotalsAt;
|
|
111
|
+
/** A not-ready skip was logged and device-history has not been ready since. */
|
|
112
|
+
private waitLogged;
|
|
63
113
|
constructor(deps: NodeMetricsHistoryRecorderDeps);
|
|
64
114
|
declare(): Promise<void>;
|
|
115
|
+
/** One process snapshot: per-runner sums plus the container's memory. */
|
|
65
116
|
recordSample(nodeId: string, atMs: number, processes: readonly RetainedProcess[], containerMemory: ContainerMemorySnapshot | null): Promise<void>;
|
|
117
|
+
/** One resources snapshot: the node's totals, at most every {@link NODE_TOTALS_MIN_INTERVAL_MS}. */
|
|
118
|
+
recordTotals(nodeId: string, atMs: number, snapshot: SystemResourceSnapshot): Promise<void>;
|
|
119
|
+
private write;
|
|
66
120
|
readContainerPoints(nodeId: string, sinceMs: number, maxPoints: number): Promise<readonly ContainerMemoryPoint[]>;
|
|
121
|
+
/**
|
|
122
|
+
* The cold tier as process samples the fold reads like the hot ring's. A
|
|
123
|
+
* runner's sums come back as `processes` equal rows (sums preserved, count
|
|
124
|
+
* right); its CPU split is `null` where it was not recorded.
|
|
125
|
+
*/
|
|
67
126
|
readProcessSamples(nodeId: string, sinceMs: number, maxPoints: number): Promise<readonly RetainedSample[]>;
|
|
68
127
|
private ensureDeclared;
|
|
69
128
|
}
|
|
129
|
+
export interface RunnerAnswers {
|
|
130
|
+
readonly main: NodeHistoryQueryAnswer;
|
|
131
|
+
readonly gc: NodeHistoryQueryAnswer;
|
|
132
|
+
readonly lifetime: NodeHistoryQueryAnswer;
|
|
133
|
+
readonly rss: NodeHistoryQueryAnswer;
|
|
134
|
+
readonly count: NodeHistoryQueryAnswer;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Per-runner cold points back into process rows. A sample exists where the
|
|
138
|
+
* runner's lifetime CPU and RSS were both recorded (always written together).
|
|
139
|
+
*/
|
|
140
|
+
export declare function assembleRunnerSamples(answers: RunnerAnswers): readonly RetainedSample[];
|
|
70
141
|
export {};
|