feat(observability): add v2 genai tracing - #35935
Conversation
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
|
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate FoundPR #34633: feat(observability): Implement OTel telemetry parity for agents and tools Why it might be related:
Recommendation: Check if PR #34633 is still open/active and review its scope to understand if your v2 implementation is complementary or overlapping with existing work. |
|
This looks really awesome. I'm eager to get otel really wired up with opencode for a project I am working on. I can sort of hack opencode with the popular otel plugin to do what I want with modifications, but it would be great if opencode itself would accept traceparent header and stamp that on all the otel related traces like tools, sessions, etc. I had AI write up some of my thoughts that I had it scan everywhere trying to see what was in the works for otel in v2, seems like otel issues/prs arent going anywhere in 1.X, likely in favor of v2 which makes a ton of sense. One thing I'd love to see: could opencode accept a What we're afterWe run
On the per-turn root thingI saw each turn is deliberately its own root trace and I think that's the right default, a conversation span held open for hours would be worse. This wouldn't really change that. It'd still be one trace per turn, just rooted at the caller when a caller passes context. Looks mostly wired already?
Also worth mentioning #37395 landed on v2 after you opened this and makes the server pick up inbound traceparent on request fibers, so you might end up in this code on rebase anyway. Couple of things to considerOn websockets it'd have to ride on the message rather than the upgrade, since the connection isn't the turn. And since message content can come from untrusted places it probably wants to be opt-in, so nobody can graft their spans onto someone else's trace. OtherwiseIf parenting isn't something you want to do here, even just a span link to the inbound context would help. Happy to test against a real OTLP stack if that's useful. |
|
Would you consider supporting opt-in model content capture? The OTel GenAI conventions classify gen_ai.system_instructions, gen_ai.input.messages, and gen_ai.output.messages as opt-in, recommending that instrumentation keep them disabled by default but provide a way to enable them. A flag such as OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, defaulting to false, could preserve the PR’s safe defaults while enabling debugging and evaluation use cases. Ideally, captured values would follow the OTel schemas and support filtering or truncation. Is this planned here or as a follow-up |
Adds end-to-end V2 GenAI observability through OTLP. It records one trace per agent turn, model steps, HTTP and WebSocket transport, local tools, hosted-tool events, retries, compaction, subagents, and structured lifecycle failures. It also documents Dash0 setup and conversation navigation.
Only explicit operation boundaries create spans. Provider trace propagation remains disabled, URL queries are omitted, and prompts, model output, tool arguments, credentials, provider bodies, and raw exception messages are not recorded on spans. Existing retry, scheduling, and tool behavior remains unchanged.
Trace shape
Tool spans are siblings of model spans so concurrent tools can finish without outliving their model parent. Model transport spans require an explicit model span; unrelated Effect and HTTP spans remain disabled.
Conversations and subagents
Each turn is a separate root trace identified by
gen_ai.conversation.id. A new turn links to the previous turn withopencode.link.type=previous_turn, allowing linked-trace navigation without keeping a conversation span open for hours. Turn links are bounded and process-local;gen_ai.conversation.idremains the canonical correlation key across restarts.Foreground subagents remain nested beneath
execute_tool subagent. Background subagents start separate root traces and link to the spawning tool withopencode.link.type=subagent. Parent and child Sessions are also correlated withopencode.session.parent.idandopencode.subagent.session.id.Design principles
chat <model>span per model step.