fix(diagnostics-otel): stabilize genai token metric model attr · openclaw/openclaw@4464844
vincentkoc
·
2026-04-26
·
via Recent Commits to openclaw:main
File tree
extensions/diagnostics-otel/src
| Original file line number | Diff line number | Diff line change |
|---|
@@ -42,6 +42,7 @@ Docs: https://docs.openclaw.ai
|
42 | 42 | - Diagnostics/OTEL: add GenAI usage token attributes to model-usage spans, including cache read/write input token counts without session identifiers or prompt/response content. Thanks @vincentkoc. |
43 | 43 | - Diagnostics/OTEL: include bounded GenAI operation, provider, and request-model attributes on model-usage spans so token usage remains self-describing without diagnostic identifiers. Thanks @vincentkoc. |
44 | 44 | - Diagnostics/OTEL: keep model-usage span GenAI provider attributes aligned with the existing semantic-convention opt-in policy, using legacy `gen_ai.system` unless latest experimental GenAI conventions are enabled. Thanks @vincentkoc. |
| 45 | +- Diagnostics/OTEL: keep `gen_ai.request.model` present on GenAI token usage metrics with a bounded `unknown` fallback when model usage events do not include a model. Thanks @vincentkoc. |
45 | 46 | - Diagnostics/OTEL: add bounded outbound message delivery lifecycle diagnostics and export them as low-cardinality delivery spans/metrics without message body, recipient, room, or media-path data. (#71471) Thanks @vincentkoc and @jlapenna. |
46 | 47 | - Diagnostics/OTEL: emit bounded exec-process diagnostics and export them as `openclaw.exec` spans without exposing command text, working directories, or container identifiers. (#71451) Thanks @vincentkoc and @jlapenna. |
47 | 48 | - Diagnostics/OTEL: support `OPENCLAW_OTEL_PRELOADED=1` so the plugin can reuse an already-registered OpenTelemetry SDK while keeping OpenClaw diagnostic listeners wired. (#71450) Thanks @vincentkoc and @jlapenna. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -740,6 +740,30 @@ describe("diagnostics-otel service", () => {
|
740 | 740 | await service.stop?.(ctx); |
741 | 741 | }); |
742 | 742 | |
| 743 | +test("keeps GenAI token usage metric model attribute present when model is unavailable", async () => { |
| 744 | +const service = createDiagnosticsOtelService(); |
| 745 | +const ctx = createOtelContext(OTEL_TEST_ENDPOINT, { metrics: true }); |
| 746 | +await service.start(ctx); |
| 747 | + |
| 748 | +emitDiagnosticEvent({ |
| 749 | +type: "model.usage", |
| 750 | +provider: "openai", |
| 751 | +usage: { input: 2 }, |
| 752 | +}); |
| 753 | +await flushDiagnosticEvents(); |
| 754 | + |
| 755 | +expect(telemetryState.histograms.get("gen_ai.client.token.usage")?.record).toHaveBeenCalledWith( |
| 756 | +2, |
| 757 | +{ |
| 758 | +"gen_ai.operation.name": "chat", |
| 759 | +"gen_ai.provider.name": "openai", |
| 760 | +"gen_ai.request.model": "unknown", |
| 761 | +"gen_ai.token.type": "input", |
| 762 | +}, |
| 763 | +); |
| 764 | +await service.stop?.(ctx); |
| 765 | +}); |
| 766 | + |
743 | 767 | test("exports GenAI usage attributes on model usage spans without diagnostic identifiers", async () => { |
744 | 768 | const service = createDiagnosticsOtelService(); |
745 | 769 | const ctx = createOtelContext(OTEL_TEST_ENDPOINT, { traces: true }); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -904,7 +904,7 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
|
904 | 904 | const genAiAttrs: Record<string, string> = { |
905 | 905 | "gen_ai.operation.name": "chat", |
906 | 906 | "gen_ai.provider.name": lowCardinalityAttr(evt.provider), |
907 | | -...(evt.model ? { "gen_ai.request.model": lowCardinalityAttr(evt.model) } : {}), |
| 907 | +"gen_ai.request.model": lowCardinalityAttr(evt.model), |
908 | 908 | }; |
909 | 909 | |
910 | 910 | const usage = evt.usage; |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。