Repository navigation
feat(daemon): receive Claude Code OTEL traces and forward spans - #332
Conversation
The AICodeOtel gRPC server now registers the OTLP TraceService. Spans are parsed into the new `spans` array of POST /api/v1/cc/otel: trace, span and parent ids as hex, start/end in nanoseconds, kind, status, the session id (session.id, else conversation.id, else another span of the same trace in the export) and the span's own attributes and events, without the per-span account identity. Large batches are split like events and metrics. `shelltime cc install` now sets CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 and OTEL_TRACES_EXPORTER=otlp, so `shelltime doctor` asks existing installs to run it again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ebmd3PkNoem9ubKNVA9K2K
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
⏱️
|
| Scenario | base | head | Δ | p | |
|---|---|---|---|---|---|
Startup/floor |
223 µs ±16% | 216 µs ±14% | ~ | 0.280 | A/A |
Startup/version |
3.50 ms ±22% | 3.24 ms ±10% | ~ | 0.315 | ✅ |
Track/daemon/pre |
3.27 ms ±33% | 3.57 ms ±20% | ~ | 0.579 | ✅ |
Track/daemon/post |
3.25 ms ±17% | 3.29 ms ±20% | ~ | 0.684 | ✅ |
Track/direct/pre |
3.51 ms ±26% | 3.45 ms ±19% | ~ | 0.912 | ✅ |
Track/direct/post |
6.63 ms ±11% | 6.69 ms ±14% | ~ | 0.529 | ✅ |
Track/direct/post-sync |
8.40 ms ±6% | 8.66 ms ±6% | ~ | 0.280 | ✅ |
Binary size: 19.2 MiB → 19.2 MiB (+0.0%).
CPU, tail latency and memory
Per exec, base → head (Δ when significant).
| Scenario | p95 wall | user CPU | sys CPU | peak RSS |
|---|---|---|---|---|
Startup/floor |
293 µs → 293 µs | 188 µs → 173 µs | 5 µs → 7 µs | 9.2 MiB → 9.2 MiB |
Startup/version |
4.80 ms → 4.48 ms | 1.96 ms → 1.92 ms | 1.36 ms → 1.30 ms | 15.6 MiB → 15.5 MiB (-0.57%) |
Track/daemon/pre |
4.37 ms → 4.96 ms | 1.88 ms → 2.13 ms | 1.45 ms → 1.44 ms | 16.5 MiB → 16.5 MiB |
Track/daemon/post |
4.66 ms → 4.33 ms | 1.99 ms → 1.93 ms | 1.41 ms → 1.44 ms | 16.4 MiB → 16.4 MiB |
Track/direct/pre |
4.87 ms → 4.72 ms | 2.08 ms → 2.02 ms | 1.54 ms → 1.45 ms | 16.4 MiB → 16.4 MiB |
Track/direct/post |
8.55 ms → 8.49 ms | 4.51 ms → 4.32 ms | 2.08 ms → 2.38 ms | 17.7 MiB → 17.6 MiB (-0.34%) |
Track/direct/post-sync |
10.98 ms → 11.00 ms | 5.51 ms → 5.83 ms | 3.11 ms → 3.26 ms | 19.7 MiB → 19.6 MiB (-0.34%) |
benchstat
goos: linux
goarch: amd64
pkg: github.com/malamtime/cli/perf
cpu: AMD EPYC
│ base │ head │
│ sec/op │ sec/op vs base │
Startup/floor-2 222.6µ ± 16% 216.1µ ± 14% ~ (p=0.280 n=10)
Startup/version-2 3.502m ± 22% 3.243m ± 10% ~ (p=0.315 n=10)
Track/daemon/pre-2 3.266m ± 33% 3.569m ± 20% ~ (p=0.579 n=10)
Track/daemon/post-2 3.251m ± 17% 3.291m ± 20% ~ (p=0.684 n=10)
Track/direct/pre-2 3.507m ± 26% 3.453m ± 19% ~ (p=0.912 n=10)
Track/direct/post-2 6.630m ± 11% 6.689m ± 14% ~ (p=0.529 n=10)
Track/direct/post-sync-2 8.400m ± 6% 8.663m ± 6% ~ (p=0.280 n=10)
geomean 2.873m 2.881m +0.26%
│ base │ head │
│ p50-sec/op │ p50-sec/op vs base │
Startup/floor-2 207.5µ ± 18% 187.9µ ± 13% ~ (p=0.190 n=10)
Startup/version-2 3.319m ± 21% 3.167m ± 13% ~ (p=0.796 n=10)
Track/daemon/pre-2 3.189m ± 33% 3.517m ± 17% ~ (p=0.684 n=10)
Track/daemon/post-2 3.193m ± 16% 3.145m ± 22% ~ (p=0.631 n=10)
Track/direct/pre-2 3.477m ± 27% 3.348m ± 20% ~ (p=0.853 n=10)
Track/direct/post-2 6.420m ± 14% 6.482m ± 18% ~ (p=0.579 n=10)
Track/direct/post-sync-2 8.239m ± 9% 8.588m ± 8% ~ (p=0.218 n=10)
geomean 2.782m 2.762m -0.71%
│ base │ head │
│ p95-sec/op │ p95-sec/op vs base │
Startup/floor-2 293.4µ ± 9% 292.8µ ± 28% ~ (p=0.853 n=10)
Startup/version-2 4.800m ± 25% 4.476m ± 10% ~ (p=0.393 n=10)
Track/daemon/pre-2 4.367m ± 39% 4.960m ± 13% ~ (p=0.481 n=10)
Track/daemon/post-2 4.658m ± 13% 4.334m ± 19% ~ (p=0.353 n=10)
Track/direct/pre-2 4.872m ± 31% 4.725m ± 16% ~ (p=0.971 n=10)
Track/direct/post-2 8.551m ± 14% 8.487m ± 9% ~ (p=0.796 n=10)
Track/direct/post-sync-2 10.98m ± 6% 11.00m ± 5% ~ (p=0.912 n=10)
geomean 3.874m 3.845m -0.75%
│ base │ head │
│ peak-rss-B │ peak-rss-B vs base │
Startup/floor-2 9.214Mi ± 1% 9.208Mi ± 2% ~ (p=0.591 n=10)
Startup/version-2 15.62Mi ± 0% 15.53Mi ± 0% -0.57% (p=0.000 n=10)
Track/daemon/pre-2 16.53Mi ± 0% 16.52Mi ± 0% ~ (p=0.781 n=10)
Track/daemon/post-2 16.43Mi ± 0% 16.42Mi ± 0% ~ (p=0.342 n=10)
Track/direct/pre-2 16.41Mi ± 0% 16.40Mi ± 0% ~ (p=0.724 n=10)
Track/direct/post-2 17.67Mi ± 0% 17.61Mi ± 0% -0.34% (p=0.000 n=10)
Track/direct/post-sync-2 19.69Mi ± 0% 19.62Mi ± 0% -0.34% (p=0.000 n=10)
geomean 15.58Mi 15.55Mi -0.20%
│ base │ head │
│ sys-sec/op │ sys-sec/op vs base │
Startup/floor-2 5.415µ ± 132% 7.355µ ± 42% ~ (p=0.971 n=10)
Startup/version-2 1.356m ± 25% 1.302m ± 25% ~ (p=0.739 n=10)
Track/daemon/pre-2 1.451m ± 29% 1.441m ± 45% ~ (p=0.971 n=10)
Track/daemon/post-2 1.407m ± 30% 1.437m ± 48% ~ (p=0.579 n=10)
Track/direct/pre-2 1.536m ± 44% 1.452m ± 37% ~ (p=0.853 n=10)
Track/direct/post-2 2.076m ± 43% 2.384m ± 21% ~ (p=0.218 n=10)
Track/direct/post-sync-2 3.110m ± 8% 3.263m ± 13% ~ (p=0.353 n=10)
geomean 761.6µ 807.5µ +6.02%
│ base │ head │
│ user-sec/op │ user-sec/op vs base │
Startup/floor-2 187.7µ ± 13% 172.6µ ± 10% ~ (p=0.123 n=10)
Startup/version-2 1.964m ± 17% 1.920m ± 9% ~ (p=1.000 n=10)
Track/daemon/pre-2 1.878m ± 27% 2.126m ± 18% ~ (p=0.280 n=10)
Track/daemon/post-2 1.992m ± 9% 1.930m ± 9% ~ (p=0.971 n=10)
Track/direct/pre-2 2.083m ± 14% 2.023m ± 8% ~ (p=0.796 n=10)
Track/direct/post-2 4.507m ± 10% 4.316m ± 14% ~ (p=0.436 n=10)
Track/direct/post-sync-2 5.510m ± 16% 5.833m ± 7% ~ (p=0.481 n=10)
geomean 1.840m 1.832m -0.42%
Δ compares medians; ~ means no significant difference (Mann-Whitney U, p ≥ 0.05). A scenario is flagged when it is more than 10% and more than 250µs slower with p < 0.05. Startup/floor runs true, not shelltime: it is an A/A check of runner noise. Runner: linux/amd64, AMD EPYC. go1.27.1, 10 rounds × 100 execs per scenario and binary.
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 3 files with indirect coverage changes 🚀 New features to boost your workflow:
|
☁️ Claude Code cloud session
119.1M tokens: 109.3K input · 220.1K output · 118.2M cache read · 655.6K cache write View this session on ShellTime → Updated 2026-10-23 03:27 UTC by ShellTime · totals for the whole session so far · the session page is visible to its owner |
|
/claude review Generated by Claude Code |
|
@claude review Generated by Claude Code |
|
Claude finished @AnnatarHe's task in 22s —— View job Review of #332: Claude Code OTEL tracesI read the diff ( Worth checking
Minor
What looks good
|
Review follow-ups: span and event names are capped like the other forwarded text (2 KB), the dropped identity attributes are commented, and span kinds and status codes get a table test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ebmd3PkNoem9ubKNVA9K2K
|
Thanks. Changed in 8ed6568: point 4 and the two minor nits. The rest stay as they are:
Minor: the dropped identity case now has a comment, and Generated by Claude Code |
What
The AICodeOtel gRPC server only registered the OTLP metrics and logs services, so Claude Code's traces (
OTEL_TRACES_EXPORTER) had nowhere to go. This PR adds trace support end to end on the CLI side.daemon/aicode_otel_server.goregisterscolltracev1.TraceService.ProcessTraces(daemon/aicode_otel_processor.go) turns each span into amodel.AICodeOtelSpan:session.id, elseconversation.id, else another span of the same trace in the exportuser.*,organization.id) is left out because it repeats on every span.spansarray ofPOST /api/v1/cc/oteland are split bySplitAICodeOtelRequestlike events and metrics. The server side is shelltime/server#560; older servers ignore the key.shelltime cc installnow also setsCLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1andOTEL_TRACES_EXPORTER=otlpin~/.claude/settings.json; both are needed for traces per the Claude Code monitoring docs.shelltime doctorlists them as missing for existing installs, so users get the "runcc installagain" hint.trace_exporterthemselves.codex installdoesn't enable it, since Codex spans are internal tracing (session_loop, …) rather than LLM and tool spans.Tests
daemon/aicode_otel_traces_test.go: span parsing (interaction, failedllm_requestwith a retry event), invalid ids and times, the event cap, Codexconversation.id, session fill-in within a trace, and a gRPC round trip whose JSON reaches the backend.model: span splitting stays within the byte budget and keeps order; the settings tests cover the two new keys.go test ./daemon/ ./model/passes.commandstrack tests (TestTrackWithSendData,TestMultipTrackWithPre) fail in this container on untouchedmaintoo, so that's the environment, not this change.HOME, port 54099) took synthetic Claude Code logs and traces and forwarded them to a local server running shelltime/server#560;spansProcessed=30.Merge after shelltime/server#560 is deployed.
Generated by Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.