test(e2e): otel trace completeness on streaming /v1/messages (LIT-3787) - #33247
Conversation
Greptile SummaryThis PR adds a streaming
Confidence Score: 5/5Test-only changes confined to All three changed files live entirely within No files require special attention.
|
| Filename | Overview |
|---|---|
| tests/e2e/models.py | Adds optional `stream: bool |
| tests/e2e/logging/logging_client.py | Extends messages_raw with a stream parameter; when true, routes through transport.stream() and sets stream=True on the body (using None for non-streaming to omit the field), mirroring the existing chat_raw pattern. |
| tests/e2e/logging/test_otel_trace_e2e.py | Adds test_messages_stream_exports_complete_trace that mirrors the existing chat completions streaming test: asserts event-stream content type, at least one chunk, exactly one gen-AI span, and litellm.request.streaming=true tag in the complete OTEL trace. |
Reviews (3): Last reviewed commit: "test(e2e): make the stream field coercio..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Covers the messages surface of logging.otel.stream.exports_metric: same tree contract as the non-streaming tests plus the stream-specific assertions (the response actually streamed, exactly one gen-AI span, and the span records litellm.request.streaming=true). Adds a stream field to the shared AnthropicMessagesBody and a stream mode to messages_raw
ac9c99c to
183bfb1
Compare
d862a91 to
22ceb38
Compare
…87) (#33262) * test(e2e): OTEL trace completeness on streaming /v1/responses Covers the responses surface of logging.otel.stream.exports_metric: same tree contract plus the stream-side assertions (event-stream content type, chunks consumed, exactly one gen-AI span). Two assertions are knowingly relaxed on this surface, both verified against live traces and tracked in LIT-4428: the responses route does not stamp litellm.request.streaming on the gen-AI span, and the spend write for a streamed responses call records spend correctly but emits no batch_write_to_db cost span. Adds a stream mode to responses_raw * test(e2e): parenthesize the settle-names ternary and make stream coercion explicit per review
c77bd78
into
litellm_e2e_otel_stream_chat_trace
…7) (#33247) * test(e2e): OTEL trace completeness on streaming /v1/messages Covers the messages surface of logging.otel.stream.exports_metric: same tree contract as the non-streaming tests plus the stream-specific assertions (the response actually streamed, exactly one gen-AI span, and the span records litellm.request.streaming=true). Adds a stream field to the shared AnthropicMessagesBody and a stream mode to messages_raw * test(e2e): make the stream field coercion explicit per review * test(e2e): otel trace completeness on streaming /v1/responses (LIT-3787) (#33262) * test(e2e): OTEL trace completeness on streaming /v1/responses Covers the responses surface of logging.otel.stream.exports_metric: same tree contract plus the stream-side assertions (event-stream content type, chunks consumed, exactly one gen-AI span). Two assertions are knowingly relaxed on this surface, both verified against live traces and tracked in LIT-4428: the responses route does not stamp litellm.request.streaming on the gen-AI span, and the spend write for a streamed responses call records spend correctly but emits no batch_write_to_db cost span. Adds a stream mode to responses_raw * test(e2e): parenthesize the settle-names ternary and make stream coercion explicit per review
Relevant issues
Linear ticket
https://linear.app/litellm-ai/issue/LIT-3787 (streaming follow-up; second of the streaming stack)
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
Screenshots / Proof of Fix
Stacked on the streaming /chat/completions PR (base of this branch); merge that first. Same infra, no new services. Verification run on 2026-07-14 at this branch's tip, proxies from source at exact refs. Outputs verbatim.
Evidence-first: a streamed /v1/messages call was driven by hand and its trace dumped from the destination before assertions were written. Exactly one gen-AI span, streaming fingerprint present:
Pass on current code (compose stack):
Fail-before-fix at 1bd603d (parent of fix(otel): one v2 logger owns the global provider; scope tenant OTLP creds per exporter #30590): the streamed call's gen-AI span arrives alone, dangling:
Static gates:
make lint-e2e-basedpyright-> 0 errors;coverage_registry.collector --strictpasses (the stream row is already counted covered by the chat test on the base branch; this PR adds the messages surface attribution viaexercised_on).Type
✅ Test
Changes
Second surface of the
logging.otel.stream.exports_metricrow: streamed/v1/messages. Same streaming lifecycle risk as chat (the gen-AI span closes from the stream-consumption path), verified to orphan identically at the foil commit.logging/test_otel_trace_e2e.py: addstest_messages_stream_exports_complete_tracewith the shared completeness contract plus the stream-specific assertions (event-stream content type, at least one chunk consumed, exactly ONE gen-AI span, andlitellm.request.streaming=trueon it, which a live trace confirms this surface stamps).models.py:AnthropicMessagesBodygains an optionalstreamfield (mirrorsChatBody).logging/logging_client.py:messages_rawgains astreammode that consumes the SSE body and counts events, mirroringchat_raw.Behavior changes
None; test-only changes under tests/e2e.
QA runbook
OpenTelemetryV2appears insuccess_callbacks{"models":["claude-haiku-4-5"],"key_alias":"otel-stream-messages-<uniq>"}and save the returned keycurl -NPOST /v1/messages with"stream": true,max_tokens: 16, and a unique phrase; retry the first call on 401 for a few seconds; confirmcontent-type: text/event-stream, thatdata:events actually arrive, and note thex-litellm-call-idresponse headerlitellm), search by taglitellm.call_id=<that id>and wait for the trace (spans flush in batches; the cost write lands last)POST /v1/messages(kind server) and no span referencing a parent missing from the traceauth /v1/messages, apostgres ...span, andbatch_write_to_db _PROXY_track_cost_callbackchat claude-haiku-4-5span (kind client), that its parent chain reaches the root, and that its tags includelitellm.request.streaming: trueFinal attestation: "I agree this test is testing what the writer wanted to test."