@openclaw/diagnostics-prometheus 2026.5.24-beta.2 → 2026.5.25-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/api.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/plugin-entry";
2
+ import { isInternalDiagnosticEventMetadata } from "openclaw/plugin-sdk/diagnostic-runtime";
2
3
  import { redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
3
- export { emptyPluginConfigSchema, redactSensitiveText };
4
+ export { emptyPluginConfigSchema, isInternalDiagnosticEventMetadata, redactSensitiveText };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { redactSensitiveText } from "./api.js";
1
+ import { isInternalDiagnosticEventMetadata, redactSensitiveText } from "./api.js";
2
2
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
3
3
  //#region extensions/diagnostics-prometheus/src/service.ts
4
4
  const DURATION_BUCKETS_SECONDS = [
@@ -47,6 +47,19 @@ const BYTE_BUCKETS = [
47
47
  4294967296,
48
48
  17179869184
49
49
  ];
50
+ const RATIO_BUCKETS = [
51
+ .01,
52
+ .05,
53
+ .1,
54
+ .25,
55
+ .5,
56
+ .75,
57
+ 1,
58
+ 2,
59
+ 4,
60
+ 8,
61
+ 16
62
+ ];
50
63
  const LOW_CARDINALITY_VALUE_RE = /^[A-Za-z0-9_.:-]{1,120}$/u;
51
64
  const MAX_PROMETHEUS_SERIES = 2048;
52
65
  const DROPPED_SERIES_COUNTER_NAME = "openclaw_prometheus_series_dropped_total";
@@ -183,6 +196,9 @@ function createPrometheusMetricStore() {
183
196
  function safeErrorMessage(err) {
184
197
  return redactSensitiveText(err instanceof Error ? err.message ?? err.name : String(err)).replaceAll("\0", " ").replace(/[\r\n\t\u2028\u2029]/gu, " ").slice(0, 500);
185
198
  }
199
+ function shouldRecordDiagnosticEvent(metadata) {
200
+ return metadata.trusted || isInternalDiagnosticEventMetadata(metadata);
201
+ }
186
202
  function renderPrometheusMetrics(store) {
187
203
  const snapshot = store.snapshot();
188
204
  const lines = [];
@@ -247,6 +263,17 @@ function modelCallLabels(evt) {
247
263
  transport: lowCardinalityLabel(evt.transport)
248
264
  };
249
265
  }
266
+ function modelFailoverLabels(evt) {
267
+ return {
268
+ from_model: lowCardinalityLabel(evt.fromModel),
269
+ from_provider: lowCardinalityLabel(evt.fromProvider),
270
+ lane: lowCardinalityQueueLaneLabel(evt.lane),
271
+ reason: lowCardinalityLabel(evt.reason, "other"),
272
+ suspended: evt.suspended === void 0 ? "unknown" : String(evt.suspended),
273
+ to_model: lowCardinalityLabel(evt.toModel),
274
+ to_provider: lowCardinalityLabel(evt.toProvider)
275
+ };
276
+ }
250
277
  function toolExecutionLabels(evt) {
251
278
  return {
252
279
  error_category: evt.type === "tool.execution.error" ? lowCardinalityLabel(evt.errorCategory, "other") : "none",
@@ -257,6 +284,15 @@ function toolExecutionLabels(evt) {
257
284
  tool_source: lowCardinalityLabel(evt.toolSource, "core")
258
285
  };
259
286
  }
287
+ function toolExecutionBlockedLabels(evt) {
288
+ return {
289
+ denied_reason: lowCardinalityLabel(evt.deniedReason, "other"),
290
+ params_kind: lowCardinalityLabel(evt.paramsSummary?.kind),
291
+ tool: lowCardinalityLabel(evt.toolName, "tool"),
292
+ tool_owner: lowCardinalityLabel(evt.toolOwner, "none"),
293
+ tool_source: lowCardinalityLabel(evt.toolSource, "core")
294
+ };
295
+ }
260
296
  function skillLabels(evt) {
261
297
  return {
262
298
  activation: lowCardinalityLabel(evt.activation, "unknown"),
@@ -277,6 +313,18 @@ function harnessLabels(evt) {
277
313
  provider: lowCardinalityLabel(evt.provider)
278
314
  };
279
315
  }
316
+ function webhookLabels(evt) {
317
+ return {
318
+ channel: lowCardinalityLabel(evt.channel),
319
+ webhook: lowCardinalityLabel(evt.updateType)
320
+ };
321
+ }
322
+ function sessionStuckLabels(evt) {
323
+ return {
324
+ reason: lowCardinalityLabel(evt.reason, "none"),
325
+ state: evt.state
326
+ };
327
+ }
280
328
  function sessionRecoveryLabels(evt) {
281
329
  return {
282
330
  action: evt.type === "session.recovery.completed" ? lowCardinalityLabel(evt.action, "unknown") : evt.allowActiveAbort ? "abort" : "recover",
@@ -285,6 +333,18 @@ function sessionRecoveryLabels(evt) {
285
333
  status: evt.type === "session.recovery.completed" ? evt.status : "requested"
286
334
  };
287
335
  }
336
+ function livenessLabels(evt) {
337
+ return { reason: lowCardinalityLabel(evt.reasons.join(":"), "unknown") };
338
+ }
339
+ function payloadLargeLabels(evt) {
340
+ return {
341
+ action: evt.action,
342
+ channel: lowCardinalityLabel(evt.channel, "none"),
343
+ plugin: lowCardinalityLabel(evt.pluginId, "none"),
344
+ reason: lowCardinalityLabel(evt.reason, "none"),
345
+ surface: lowCardinalityLabel(evt.surface, "unknown")
346
+ };
347
+ }
288
348
  function talkLabels(evt) {
289
349
  return {
290
350
  brain: lowCardinalityLabel(evt.brain),
@@ -325,7 +385,7 @@ function recordModelUsage(store, evt) {
325
385
  store.histogram("openclaw_model_usage_duration_seconds", "Model usage event duration in seconds.", labels, seconds(evt.durationMs));
326
386
  }
327
387
  function recordDiagnosticEvent(store, evt, metadata) {
328
- if (!metadata.trusted) return;
388
+ if (!shouldRecordDiagnosticEvent(metadata)) return;
329
389
  switch (evt.type) {
330
390
  case "model.usage":
331
391
  recordModelUsage(store, evt);
@@ -339,11 +399,17 @@ function recordDiagnosticEvent(store, evt, metadata) {
339
399
  store.histogram("openclaw_model_call_duration_seconds", "Provider model call duration in seconds.", modelCallLabels(evt), seconds(evt.durationMs));
340
400
  store.counter("openclaw_model_call_total", "Provider model calls completed by outcome.", modelCallLabels(evt));
341
401
  return;
402
+ case "model.failover":
403
+ store.counter("openclaw_model_failover_total", "Model failovers by source, destination, lane, and reason.", modelFailoverLabels(evt));
404
+ return;
342
405
  case "tool.execution.completed":
343
406
  case "tool.execution.error":
344
407
  store.histogram("openclaw_tool_execution_duration_seconds", "Tool execution duration in seconds.", toolExecutionLabels(evt), seconds(evt.durationMs));
345
408
  store.counter("openclaw_tool_execution_total", "Tool executions completed by outcome.", toolExecutionLabels(evt));
346
409
  return;
410
+ case "tool.execution.blocked":
411
+ store.counter("openclaw_tool_execution_blocked_total", "Tool executions blocked by policy or sandbox diagnostics.", toolExecutionBlockedLabels(evt));
412
+ return;
347
413
  case "skill.used":
348
414
  store.counter("openclaw_skill_used_total", "Skills used by agent runs.", skillLabels(evt));
349
415
  return;
@@ -364,6 +430,15 @@ function recordDiagnosticEvent(store, evt, metadata) {
364
430
  reason: lowCardinalityLabel(evt.reason, "none")
365
431
  }, seconds(evt.durationMs));
366
432
  return;
433
+ case "webhook.received":
434
+ store.counter("openclaw_webhook_received_total", "Webhook requests received by channel and update type.", webhookLabels(evt));
435
+ return;
436
+ case "webhook.processed":
437
+ store.histogram("openclaw_webhook_duration_seconds", "Webhook processing duration in seconds.", webhookLabels(evt), seconds(evt.durationMs));
438
+ return;
439
+ case "webhook.error":
440
+ store.counter("openclaw_webhook_error_total", "Webhook processing errors by channel and update type.", webhookLabels(evt));
441
+ return;
367
442
  case "message.delivery.started":
368
443
  store.counter("openclaw_message_delivery_started_total", "Outbound message delivery attempts started.", {
369
444
  channel: lowCardinalityLabel(evt.channel),
@@ -433,6 +508,10 @@ function recordDiagnosticEvent(store, evt, metadata) {
433
508
  });
434
509
  if (evt.queueDepth !== void 0) store.gauge("openclaw_session_queue_depth", "Latest observed session queue depth.", { state: evt.state }, numericValue(evt.queueDepth));
435
510
  return;
511
+ case "session.stuck":
512
+ store.counter("openclaw_session_stuck_total", "Stale session bookkeeping observations with no active work.", sessionStuckLabels(evt));
513
+ store.histogram("openclaw_session_stuck_age_seconds", "Age of stale session bookkeeping observations in seconds.", sessionStuckLabels(evt), seconds(evt.ageMs));
514
+ return;
436
515
  case "session.turn.created":
437
516
  store.counter("openclaw_session_turn_created_total", "Agent session turns created.", {
438
517
  agent: lowCardinalityLabel(evt.agentId),
@@ -452,6 +531,16 @@ function recordDiagnosticEvent(store, evt, metadata) {
452
531
  reason: evt.reason
453
532
  });
454
533
  return;
534
+ case "diagnostic.liveness.warning":
535
+ store.counter("openclaw_liveness_warning_total", "Diagnostic liveness warning events.", livenessLabels(evt));
536
+ store.gauge("openclaw_liveness_sessions", "Latest session counts reported with diagnostic liveness warnings.", { state: "active" }, numericValue(evt.active));
537
+ store.gauge("openclaw_liveness_sessions", "Latest session counts reported with diagnostic liveness warnings.", { state: "waiting" }, numericValue(evt.waiting));
538
+ store.gauge("openclaw_liveness_sessions", "Latest session counts reported with diagnostic liveness warnings.", { state: "queued" }, numericValue(evt.queued));
539
+ store.histogram("openclaw_liveness_event_loop_delay_p99_seconds", "P99 event-loop delay reported by diagnostic liveness warnings in seconds.", livenessLabels(evt), seconds(evt.eventLoopDelayP99Ms));
540
+ store.histogram("openclaw_liveness_event_loop_delay_max_seconds", "Maximum event-loop delay reported by diagnostic liveness warnings in seconds.", livenessLabels(evt), seconds(evt.eventLoopDelayMaxMs));
541
+ store.histogram("openclaw_liveness_event_loop_utilization_ratio", "Event-loop utilization reported by diagnostic liveness warnings.", livenessLabels(evt), numericValue(evt.eventLoopUtilization), RATIO_BUCKETS);
542
+ store.histogram("openclaw_liveness_cpu_core_ratio", "CPU core ratio reported by diagnostic liveness warnings.", livenessLabels(evt), numericValue(evt.cpuCoreRatio), RATIO_BUCKETS);
543
+ return;
455
544
  case "diagnostic.async_queue.dropped":
456
545
  store.counter("openclaw_diagnostic_async_queue_dropped_total", "Async diagnostic queue drops by dropped event class.", { drop_class: "total" }, numericValue(evt.droppedEvents));
457
546
  if (evt.droppedTrustedEvents !== void 0) store.counter("openclaw_diagnostic_async_queue_dropped_total", "Async diagnostic queue drops by dropped event class.", { drop_class: "trusted" }, numericValue(evt.droppedTrustedEvents));
@@ -459,8 +548,7 @@ function recordDiagnosticEvent(store, evt, metadata) {
459
548
  if (evt.droppedPriorityEvents !== void 0) store.counter("openclaw_diagnostic_async_queue_dropped_total", "Async diagnostic queue drops by dropped event class.", { drop_class: "priority" }, numericValue(evt.droppedPriorityEvents));
460
549
  store.gauge("openclaw_diagnostic_async_queue_length", "Latest async diagnostic queue length after a drop summary.", {}, numericValue(evt.queueLength));
461
550
  return;
462
- case "diagnostic.heartbeat":
463
- case "diagnostic.liveness.warning": return;
551
+ case "diagnostic.heartbeat": return;
464
552
  case "telemetry.exporter":
465
553
  store.counter("openclaw_telemetry_exporter_total", "Telemetry exporter lifecycle events.", {
466
554
  exporter: lowCardinalityLabel(evt.exporter),
@@ -469,6 +557,10 @@ function recordDiagnosticEvent(store, evt, metadata) {
469
557
  status: evt.status
470
558
  });
471
559
  return;
560
+ case "payload.large":
561
+ store.counter("openclaw_payload_large_total", "Oversized payload diagnostics by surface and action.", payloadLargeLabels(evt));
562
+ store.histogram("openclaw_payload_large_bytes", "Oversized payload byte sizes by surface and action.", payloadLargeLabels(evt), numericValue(evt.bytes), BYTE_BUCKETS);
563
+ return;
472
564
  default: return;
473
565
  }
474
566
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/diagnostics-prometheus",
3
- "version": "2026.5.24-beta.2",
3
+ "version": "2026.5.25-beta.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/diagnostics-prometheus",
9
- "version": "2026.5.24-beta.2"
9
+ "version": "2026.5.25-beta.1"
10
10
  }
11
11
  }
12
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/diagnostics-prometheus",
3
- "version": "2026.5.24-beta.2",
3
+ "version": "2026.5.25-beta.1",
4
4
  "description": "OpenClaw diagnostics Prometheus exporter",
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.5.24-beta.2"
21
+ "pluginApi": ">=2026.5.25-beta.1"
22
22
  },
23
23
  "build": {
24
- "openclawVersion": "2026.5.24-beta.2"
24
+ "openclawVersion": "2026.5.25-beta.1"
25
25
  },
26
26
  "release": {
27
27
  "publishToClawHub": true,
@@ -37,7 +37,7 @@
37
37
  "npm-shrinkwrap.json"
38
38
  ],
39
39
  "peerDependencies": {
40
- "openclaw": ">=2026.5.24-beta.2"
40
+ "openclaw": ">=2026.5.25-beta.1"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "openclaw": {