@openclaw/diagnostics-prometheus 2026.10.5-beta.4 → 2026.10.10-beta.1
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/index.js +170 -11
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -166,7 +166,7 @@ function createPrometheusMetricStore() {
|
|
|
166
166
|
}
|
|
167
167
|
//#endregion
|
|
168
168
|
//#region extensions/diagnostics-prometheus/src/service-child-process.ts
|
|
169
|
-
/** Git
|
|
169
|
+
/** Git owners and SQLite session transports carry bounded operation labels. */
|
|
170
170
|
function recordChildProcessSpawn(store, evt) {
|
|
171
171
|
store.counter("openclaw_child_process_spawn_total", "Successful child launches through the shared spawn and exec owners.", {
|
|
172
172
|
family: normalizeDiagnosticValue(evt.family),
|
|
@@ -176,6 +176,15 @@ function recordChildProcessSpawn(store, evt) {
|
|
|
176
176
|
//#endregion
|
|
177
177
|
//#region extensions/diagnostics-prometheus/src/service-memory.ts
|
|
178
178
|
function recordMemorySample(store, memory, byteBuckets) {
|
|
179
|
+
for (const message of memory.workerMessages ?? []) {
|
|
180
|
+
const labels = {
|
|
181
|
+
kind: message.kind,
|
|
182
|
+
direction: message.direction
|
|
183
|
+
};
|
|
184
|
+
store.counterValue("openclaw_worker_messages_total", "Messages crossing the Gateway main-thread worker boundary.", labels, message.messages);
|
|
185
|
+
store.counterValue("openclaw_worker_message_payload_bytes_total", "Known worker payload bytes, excluding transport framing and unmeasured object graphs.", labels, message.payloadBytes);
|
|
186
|
+
store.counterValue("openclaw_worker_message_unmeasured_total", "Worker messages without a known payload size; these do not contribute to payload bytes.", labels, message.unmeasuredMessages);
|
|
187
|
+
}
|
|
179
188
|
for (const worker of memory.workerLifecycle ?? []) {
|
|
180
189
|
store.counterValue("openclaw_worker_started_total", "Worker isolates created by bounded script basename.", { script: worker.script }, worker.started);
|
|
181
190
|
for (const { reason, count } of worker.retired) store.counterValue("openclaw_worker_retired_total", "Worker isolates confirmed exited by owner retirement reason.", {
|
|
@@ -192,7 +201,10 @@ function recordMemorySample(store, memory, byteBuckets) {
|
|
|
192
201
|
["worker_heap_total", "workerHeapTotalBytes"],
|
|
193
202
|
["worker_heap_used", "workerHeapUsedBytes"]
|
|
194
203
|
]) store.gauge("openclaw_memory_bytes", "Latest process memory usage by memory kind.", { kind }, asNonNegativeFiniteNumber(memory[field]));
|
|
195
|
-
for (const [name, field] of [["openclaw_worker_count", "workerCount"], ["openclaw_worker_heap_sampled_count", "workerHeapSampledCount"]])
|
|
204
|
+
for (const [name, field] of [["openclaw_worker_count", "workerCount"], ["openclaw_worker_heap_sampled_count", "workerHeapSampledCount"]]) {
|
|
205
|
+
store.clearGauges(name);
|
|
206
|
+
store.gauge(name, "Worker isolate counts.", {}, asNonNegativeFiniteNumber(memory[field]));
|
|
207
|
+
}
|
|
196
208
|
store.clearGauges("openclaw_heap_space_bytes");
|
|
197
209
|
for (const space of memory.heapSpaces ?? []) for (const [stat, field] of [
|
|
198
210
|
["used", "space_used_size"],
|
|
@@ -203,13 +215,39 @@ function recordMemorySample(store, memory, byteBuckets) {
|
|
|
203
215
|
space: space.space_name,
|
|
204
216
|
stat
|
|
205
217
|
}, space[field]);
|
|
206
|
-
const
|
|
218
|
+
const workers = /* @__PURE__ */ new Map();
|
|
219
|
+
store.clearGauges("openclaw_code_mode_worker_heap_bytes");
|
|
207
220
|
for (const worker of memory.workerHeaps ?? []) {
|
|
221
|
+
if (worker.workerSlot !== void 0) for (const [kind, value] of [["used", worker.heapUsed], ["limit", worker.heapSizeLimitBytes]]) store.gauge("openclaw_code_mode_worker_heap_bytes", "Latest live Code Mode isolate heap usage and limit by reusable worker slot.", {
|
|
222
|
+
slot: String(worker.workerSlot),
|
|
223
|
+
kind
|
|
224
|
+
}, value);
|
|
225
|
+
const totals = workers.get(worker.script) ?? {
|
|
226
|
+
count: 0,
|
|
227
|
+
sampled: 0,
|
|
228
|
+
heapUsed: void 0
|
|
229
|
+
};
|
|
230
|
+
totals.count++;
|
|
231
|
+
totals.sampled++;
|
|
208
232
|
const heapUsed = asNonNegativeFiniteNumber(worker.heapUsed);
|
|
209
|
-
if (heapUsed !== void 0)
|
|
233
|
+
if (heapUsed !== void 0) totals.heapUsed = (totals.heapUsed ?? 0) + heapUsed;
|
|
234
|
+
workers.set(worker.script, totals);
|
|
235
|
+
}
|
|
236
|
+
for (const worker of memory.workerMemoryMissing ?? []) {
|
|
237
|
+
const totals = workers.get(worker.script) ?? {
|
|
238
|
+
count: 0,
|
|
239
|
+
sampled: 0,
|
|
240
|
+
heapUsed: void 0
|
|
241
|
+
};
|
|
242
|
+
totals.count++;
|
|
243
|
+
workers.set(worker.script, totals);
|
|
210
244
|
}
|
|
211
245
|
store.clearGauges("openclaw_worker_heap_used_bytes");
|
|
212
|
-
for (const [script,
|
|
246
|
+
for (const [script, totals] of workers) {
|
|
247
|
+
store.gauge("openclaw_worker_count", "Worker isolate counts.", { script }, totals.count);
|
|
248
|
+
store.gauge("openclaw_worker_heap_sampled_count", "Worker isolate counts.", { script }, totals.sampled);
|
|
249
|
+
store.gauge("openclaw_worker_heap_used_bytes", "Latest live Worker heap usage by bounded script basename.", { script }, totals.heapUsed);
|
|
250
|
+
}
|
|
213
251
|
store.histogram("openclaw_memory_rss_bytes", "RSS memory sample distribution in bytes.", {}, asNonNegativeFiniteNumber(memory.rssBytes), byteBuckets);
|
|
214
252
|
}
|
|
215
253
|
//#endregion
|
|
@@ -259,6 +297,49 @@ function recordModelUsage(store, evt) {
|
|
|
259
297
|
}
|
|
260
298
|
//#endregion
|
|
261
299
|
//#region extensions/diagnostics-prometheus/src/service-operation-timing.ts
|
|
300
|
+
const RPC_DURATION_BUCKETS_SECONDS = [
|
|
301
|
+
.005,
|
|
302
|
+
.01,
|
|
303
|
+
.0125,
|
|
304
|
+
.015,
|
|
305
|
+
.02,
|
|
306
|
+
.025,
|
|
307
|
+
.03,
|
|
308
|
+
.04,
|
|
309
|
+
.05,
|
|
310
|
+
.06,
|
|
311
|
+
.08,
|
|
312
|
+
.1,
|
|
313
|
+
.125,
|
|
314
|
+
.15,
|
|
315
|
+
.2,
|
|
316
|
+
.25,
|
|
317
|
+
.3,
|
|
318
|
+
.4,
|
|
319
|
+
.5,
|
|
320
|
+
.6,
|
|
321
|
+
.8,
|
|
322
|
+
1,
|
|
323
|
+
1.25,
|
|
324
|
+
1.5,
|
|
325
|
+
2,
|
|
326
|
+
2.5,
|
|
327
|
+
3,
|
|
328
|
+
4,
|
|
329
|
+
5,
|
|
330
|
+
6,
|
|
331
|
+
8,
|
|
332
|
+
10,
|
|
333
|
+
12.5,
|
|
334
|
+
15,
|
|
335
|
+
20,
|
|
336
|
+
25,
|
|
337
|
+
30,
|
|
338
|
+
60,
|
|
339
|
+
120,
|
|
340
|
+
300,
|
|
341
|
+
600
|
|
342
|
+
];
|
|
262
343
|
const RESPONSE_BYTE_BUCKETS = Array.from({ length: 17 }, (_, index) => 1024 * 2 ** index);
|
|
263
344
|
const HEAP_DELTA_BYTE_BUCKETS = [
|
|
264
345
|
...RESPONSE_BYTE_BUCKETS.toReversed().map((bytes) => -bytes),
|
|
@@ -278,11 +359,30 @@ const CATALOG_LIST_PHASES = /* @__PURE__ */ new Set([
|
|
|
278
359
|
const CHAT_SEND_PHASE = /^chat\.send\.(authority|admission|preparation|attachments|replyContext|authoring|persist|runAdmission|replyInitialization|snapshot|worktree|effects|response|dispatch)$/;
|
|
279
360
|
function recordOperationTimingEvent(store, evt, metadata) {
|
|
280
361
|
switch (evt.type) {
|
|
362
|
+
case "secret.egress":
|
|
363
|
+
store.counter("openclaw_secret_egress_requests_total", "Secret egress proxy requests by outcome and credential substitution.", {
|
|
364
|
+
outcome: evt.outcome,
|
|
365
|
+
substituted: String(evt.substituted)
|
|
366
|
+
});
|
|
367
|
+
return;
|
|
368
|
+
case "tool.catalog": {
|
|
369
|
+
const labels = {
|
|
370
|
+
source: evt.source,
|
|
371
|
+
mode: evt.mode
|
|
372
|
+
};
|
|
373
|
+
store.counter("openclaw_tool_catalog_total", "Tool catalogs prepared.", labels);
|
|
374
|
+
store.counter("openclaw_tool_catalog_tools_total", "Tools cataloged during preparation.", labels, evt.toolCount);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
281
377
|
case "gateway.http.cancelled":
|
|
282
378
|
store.counter("openclaw_gateway_http_cancelled_total", "Gateway HTTP requests cancelled before completion.", { source: evt.source });
|
|
283
379
|
return;
|
|
284
380
|
case "diagnostic.gc":
|
|
285
|
-
store.histogram("openclaw_gc_duration_seconds", "Elapsed garbage collection duration in seconds
|
|
381
|
+
store.histogram("openclaw_gc_duration_seconds", "Elapsed garbage collection duration in seconds by collection kind and isolate role.", {
|
|
382
|
+
kind: evt.kind ?? "unknown",
|
|
383
|
+
thread: evt.thread ?? "main",
|
|
384
|
+
...evt.workerSlot === void 0 ? {} : { slot: String(evt.workerSlot) }
|
|
385
|
+
}, seconds(evt.durationMs));
|
|
286
386
|
return;
|
|
287
387
|
case "gateway.event_loop.sample":
|
|
288
388
|
store.histogram("openclaw_gateway_event_loop_delay_max_seconds", "Maximum event-loop delay per completed Gateway observation window in seconds.", {}, seconds(evt.delayMaxMs));
|
|
@@ -297,7 +397,7 @@ function recordOperationTimingEvent(store, evt, metadata) {
|
|
|
297
397
|
const sendPhase = CHAT_SEND_PHASE.exec(evt.name)?.[1];
|
|
298
398
|
if (sendPhase) {
|
|
299
399
|
const stage = evt.details?.stage;
|
|
300
|
-
if (stage === "request" || stage === "startup") store.histogram("openclaw_chat_send_phase_seconds", "Elapsed chat.send owner phases before acknowledgement and
|
|
400
|
+
if (stage === "request" || stage === "startup" || stage === "steer" || stage === "queued") store.histogram("openclaw_chat_send_phase_seconds", "Elapsed chat.send owner phases before acknowledgement, during startup, or awaiting steering and queued follow-up delivery.", {
|
|
301
401
|
phase: sendPhase,
|
|
302
402
|
stage
|
|
303
403
|
}, seconds(evt.durationMs));
|
|
@@ -320,6 +420,17 @@ function recordOperationTimingEvent(store, evt, metadata) {
|
|
|
320
420
|
const labels = { method: evt.method };
|
|
321
421
|
if (evt.phase === "received") {
|
|
322
422
|
store.counter("openclaw_gateway_rpc_requests_total", "Authenticated Gateway WebSocket requests received.", labels);
|
|
423
|
+
if (evt.method === "models.list" && evt.modelsList) {
|
|
424
|
+
const catalog = evt.modelsList;
|
|
425
|
+
store.counter("openclaw_models_list_requests_total", "Model catalog requests by client kind and bounded request shape.", {
|
|
426
|
+
client_kind: catalog.clientKind,
|
|
427
|
+
source: catalog.source,
|
|
428
|
+
view: catalog.view,
|
|
429
|
+
scope: catalog.scope,
|
|
430
|
+
refresh: String(catalog.refresh),
|
|
431
|
+
prepared_only: String(catalog.preparedOnly)
|
|
432
|
+
});
|
|
433
|
+
}
|
|
323
434
|
return;
|
|
324
435
|
}
|
|
325
436
|
if (evt.phase === "response" && (evt.outcome === "ok" || evt.outcome === "error")) {
|
|
@@ -330,13 +441,13 @@ function recordOperationTimingEvent(store, evt, metadata) {
|
|
|
330
441
|
phase: evt.phase,
|
|
331
442
|
outcome: evt.outcome
|
|
332
443
|
});
|
|
333
|
-
if (evt.phase === "response" && (evt.outcome === "ok" || evt.outcome === "error")) store.histogram("openclaw_gateway_rpc_first_response_seconds", "Elapsed time until the first Gateway RPC response is sent.", labels, seconds(evt.durationMs));
|
|
444
|
+
if (evt.phase === "response" && (evt.outcome === "ok" || evt.outcome === "error")) store.histogram("openclaw_gateway_rpc_first_response_seconds", "Elapsed time until the first Gateway RPC response is sent.", labels, seconds(evt.durationMs), RPC_DURATION_BUCKETS_SECONDS);
|
|
334
445
|
else if (evt.phase === "handler") {
|
|
335
446
|
if (evt.heapDeltaBytes !== void 0) store.counter("openclaw_gateway_rpc_handler_heap_delta_exclusive_total", "Gateway RPC handlers with an exclusive main-thread heap-change sample.", labels);
|
|
336
447
|
store.histogram("openclaw_gateway_rpc_handler_heap_delta_bytes", "Exclusive RPC handler heap change; background work and GC can affect signed samples.", labels, evt.heapDeltaBytes, HEAP_DELTA_BYTE_BUCKETS);
|
|
337
|
-
store.histogram("openclaw_gateway_rpc_handler_seconds", "Gateway RPC handler duration until return or throw.", labels, seconds(evt.durationMs));
|
|
338
|
-
store.histogram("openclaw_gateway_rpc_admission_seconds", "Elapsed time from Gateway RPC receipt until handler invocation.", labels, seconds(evt.admissionMs));
|
|
339
|
-
} else if (evt.phase === "dispatch") store.histogram("openclaw_gateway_rpc_queue_wait_seconds", "Gateway operator request start queue wait.", labels, seconds(evt.queueWaitMs));
|
|
448
|
+
store.histogram("openclaw_gateway_rpc_handler_seconds", "Gateway RPC handler duration until return or throw.", labels, seconds(evt.durationMs), RPC_DURATION_BUCKETS_SECONDS);
|
|
449
|
+
store.histogram("openclaw_gateway_rpc_admission_seconds", "Elapsed time from Gateway RPC receipt until handler invocation.", labels, seconds(evt.admissionMs), RPC_DURATION_BUCKETS_SECONDS);
|
|
450
|
+
} else if (evt.phase === "dispatch") store.histogram("openclaw_gateway_rpc_queue_wait_seconds", "Gateway operator request start queue wait.", labels, seconds(evt.queueWaitMs), RPC_DURATION_BUCKETS_SECONDS);
|
|
340
451
|
}
|
|
341
452
|
}
|
|
342
453
|
}
|
|
@@ -434,6 +545,52 @@ function recordWorkerRequest(store, event) {
|
|
|
434
545
|
};
|
|
435
546
|
store.histogram("openclaw_worker_queue_wait_seconds", "Elapsed time from worker request enqueue to dispatch.", labels, seconds(event.queueWaitMs));
|
|
436
547
|
store.histogram("openclaw_worker_request_seconds", "Elapsed time from worker dispatch to reply or failure, including preparation and transport.", labels, seconds(event.durationMs));
|
|
548
|
+
if (event.phase !== "completed" || !event.timing) return;
|
|
549
|
+
for (const [phase, start, end] of [
|
|
550
|
+
[
|
|
551
|
+
"dispatch",
|
|
552
|
+
"dispatched",
|
|
553
|
+
"posted"
|
|
554
|
+
],
|
|
555
|
+
[
|
|
556
|
+
"delivery",
|
|
557
|
+
"posted",
|
|
558
|
+
"received"
|
|
559
|
+
],
|
|
560
|
+
[
|
|
561
|
+
"input",
|
|
562
|
+
"received",
|
|
563
|
+
"inputReady"
|
|
564
|
+
],
|
|
565
|
+
[
|
|
566
|
+
"prepare",
|
|
567
|
+
"inputReady",
|
|
568
|
+
"executeStarted"
|
|
569
|
+
],
|
|
570
|
+
[
|
|
571
|
+
"execute",
|
|
572
|
+
"executeStarted",
|
|
573
|
+
"executeFinished"
|
|
574
|
+
],
|
|
575
|
+
[
|
|
576
|
+
"result",
|
|
577
|
+
"executeFinished",
|
|
578
|
+
"replied"
|
|
579
|
+
],
|
|
580
|
+
[
|
|
581
|
+
"reply",
|
|
582
|
+
"replied",
|
|
583
|
+
"replyReceived"
|
|
584
|
+
]
|
|
585
|
+
]) {
|
|
586
|
+
const started = event.timing[start];
|
|
587
|
+
const finished = event.timing[end];
|
|
588
|
+
if (started === void 0 || finished === void 0) continue;
|
|
589
|
+
store.histogram("openclaw_worker_request_phase_seconds", "Elapsed time within an observed SQLite worker request phase, including transport.", {
|
|
590
|
+
...labels,
|
|
591
|
+
phase
|
|
592
|
+
}, seconds(finished - started));
|
|
593
|
+
}
|
|
437
594
|
}
|
|
438
595
|
//#endregion
|
|
439
596
|
//#region extensions/diagnostics-prometheus/src/service.ts
|
|
@@ -512,6 +669,8 @@ function recordDiagnosticEvent(store, evt, metadata) {
|
|
|
512
669
|
if (metadata.trusted) recordWorkerRequest(store, evt);
|
|
513
670
|
return;
|
|
514
671
|
case "diagnostic.phase.completed":
|
|
672
|
+
case "secret.egress":
|
|
673
|
+
case "tool.catalog":
|
|
515
674
|
case "gateway.rpc":
|
|
516
675
|
case "gateway.http.cancelled":
|
|
517
676
|
case "diagnostic.gc":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/diagnostics-prometheus",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.10-beta.1",
|
|
4
4
|
"description": "OpenClaw diagnostics Prometheus exporter for runtime metrics.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"minHostVersion": ">=2026.4.25"
|
|
19
19
|
},
|
|
20
20
|
"compat": {
|
|
21
|
-
"pluginApi": ">=2026.10.
|
|
21
|
+
"pluginApi": ">=2026.10.10-beta.1"
|
|
22
22
|
},
|
|
23
23
|
"build": {
|
|
24
|
-
"openclawVersion": "2026.10.
|
|
24
|
+
"openclawVersion": "2026.10.10-beta.1"
|
|
25
25
|
},
|
|
26
26
|
"release": {
|
|
27
27
|
"publishToClawHub": true,
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"assets/activity.svg"
|
|
40
40
|
],
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"openclaw": ">=2026.10.
|
|
42
|
+
"openclaw": ">=2026.10.10-beta.1"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|
|
45
45
|
"openclaw": {
|