Skip to content

feat(telemetry): add client_id attribute and permission route spans#4628

Merged
wenshao merged 1 commit into
daemon_mode_b_mainfrom
feat/daemon-otel-client-id-permission
May 30, 2026
Merged

feat(telemetry): add client_id attribute and permission route spans#4628
wenshao merged 1 commit into
daemon_mode_b_mainfrom
feat/daemon-otel-client-id-permission

Conversation

@doudouOUC

Copy link
Copy Markdown
Collaborator

Summary

  • Add qwen-code.client_id span attribute to daemon HTTP request spans (from X-Qwen-Client-Id header, validated with CLIENT_ID_RE) and bridge prompt.dispatch spans (from BridgeClientRequestContext.clientId)
  • Add telemetry coverage for permission vote routes: POST /session/:id/permission/:requestId and POST /permission/:requestId, with qwen-code.daemon.permission.request_id span attribute
  • Add addDaemonRequestAttribute() helper for post-rebase promptId enrichment (plumbing for feat(telemetry): cover qwen serve daemon end-to-end with OpenTelemetry #4554 scope item)

Test plan

  • packages/core daemon-tracing tests: 8 passed (4 new — clientId/permissionRequestId inclusion/omission, addDaemonRequestAttribute active/no-op)
  • packages/acp-bridge bridge tests: 196 passed (existing telemetry test updated to verify client_id flows through prompt.dispatch span)
  • Pre-commit lint + prettier pass

🤖 Generated with Qwen Code

Copilot AI review requested due to automatic review settings May 29, 2026 14:35
@github-actions

Copy link
Copy Markdown
Contributor

📋 Review Summary

This PR adds telemetry coverage for daemon HTTP request spans by introducing qwen-code.client_id attribute extraction from the X-Qwen-Client-Id header and bridging it through prompt.dispatch spans. It also adds span attributes for permission vote routes and introduces the addDaemonRequestAttribute() helper for post-rebase prompt ID enrichment. The implementation is clean, well-tested, and follows existing telemetry patterns.

🔍 General Feedback

  • The changes are minimal and focused on the stated objectives—no speculative features added
  • Test coverage is comprehensive with both inclusion and omission cases for the new attributes
  • The code follows existing patterns in the codebase for telemetry attribute handling
  • Good defensive programming with try-catch blocks around telemetry operations
  • The PR description clearly outlines the scope and test results

🎯 Specific Feedback

🟢 Medium

  • File: packages/cli/src/serve/server.ts:2113-2120 - The inline client ID validation logic in daemonTelemetryMiddleware duplicates the logic in parseClientIdHeader function (lines 2098-2109). Consider refactoring to reuse parseClientIdHeader or extract the validation into a shared helper to avoid drift:
// Current inline logic:
const rawClientId = req.get(CLIENT_ID_HEADER);
const clientId =
  rawClientId !== undefined &&
  rawClientId !== '' &&
  rawClientId.length <= MAX_CLIENT_ID_LENGTH &&
  CLIENT_ID_RE.test(rawClientId)
    ? rawClientId
    : undefined;

// Could be:
const rawClientId = req.get(CLIENT_ID_HEADER);
const clientId = parseClientIdHeader(req, res) ?? undefined;
// Note: parseClientIdHeader sends 400 response on invalid, so adjust as needed

🔵 Low

  • File: packages/core/src/telemetry/daemon-tracing.ts:168-177 - The addDaemonRequestAttribute function name is slightly misleading—it sets an attribute on the active span, not specifically on the request span. Consider renaming to addActiveSpanAttribute or adding a JSDoc comment clarifying its intended use case (i.e., only call when within a daemon request span context).

  • File: packages/cli/src/serve/server.ts:279-281 - The return type change for resolveDaemonTelemetryRoute adds permissionRequestId?: string but the function comment/type documentation isn't updated. Consider adding a brief JSDoc explaining the function's purpose and return structure.

  • File: packages/acp-bridge/src/bridge.test.ts:96-154 - The test now passes clientId via a fourth parameter to sendPrompt. Consider adding a comment explaining why clientId is passed separately from the PromptRequest object (i.e., it's telemetry context, not part of the prompt payload).

✅ Highlights

  • Excellent test coverage with 8 test cases in daemon-tracing, including edge cases for attribute omission and no-op behavior
  • The permission route regex patterns are well-structured and follow the existing pattern for session action routes
  • Good use of conditional spread syntax for optional attributes—clean and readable
  • The addDaemonRequestAttribute helper is a solid foundation for future telemetry enrichment (plumbing for feat(telemetry): cover qwen serve daemon end-to-end with OpenTelemetry #4554)
  • Proper error isolation with try-catch blocks ensuring telemetry never affects request handling

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds additional OpenTelemetry span attributes and span coverage to improve daemon/bridge observability in qwen serve, specifically identifying the daemon client and permission-vote requests.

Changes:

  • Add qwen-code.client_id span attribute to daemon HTTP request spans (validated from X-Qwen-Client-Id) and bridge prompt.dispatch spans (from BridgeClientRequestContext.clientId).
  • Add daemon request-span routing + attributes for permission vote endpoints, including qwen-code.daemon.permission.request_id.
  • Export addDaemonRequestAttribute() helper and add/adjust unit tests to cover the new attributes and helper behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/core/src/telemetry/index.ts Re-exports addDaemonRequestAttribute from daemon tracing utilities.
packages/core/src/telemetry/daemon-tracing.ts Adds optional clientId + permissionRequestId request-span attributes and introduces addDaemonRequestAttribute().
packages/core/src/telemetry/daemon-tracing.test.ts Extends daemon tracing tests to cover new attributes and the new helper.
packages/cli/src/serve/server.ts Extends daemon telemetry middleware route resolution to include permission vote routes and enriches request spans with validated client id + permission request id.
packages/acp-bridge/src/bridge.ts Adds qwen-code.client_id to prompt.dispatch span attributes when client context is present.
packages/acp-bridge/src/bridge.test.ts Updates telemetry test to assert client_id propagation on prompt.dispatch.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/cli/src/serve/server.ts
Comment thread packages/cli/src/serve/server.ts
Comment thread packages/cli/src/serve/server.ts
@wenshao

wenshao commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Maintainer Verification Report

Reviewer: @wenshao
Environment: macOS Darwin 25.4.0 / Node.js local build
Branch: feat/daemon-otel-client-id-permissionfeat/daemon-otel-e2e-design


Build

Step Result
npm run build (full monorepo) ✅ Pass (exit 0, 0 errors, 15 pre-existing lint warnings in unrelated vscode-ide-companion)
tsc --noEmit packages/core ✅ Pass (exit 0)
tsc --noEmit packages/cli ✅ Pass (exit 0)

Unit Tests

Package Test File Tests Result
@qwen-code/qwen-code-core daemon-tracing.test.ts 8 (4 new) ✅ All passed (7ms)
@qwen-code/acp-bridge bridge.test.ts 196 (1 updated) ✅ All passed (1008ms)

New Test Coverage

Test What It Verifies
includes clientId and permissionRequestId in request span attributes withDaemonRequestSpan correctly maps clientIdqwen-code.client_id and permissionRequestIdqwen-code.daemon.permission.request_id
omits clientId and permissionRequestId when not provided Span attributes are clean when optional fields are absent
addDaemonRequestAttribute sets attribute on the active span New helper correctly delegates to trace.getSpan().setAttribute()
addDaemonRequestAttribute is a no-op without an active span No-throw safety when no active span exists
Bridge test update Verifies clientId flows from sendPrompt() context through to prompt.dispatch span attributes

Code Review Notes

Changes are well-scoped and correct:

  1. daemon-tracing.ts: DaemonRequestSpanOptions extended with optional clientId / permissionRequestId; both conditionally spread into span attributes — clean pattern consistent with existing sessionId / workspaceHash handling. New addDaemonRequestAttribute() helper is correctly defensive (try/catch, optional chaining on getSpan()).

  2. server.ts: resolveDaemonTelemetryRoute() now matches two new permission routes (POST /session/:id/permission/:requestId and POST /permission/:requestId) with proper regex extraction. clientId extraction from X-Qwen-Client-Id header validates against CLIENT_ID_RE (/^[A-Za-z0-9._:-]+$/) and MAX_CLIENT_ID_LENGTH (128) — reuses existing constants, consistent with the existing parseClientId path.

  3. bridge.ts: Minimal 3-line change — conditionally spreads context.clientId into prompt.dispatch span attributes. Pattern matches the existing conditional spread style.

  4. index.ts: Clean re-export of addDaemonRequestAttribute.

No concerns found: No security issues (input is validated before use), no breaking changes, no unnecessary abstractions. The addDaemonRequestAttribute helper is well-motivated as plumbing for #4554 promptId enrichment.

Verdict

Ready to merge — all builds and tests pass, code is clean, well-tested, and consistent with existing patterns.

wenshao
wenshao previously approved these changes May 29, 2026
@doudouOUC doudouOUC changed the base branch from feat/daemon-otel-e2e-design to daemon_mode_b_main May 30, 2026 01:27
@doudouOUC doudouOUC dismissed wenshao’s stale review May 30, 2026 01:27

The base branch was changed.

…o daemon telemetry

Add qwen-code.client_id span attribute to daemon HTTP request spans and
bridge prompt.dispatch spans. Add telemetry coverage for permission vote
routes (POST /session/:id/permission/:requestId, POST /permission/:requestId).
Add addDaemonRequestAttribute helper for post-rebase promptId enrichment.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
@doudouOUC doudouOUC force-pushed the feat/daemon-otel-client-id-permission branch from a752447 to cea3628 Compare May 30, 2026 01:37
@doudouOUC doudouOUC requested a review from wenshao May 30, 2026 01:38
Comment thread packages/cli/src/serve/server.ts
@doudouOUC doudouOUC requested a review from chiga0 May 30, 2026 11:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants