litellm/tests/unit/integrations/otel
yucheng-berri 38f318e736
fix(otel): decide per-team Arize sampling from the trace id so every pod agrees (#47468)
* fix(otel): decide per-team Arize sampling from the trace id so every pod agrees

* test(otel): cover per-team sampling across pods, workers, endpoints and restarts

* fix(otel): remember only a failed tree's sampling verdict so a later failed call answers to the error rate

A successful tree's verdict follows from the trace id alone, so remembering it only made a later failed call of the same trace follow the success rate on the pod that served both, while other pods judged it at the error rate

* test(otel): flush every worker before the restart cell kills it and cover a failed call after a dropped one

* fix(otel): decide team sampling per request, not per trace

Calls sharing a caller's trace id are separate requests, keyed by their root span.
Each is decided by the trace hash at the rate for its own outcome, and only its own
late spans follow its verdict, so no pod applies an earlier call's verdict to a later
call of the trace

* fix(otel): forget a span's request root when it ends, not when newer spans start

The root of each open span was kept in a first-in-first-out table of 16384 entries,
so a span two levels below the root that stayed open while the worker started more
spans than that lost its entry and ended under its parent's id. Its request then
never closed and was held from every sampled destination until shutdown.

Each open span now keeps its entry until it ends, and a span starting under a parent
that has already ended reads the root from the parent span itself

* fix(otel): decide a request as its spans end once it falls out of the open span table

A request whose span was pushed out of the table of open spans, because the worker
held more than 16384 open at once, ended that span under another key and was held
from every sampled destination until shutdown. Pushing a span out now drops its
request's open count too, so the request is decided as each of its spans ends, the
way one pushed out of the open request table already is

* test(otel): annotate the team sampling test locals as Final

* test(otel): build the caller's remote parent in one helper instead of rebinding it per trace

* fix(otel): keep each open span's request until it ends, bounded by the open requests

The span table had its own bound of 16384, so a worker holding more spans open than
that pushed out the oldest, and a failure in such a span no longer reached its
request. Each request now holds the ids of its open spans, and a span's entry in the
lookup goes when the span ends or when its request is pushed out of the open request
table, the same bound main already applies. A failure anywhere in a tracked request
reaches its verdict however many spans are open

---------

Co-authored-by: yucheng-berri <293926326+yucheng-berri@users.noreply.github.com>
2026-10-26 11:44:30 -07:00
..
__init__.py test: move tests/test_litellm integrations and secret_managers into tests/unit (#43194) 2026-09-25 12:57:07 -07:00
test_db_endpoint.py fix(otel): name postgres service spans by operation and table (#44240) 2026-10-03 09:20:28 -07:00
test_langfuse_logger.py fix(langfuse_otel)!: send the completion start time (#45597) 2026-10-20 13:52:26 +00:00
test_otel_v2_baggage.py fix(otel): emit OpenInference tool calls and metadata on Arize OTel v2 spans (#43698) 2026-10-08 15:53:07 -07:00
test_otel_v2_components.py fix(ci): unblock dependency security checks (#48055) 2026-10-23 14:05:46 -07:00
test_otel_v2_config_baggage_parenting_guardrails.py fix(otel): tolerate non-dict callback_settings.otel and ignore bare EXCLUDED_SERVICES env (#44086) 2026-10-02 12:36:46 -07:00
test_otel_v2_destinations.py fix(otel): decide per-team Arize sampling from the trace id so every pod agrees (#47468) 2026-10-26 11:44:30 -07:00
test_otel_v2_dynamic.py feat(otel): add SigNoz preset for OpenTelemetry v2 (#43296) 2026-09-26 18:15:45 -07:00
test_otel_v2_emitter.py fix(otel)!: leave out span cost when the price lookup failed (#44187) 2026-10-20 09:48:47 +00:00
test_otel_v2_logger.py fix(proxy)!: stop update_cache from resurrecting evicted auth cache entries (#46997) 2026-10-20 17:09:53 +00:00
test_otel_v2_metrics.py test: move tests/test_litellm integrations and secret_managers into tests/unit (#43194) 2026-09-25 12:57:07 -07:00
test_otel_v2_mount.py fix(ci): unblock dependency security checks (#48055) 2026-10-23 14:05:46 -07:00
test_otel_v2_multibackend.py test: move tests/test_litellm integrations and secret_managers into tests/unit (#43194) 2026-09-25 12:57:07 -07:00
test_otel_v2_presets.py fix(ci): unblock dependency security checks (#48055) 2026-10-23 14:05:46 -07:00
test_otel_v2_sources_of_truth.py feat(otel)!: let a team capture_message_content override the global setting for its OTel v2 destination (#44264) 2026-10-10 13:52:32 -07:00
test_otel_v2_vendor_mappers.py fix(langfuse_otel)!: send the completion start time (#45597) 2026-10-20 13:52:26 +00:00
test_runtime.py feat(otel): trace auto-router configuration and classifier failures (#44926) 2026-10-06 15:40:34 -07:00