qwen-code/docs/developers
jinye 64401e1d17
feat(telemetry): support custom resource attributes and add metric cardinality controls (#4367)
* feat(telemetry): support custom resource attributes and add metric cardinality controls

Resolves #4365.

Adds two coupled OpenTelemetry capabilities to make qwen-code's telemetry
production-ready in multi-team / multi-tenant deployments:

1. Custom resource attributes via standard `OTEL_RESOURCE_ATTRIBUTES` and
   `OTEL_SERVICE_NAME` env vars and a new `telemetry.resourceAttributes`
   setting. Operators can now tag every span / log / metric with `team`,
   `env`, `cost_center`, or anything else their backend needs.
2. Metric cardinality controls. `session.id` is moved off the OpenTelemetry
   Resource (where it auto-attached to every metric data point and caused
   unbounded time-series fan-out on Prometheus / ARMS Metric / etc.) and
   gated behind a new opt-in `telemetry.metrics.includeSessionId` toggle.
   Spans and logs still carry `session.id` for trace and log correlation.

Reserved keys (`service.version`, `session.id`) are stripped from both env
and settings sources with a `diag.warn`. `OTEL_SERVICE_NAME` follows the
OTel spec precedence (highest priority for `service.name`). Settings JSON
values are runtime-coerced to strings as defense against hand-edited
non-conforming JSON.

Breaking change: metrics no longer carry `session.id` by default. Operators
who need it can restore the previous behavior with
`QWEN_TELEMETRY_METRICS_INCLUDE_SESSION_ID=true` or
`telemetry.metrics.includeSessionId: true` in settings.json; recommended
only for short-term debugging since it re-introduces the cardinality
problem. For long-term session-level analysis, prefer trace and log
backends which handle per-event data without cardinality pressure.

Design doc: docs/design/telemetry-resource-attributes-design.md

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

* docs(telemetry): align reserved-key descriptions with implementation

Round 1 review fixes (#4367). After session.id was added to
RESERVED_RESOURCE_ATTRIBUTE_KEYS in Codex review, four user-facing
descriptions still claimed only service.version was reserved:

- packages/core/src/telemetry/config.ts (merge comment)
- packages/core/src/config/config.ts (TelemetrySettings JSDoc)
- packages/cli/src/config/settingsSchema.ts (schema description)
- packages/vscode-ide-companion/schemas/settings.schema.json (regenerated)

Also corrects scope claim: resource attributes apply to every signal
the SDK exports (OTLP and file outfile share the same Resource), not
just OTLP.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

* docs(telemetry): clarify warning destination and surface percent-encoding hint

Round 2 self-review fixes (#4367). Two small but real UX gaps:

1. Reserved-key / malformed-pair / coerce warnings route to the debug
   log (per #3986), not the console — so a user who types
   `OTEL_RESOURCE_ATTRIBUTES=service.version=2.0` sees no feedback that
   the value was silently dropped. Adds a "Troubleshooting" section in
   telemetry.md telling users where to look, and a note in the parser
   docstring documenting where warns go.

2. A literal (unencoded) comma in an env var value is a common foot-gun:
   the parser splits on it, producing a malformed second half that is
   silently dropped. Updates the warn text to include a "hint:
   percent-encode literal commas as %2C" callout, and adds the same
   guidance to the docs.

Deferred to a follow-up: startup-time stderr summary of dropped
attributes. Stderr during TUI render could break Ink rendering, so the
right surface needs separate design.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

* test(telemetry): cover first-`=` split contract in OTEL_RESOURCE_ATTRIBUTES parser

Per review feedback on #4367. The parser uses `indexOf('=')` so
the first `=` separates key and value while subsequent `=` stay in
the value. The behavior was correct but untested; a future refactor
to `split('=')` would silently break base64-padded, JWT, or
connection-string values.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

* feat(telemetry): tighten resource-attribute input validation + startup summary

Adopts review feedback from #4367 (wenshao via Qwen Code /review).

Five accepted suggestions, bundled because they all touch the same
parse/coerce/strip pipeline:

1. Key percent-decoding (CRITICAL). `parseOtelResourceAttributes` now
   percent-decodes both keys and values per the OTel / W3C Baggage spec.
   Without this, `OTEL_RESOURCE_ATTRIBUTES=service%2Eversion=99` lands
   on Resource as the literal key `service%2Eversion`, bypassing the
   reserved-key filter; a collector that decodes keys downstream could
   then resurrect `service.version` and spoof the version label.

2. Startup summary of dropped attributes. Every `diag.warn` in
   resource-attributes.ts routes only to the OTel debug log (per
   #3986), giving operators zero feedback when their attributes are
   silently dropped. Helpers now optionally accumulate diagnostics
   into a `ResourceAttributeWarnings` array; the resolver collects
   them and the SDK emits a one-time console summary at init (before
   Ink renders, so no TUI conflict).

3. `||` instead of `??` for service.name fallback. Settings can put
   an empty string through `??`, producing a blank `service.name`
   that some backends reject. `||` falls through to the default.

4. `coerceStringResourceAttributes` now trims keys and skips
   empty/whitespace-only keys, matching `parseOtelResourceAttributes`.
   Previously `{"  ": "x"}` or `{"team ": "y"}` from settings.json
   would land as malformed Resource attributes.

5. `OTEL_SERVICE_NAME` is trimmed before the truthy check, so values
   like `'  '` or `'\t'` are treated as unset rather than producing
   a whitespace-only service name on Resource.

One suggestion declined (in-thread reply on PR):

- "Redundant `?? {}` in sdk.ts:160" — intentional defense-in-depth for
  `vi.mock('../config/config.js')` callers in `telemetry.test.ts` where
  auto-stub returns undefined. The reviewer is right that production
  code paths never hit it, but tests do.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

* fix(telemetry): trim whitespace-only service.name + add invalid-key-encoding test

Adopts two review suggestions on #4367 (wenshao via Qwen Code /review):

1. `service.name` fallback uses `.trim() || SERVICE_NAME` instead of plain
   `||`. Plain `||` lets whitespace-only values (`" "`, `"\t"`) through as
   truthy, producing a blank service name on Resource that some backends
   reject. Both settings (no value trimming) and env (`%20` decodes to `" "`)
   can deliver such values. Test added.

2. Adds `key%ZZ=val` to the parameterized parser test to cover the
   invalid-percent-encoding-on-key catch branch. Previously only the
   value-side catch was tested.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
2026-05-21 13:54:37 +08:00
..
daemon-client-adapters feat(tui): add daemon adapter spike (#4202) 2026-05-18 11:22:39 +08:00
development feat(telemetry): support custom resource attributes and add metric cardinality controls (#4367) 2026-05-21 13:54:37 +08:00
examples feat(serve): add workspace file write/edit routes (#4175 PR20) (#4280) 2026-05-18 22:37:08 +08:00
tools feat(core): add NotebookEdit tool for Jupyter notebooks 2026-05-21 00:06:15 +08:00
_meta.ts feat(cli,sdk): qwen serve daemon (Stage 1) (#3889) 2026-05-13 14:47:47 +08:00
architecture.md docs: enhance architecture documentation and add contribution guidelines 2025-12-11 18:31:24 +08:00
channel-plugins.md feat(channels): add dispatch modes and prompt lifecycle hooks 2026-03-28 06:19:02 +00:00
contributing.md chore(deps): upgrade ink 6.2.3 → 7.0.2 + bump Node engine to 22 (#3860) 2026-05-11 17:29:50 +08:00
qwen-serve-protocol.md feat(cli,core): add Auto approval mode with LLM classifier (#4151) 2026-05-20 10:30:05 +08:00
roadmap.md feat(cli): improve auth dialog UX with clearer three-option layout 2026-03-01 15:22:35 +08:00
sdk-java.md feat(core): add NotebookEdit tool for Jupyter notebooks 2026-05-21 00:06:15 +08:00
sdk-python.md doc[sdk-python] Expand Python SDK usage documentation (#3995) 2026-05-12 15:27:00 +08:00
sdk-typescript.md feat(core): add NotebookEdit tool for Jupyter notebooks 2026-05-21 00:06:15 +08:00