Repository navigation
Emit gen_ai.* attributes on APM spans - #12450
gh-worker-dd-mergequeue-cf854d[bot] merged 15 commits into
Conversation
Write the scalar gen_ai.* subset of an LLM Observability span onto the APM span, so model, provider, application, conversation and token usage become indexed, searchable APM tags. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
|
@codex review |
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. |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
The openai-java instrumentation keeps tracing when LLM Observability is disabled, and the operation, model, provider and ml_app are all known on that path. Token usage and conversation id are not computed there, so they stay unreported. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The repository does not accept new .groovy files. The module already has a JUnit forked-test base for LLMObs configurations, so the coverage moves there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
More details
The finish-time mapping reads only scalar LLM Observability tags. It keeps message bodies off APM spans and limits usage metrics to LLM and embedding spans.
🤖 Datadog Autotest · Commit 1527dca · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Codex Review: Didn't find any major issues. Keep it up! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both tests in the class produce an openai.request span, so taking the first one written let a late trace from the sibling test be asserted on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The attributes are derived from the LLMObs tag set, which the openai decorators do not build with LLM Observability off. Drop the fallback that resolved operation, model and ml_app from APM tags instead, and collapse GenAiApmTags back to a single apply(span). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sets _dd.llmobs.artificial_gen_ai_tags alongside the gen_ai.* attributes so the backend processor does not treat them as a user annotation and create a duplicate LLM Observability span. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This reverts commit eeeafa8.
The openai decorators read the token counts off every response, but only tagged them behind the LLMObs guard, so the disabled path carried the gen_ai scalars without any usage. Extract the counts above the guard and route them through TokenUsage, which writes the LLMObs metric when enabled and the gen_ai.usage.* APM metric when not. _ml_obs_metric.* stays behind the guard. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
wait until backend change is merged tuesday before merging. |
ncybul
left a comment
There was a problem hiding this comment.
Just a couple small questions but other than that LGTM!
vandonr
left a comment
There was a problem hiding this comment.
looks good overall, 2 minor comments
Matches the other three decorators, which all hand their usage object to a private static withUsage(AgentSpan, ...). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
What Does This Do
Emits the scalar
gen_ai.*attributes onto APM spans, making them indexed APM tags:gen_ai.operation.name,gen_ai.request.model,gen_ai.provider.name,gen_ai.application.name,gen_ai.conversation.idgen_ai.usage.{input,output,total,cache_read_input,cache_write_input,reasoning_output}_tokensGenAiApmTagsreads the values back off the span's_ml_obs_tag.*/_ml_obs_metric.*keys at finish time and is called from both emission sites: manual SDK spans (DDLLMObsSpan.finish) and auto-instrumentation (OpenAiDecorator.doBeforeFinish). SinceLLMObsSpanMapperonly serializes_ml_obs_*keys, the unprefixed tags land on the APM span only.Alongside them it sets the internal
_dd.llmobs.artificial_gen_ai_tagstag, marking the attributes as tracer-written rather than user-annotated. Without it the backend processor treats the APM span as a user-annotated gen_ai span and creates a duplicate LLM Observability span.Message bodies (input, output, tool definitions, retrieval documents) stay off the APM span and keep coming from the LLMObs track. Port of DataDog/dd-trace-py#20083, DataDog/dd-trace-py#20411 and DataDog/dd-trace-js#10261.
With LLM Observability disabled
The openai instrumentation still traces, so it still emits the attributes it can resolve. It does not build the LLMObs tag set in that configuration, so
OpenAiDecoratorpasses operation (fromopenai.request.endpoint), model and ml_app toGenAiApmTags.applydirectly, and the token counts it reads off every response are routed throughTokenUsagetogen_ai.usage.*instead of_ml_obs_metric.*.gen_ai.conversation.idis the one attribute with no APM-side source, so it is absent. This matches dd-trace-js.Motivation
The APM trace UI merges these keys from the LLMObs track client-side, so the values render but aren't indexed. You can't filter, facet, or monitor on model, provider, or token usage in APM.
Testing
testing streaming and non-streaming, llmobs enabled and disabled: 4 traces show up in query
showing up in query
embedding
🤖 Generated with Claude Code