@openclaw/diagnostics-otel 2026.5.20-beta.1 → 2026.5.20

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.
Files changed (2) hide show
  1. package/dist/index.js +52 -0
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
10
10
  import { NodeSDK } from "@opentelemetry/sdk-node";
11
11
  import { ParentBasedSampler, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
12
12
  import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
13
+ import { registerUnhandledRejectionHandler } from "openclaw/plugin-sdk/runtime-env";
13
14
  //#region extensions/diagnostics-otel/src/service.ts
14
15
  const DEFAULT_SERVICE_NAME = "openclaw";
15
16
  const DROPPED_OTEL_ATTRIBUTE_KEYS = new Set([
@@ -119,6 +120,46 @@ function errorCategory(err) {
119
120
  return "unknown";
120
121
  }
121
122
  }
123
+ function collectNestedErrorCandidates(err) {
124
+ const queue = [err];
125
+ const seen = /* @__PURE__ */ new Set();
126
+ const candidates = [];
127
+ while (queue.length > 0) {
128
+ const current = queue.shift();
129
+ if (current == null || seen.has(current)) continue;
130
+ seen.add(current);
131
+ candidates.push(current);
132
+ if (Array.isArray(current)) {
133
+ for (const item of current) if (item != null && !seen.has(item)) queue.push(item);
134
+ continue;
135
+ }
136
+ if (typeof current !== "object") continue;
137
+ const record = current;
138
+ for (const nested of [
139
+ record.cause,
140
+ record.reason,
141
+ record.original,
142
+ record.error
143
+ ]) if (nested != null && !seen.has(nested)) queue.push(nested);
144
+ if (Array.isArray(record.errors)) {
145
+ for (const nested of record.errors) if (nested != null && !seen.has(nested)) queue.push(nested);
146
+ }
147
+ }
148
+ return candidates;
149
+ }
150
+ function readErrorName(err) {
151
+ if (!err || typeof err !== "object") return;
152
+ const name = err.name;
153
+ return typeof name === "string" && name.trim() ? name : void 0;
154
+ }
155
+ function readErrorCode(err) {
156
+ if (!err || typeof err !== "object") return;
157
+ const code = err.code;
158
+ return typeof code === "string" || typeof code === "number" ? code : void 0;
159
+ }
160
+ function findOtlpExporterError(reason) {
161
+ for (const candidate of collectNestedErrorCandidates(reason)) if (readErrorName(candidate) === "OTLPExporterError" && candidate && typeof candidate === "object") return candidate;
162
+ }
122
163
  function redactOtelAttributes(attributes) {
123
164
  const redactedAttributes = {};
124
165
  for (const [key, value] of Object.entries(attributes)) {
@@ -291,15 +332,19 @@ function createDiagnosticsOtelService() {
291
332
  let logProvider = null;
292
333
  let unsubscribe = null;
293
334
  let stopActiveTrustedSpans = null;
335
+ let unregisterUnhandledRejectionHandler = null;
294
336
  const stopStarted = async () => {
295
337
  const currentUnsubscribe = unsubscribe;
296
338
  const currentLogProvider = logProvider;
297
339
  const currentSdk = sdk;
298
340
  const currentStopActiveTrustedSpans = stopActiveTrustedSpans;
341
+ const currentUnregisterUnhandledRejectionHandler = unregisterUnhandledRejectionHandler;
299
342
  unsubscribe = null;
300
343
  logProvider = null;
301
344
  sdk = null;
302
345
  stopActiveTrustedSpans = null;
346
+ unregisterUnhandledRejectionHandler = null;
347
+ currentUnregisterUnhandledRejectionHandler?.();
303
348
  currentUnsubscribe?.();
304
349
  currentStopActiveTrustedSpans?.();
305
350
  if (currentLogProvider) await currentLogProvider.shutdown().catch(() => void 0);
@@ -1533,6 +1578,13 @@ function createDiagnosticsOtelService() {
1533
1578
  ctx.logger.error(`diagnostics-otel: event handler failed (${evt.type}): ${formatError(err)}`);
1534
1579
  }
1535
1580
  });
1581
+ unregisterUnhandledRejectionHandler = registerUnhandledRejectionHandler((reason) => {
1582
+ const otlpError = findOtlpExporterError(reason);
1583
+ if (!otlpError) return false;
1584
+ const code = readErrorCode(otlpError) ?? "unknown";
1585
+ ctx.logger.warn(`diagnostics-otel: suppressed OTLP exporter unhandled rejection (code=${String(code)})`);
1586
+ return true;
1587
+ });
1536
1588
  emitForSignals(enabledSignals, {
1537
1589
  exporter: "diagnostics-otel",
1538
1590
  status: "started",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/diagnostics-otel",
3
- "version": "2026.5.20-beta.1",
3
+ "version": "2026.5.20",
4
4
  "description": "OpenClaw diagnostics OpenTelemetry exporter",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,10 +34,10 @@
34
34
  "minHostVersion": ">=2026.4.25"
35
35
  },
36
36
  "compat": {
37
- "pluginApi": ">=2026.5.20-beta.1"
37
+ "pluginApi": ">=2026.5.20"
38
38
  },
39
39
  "build": {
40
- "openclawVersion": "2026.5.20-beta.1"
40
+ "openclawVersion": "2026.5.20"
41
41
  },
42
42
  "release": {
43
43
  "publishToClawHub": true,
@@ -52,7 +52,7 @@
52
52
  "openclaw.plugin.json"
53
53
  ],
54
54
  "peerDependencies": {
55
- "openclaw": ">=2026.5.20-beta.1"
55
+ "openclaw": ">=2026.5.20"
56
56
  },
57
57
  "peerDependenciesMeta": {
58
58
  "openclaw": {