Skip to content

Commit fae5421

Browse files
Pandah97steipete
andauthored
fix(diagnostics-prometheus): use truncateUtf16Safe for error message truncation (#102591)
* fix(diagnostics-prometheus): use truncateUtf16Safe for error message truncation The safeErrorMessage function uses naive .slice(0, 500) on error messages which can split surrogate pairs. Replace with truncateUtf16Safe(). * test(diagnostics-prometheus): cover UTF-16-safe errors --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent 4be6fa7 commit fae5421

2 files changed

Lines changed: 31 additions & 5 deletions

File tree

extensions/diagnostics-prometheus/src/service.test.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ describe("diagnostics-prometheus service", () => {
674674
) => void
675675
> = [];
676676
const emitted: unknown[] = [];
677+
const error = vi.fn();
677678
const exporter = createDiagnosticsPrometheusExporter();
678679
const unsubscribe = vi.fn();
679680

@@ -683,7 +684,7 @@ describe("diagnostics-prometheus service", () => {
683684
logger: {
684685
info: vi.fn(),
685686
warn: vi.fn(),
686-
error: vi.fn(),
687+
error,
687688
debug: vi.fn(),
688689
},
689690
internalDiagnostics: {
@@ -721,6 +722,28 @@ describe("diagnostics-prometheus service", () => {
721722
'openclaw_model_tokens_total{agent="unknown",channel="unknown",model="gpt-5.4",provider="openai",token_type="input"} 12',
722723
);
723724

725+
const prefix = "x".repeat(499);
726+
const usage = {} as Extract<DiagnosticEventPayload, { type: "model.usage" }>["usage"];
727+
Object.defineProperty(usage, "input", {
728+
get() {
729+
throw new Error(`${prefix}😀`);
730+
},
731+
});
732+
listeners[0](
733+
{
734+
...baseEvent(),
735+
type: "model.usage",
736+
provider: "openai",
737+
model: "gpt-5.4",
738+
usage,
739+
},
740+
trusted,
741+
{},
742+
);
743+
expect(error).toHaveBeenCalledWith(
744+
`diagnostics-prometheus: event handler failed (model.usage): ${prefix}`,
745+
);
746+
724747
exporter.service.stop?.();
725748

726749
expect(unsubscribe).toHaveBeenCalledOnce();

extensions/diagnostics-prometheus/src/service.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Diagnostics Prometheus plugin module implements service behavior.
22
import type { IncomingMessage, ServerResponse } from "node:http";
3+
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
34
import type {
45
DiagnosticEventMetadata,
56
DiagnosticEventPayload,
@@ -228,10 +229,12 @@ function createPrometheusMetricStore() {
228229

229230
function safeErrorMessage(err: unknown): string {
230231
const message = err instanceof Error ? (err.message ?? err.name) : String(err);
231-
return redactSensitiveText(message)
232-
.replaceAll("\u0000", " ")
233-
.replace(/[\r\n\t\u2028\u2029]/gu, " ")
234-
.slice(0, 500);
232+
return truncateUtf16Safe(
233+
redactSensitiveText(message)
234+
.replaceAll("\u0000", " ")
235+
.replace(/[\r\n\t\u2028\u2029]/gu, " "),
236+
500,
237+
);
235238
}
236239

237240
function shouldRecordDiagnosticEvent(metadata: DiagnosticEventMetadata): boolean {

0 commit comments

Comments
 (0)