litellm/tests/test_litellm/integrations/otel
devin-ai-integration[bot] e7dd524a3c
feat(otel): stamp litellm.request.route on the LLM call span (#39698)
* feat(otel): stamp litellm.request.route on the LLM call span

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor(otel): drop redundant comment on REQUEST_ROUTE

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* style(otel): Final-annotate route test locals, drop field comment

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(otel): read litellm.request.route off the server span

The LLM call span took the auth-normalized literal path from logging
metadata, which disagrees with the SERVER span wherever FastAPI matched a
template: on /engines/{model:path}/chat/completions the LLM span spelled the
model name while http.route carried the template, so the two spans grouped
into different buckets and the PR's premise did not hold.

Read the value off the span that already holds it. The request's root SERVER
span is anchored per request for parenting, and its attributes stay readable
after it ends, so request_root_http_route() answers from the async close
callback with the same http.route the SERVER span exports: the route template
on a normal route, the literal path where the passthrough hook rewrote it, and
the mount point on an MCP call. Nothing has to re-derive any of that, so the
two spans cannot drift apart.

The route the proxy recorded at auth stays as the backstop for a deployment
whose FastAPI instrumentation never mounted, where there is no server span to
disagree with. Off the proxy the attribute is omitted rather than empty.

---------

Co-authored-by: shivam <shivam@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Yucheng He <yucheng@berri.ai>
2026-09-05 03:33:44 +00:00
..
test_db_endpoint.py feat(otel): attribute Prisma database spans to PostgreSQL instead of localhost (#36595) 2026-08-18 20:08:43 -07:00
test_langfuse_logger.py fix(otel): stamp the Langfuse root observation from the post-guardrail request and response 2026-09-02 13:12:05 -07:00
test_otel_v2_baggage.py feat(otel): allowlist team_metadata sub-keys promoted to baggage (#29442) 2026-06-01 14:02:23 -07:00
test_otel_v2_components.py fix(otel): emit cache token counts on OTel v2 LLM spans (#38716) 2026-08-31 13:59:59 -07:00
test_otel_v2_config_baggage_parenting_guardrails.py
test_otel_v2_dynamic.py fix(otel/v2): detach credential-routed tenant spans into their own trace (#38847) 2026-08-29 17:41:25 -07:00
test_otel_v2_emitter.py fix(otel): cap tool-definition attributes so they cannot evict gen_ai.* from the LLM span (#34828) 2026-07-30 12:01:10 -07:00
test_otel_v2_logger.py feat(otel): stamp litellm.request.route on the LLM call span (#39698) 2026-09-05 03:33:44 +00:00
test_otel_v2_metrics.py fix(logging): stop billing and logging response reads as LLM calls (#36890) 2026-08-26 18:34:17 -07:00
test_otel_v2_mount.py feat(otel): stamp litellm.request.route on the LLM call span (#39698) 2026-09-05 03:33:44 +00:00
test_otel_v2_multibackend.py
test_otel_v2_presets.py feat(newrelic): per-team New Relic trace routing via team callbacks (#37603) 2026-08-22 19:13:48 -07:00
test_otel_v2_sources_of_truth.py feat(otel): stamp litellm.request.route on the LLM call span (#39698) 2026-09-05 03:33:44 +00:00
test_otel_v2_vendor_mappers.py
test_runtime.py perf(otel): memoize per-request lazy import of otel runtime hooks (#31707) 2026-06-30 10:26:20 -07:00