Skip to content

feat(observability): parse client session_id out of JSON-encoded metadata.user_id#248

Merged
steventohme merged 1 commit into
mainfrom
steven/router-client-session-id-json
May 25, 2026
Merged

feat(observability): parse client session_id out of JSON-encoded metadata.user_id#248
steventohme merged 1 commit into
mainfrom
steven/router-client-session-id-json

Conversation

@steventohme
Copy link
Copy Markdown
Collaborator

Summary

Claude Code (post 0.x) sends metadata.user_id as a stringified JSON object — e.g. {\"device_id\":\"...\",\"session_id\":\"<uuid>\",\"account_id\":\"...\"}. The previous extractor (shipped in #247) regex-matched on the raw string and, because that JSON is longer than 64 chars, returned a truncated blob starting with {\"device_id\":\"… instead of the bare session UUID. Result: client_session_id was in the logs, but the value the user sees in Claude Code's /status didn't grep.

This PR makes ClientSessionID try JSON-parsing first when the raw value looks like a JSON object, probing the well-known session-id field names in order — session_id, sessionId, conversation_id, conversationId — and only falling through to the existing regex + truncation behavior when nothing matches.

Test plan

  • go test ./internal/translate/... ./internal/proxy/... -count=1
  • wv mr tc
  • New test cases:
    • Claude Code stringified JSON with session_id → bare UUID
    • Stringified JSON with sessionId (camelCase) → bare UUID
    • JSON object with no recognized key → falls back to 64-char truncation
  • After deploy: confirm client_session_id=<bare-uuid> in prod logs (no leading {), matching /status UUID in Claude Code.

🤖 Generated with Claude Code

…data.user_id

Claude Code (post 0.x) sends metadata.user_id as a stringified JSON
object — e.g. {"device_id":"…","session_id":"<uuid>","account_id":"…"} —
so the previous regex-only extractor returned a truncated blob starting
with "{\"device_id\":\"…" instead of the bare session UUID. Operators
running /status in Claude Code can now grep router logs by the UUID the
client shows them.

ClientSessionID now probes session_id / sessionId / conversation_id /
conversationId when the raw value parses as a JSON object, then falls
through to the existing regex + truncation behavior for non-JSON forms.
@steventohme steventohme merged commit 361fba1 into main May 25, 2026
7 checks passed
@steventohme steventohme deleted the steven/router-client-session-id-json branch May 25, 2026 23:04
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.

1 participant