Skip to content

refactor(tracing): normalize agent spans in Rust - #44071

Merged
ishaan-berri merged 8 commits into
mainfrom
litellm_rust_trace_normalizers
Oct 2, 2026
Merged

ishaan-berri merged 8 commits into
mainfrom
litellm_rust_trace_normalizers

Conversation

@yujonglee-berri

@yujonglee-berri yujonglee-berri commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Trace normalization is duplicated across Python and Rust
  • Normalized fields lack a shared typed contract

How it solves it:

  • Moves LangSmith, OpenInference, and GenAI normalization into Rust
  • Validates Rust output with Pydantic at the Python boundary
  • Checks normalized field mappings against live ClickHouse columns
  • Generates dashboard trace types from the API response models

Merge preservation

#43975: the bounded OTLP receiver, shared resource identity, and paged span diagnostics remain covered by tracing and bridge tests

#44035: lifespan-owned tracing, access scoping, and shutdown draining pass the route, lifecycle, and storage tests

#44068: Lens trace access, setup polling, and investigations pass 56 focused dashboard tests

Review evidence

The native bridge returns consumed_attributes as a Python tuple at the current tip. Direct execution with the LangSmith export returned ('gen_ai.prompt', 'gen_ai.completion'); the bridge conversion test passes

User Flow

Before: a developer imports a LangSmith trace and inspects its agent and LLM spans

  1. They POST the OTLP export to http://localhost:4097/v1/traces and receive HTTP 200 with {}
  2. They GET /v1/traces/4bad42b84e9de3ba46fc870185f8f023 and see six spans, one LLM call, two tool calls, and 3332 input tokens
  3. They GET /v1/traces/4bad42b84e9de3ba46fc870185f8f023/spans/8a6a1c31940d07af and see full tool call IDs and types

After: the same trace remains readable with the same fields while normalization runs in Rust

  1. They POST the same OTLP export to http://localhost:4098/v1/traces and receive HTTP 200 with {}
  2. They GET the same trace URL on port 4098 and see the same counts and request ID
  3. They GET the same span URL on port 4098 and see the same full tool call payload

Pre-Submission checklist

  • I have added meaningful tests
  • The handful of test files covering my change pass locally
  • My PR passes all required CI/CD checks
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review

Screenshots / Proof of Fix

Both runs used tests/test_litellm/tracing/fixtures/langsmith_deep_agent_export.json, local proxies, and separate PostgreSQL and ClickHouse databases

Before (a14af73)

  1. curl -X POST http://127.0.0.1:4097/v1/traces -H 'Authorization: Bearer <local key>' -H 'Content-Type: application/json' --data-binary @tests/test_litellm/tracing/fixtures/langsmith_deep_agent_export.json returned HTTP 200 and {}
  2. curl http://127.0.0.1:4097/v1/traces/4bad42b84e9de3ba46fc870185f8f023 -H 'Authorization: Bearer <local key>' returned HTTP 200 with span_count=6, llm_calls=1, tool_calls=2, input_tokens=3332, output_tokens=467, and LLM request ID chatcmpl-4077bb36-9380-4a3b-9481-245700cef09a
  3. curl http://127.0.0.1:4097/v1/traces/4bad42b84e9de3ba46fc870185f8f023/spans/8a6a1c31940d07af -H 'Authorization: Bearer <local key>' returned HTTP 200 with full tool call IDs and types

After (246bf31)

  1. The same POST on port 4098 returned HTTP 200 and {}
  2. The same trace GET on port 4098 returned HTTP 200; the full JSON response matched Before
  3. The same span GET on port 4098 returned HTTP 200; the full JSON response matched Before

Type

Refactoring

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

@yujonglee-berri
yujonglee-berri requested a review from a team October 1, 2026 20:39
@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[High risk] Moves span normalization logic from Python to Rust.

The PR appears safe to merge; the remaining new finding is a non-blocking Python type-contract mismatch.

Findings

  1. P2 Consumed attributes type mismatch ▶

Summary

The PR moves agent-span normalization into Rust, validates normalized fields at the Python boundary, checks their ClickHouse column mappings, and generates dashboard trace types from API response models.

  • The latest revision changes how consumed-attribute arrays cross the Rust–Python boundary and updates their Python annotation.

Reviews (3) · Last reviewed commit: "fix(tracing): type consumed attributes a..."

Comment thread litellm-rust/crates/traces/src/normalize/langsmith.rs
Comment thread litellm-rust/crates/traces/src/normalize/langsmith.rs Outdated
Comment thread litellm-rust/crates/traces/src/normalize/mod.rs
@codspeed

codspeed Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_rust_trace_normalizers (246bf31) with main (d7e6154)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (610576d) during the generation of this report, so d7e6154 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment thread litellm-rust/crates/traces/src/normalize/langsmith.rs
Comment thread litellm-rust/crates/traces/src/normalize/langsmith.rs Outdated
Comment thread litellm-rust/crates/traces/src/normalize/langsmith.rs Outdated
@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/rust_bridge/traces.py 84.61% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@yujonglee-berri
yujonglee-berri added this pull request to stack #44087 October 1, 2026 21:31
@yujonglee-berri

Copy link
Copy Markdown
Contributor Author

@greptile-apps wdyt

@yujonglee-berri

Copy link
Copy Markdown
Contributor Author

@greptile-apps The specific 3/5 rationale is not fair to this PR’s current diff. OTLP JSON identifier decoding was already on main; this PR leaves that code unchanged, and the existing hex ID fixture passes. This PR also changes no historical benchmark files. That work entered the merge base through #44057

Comment thread litellm/rust_bridge/traces.py

@ishaan-berri ishaan-berri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add UI screenshots showing tracing still works ?

@ishaan-berri
ishaan-berri merged commit ae6b762 into main Oct 2, 2026
109 of 110 checks passed
@ishaan-berri
ishaan-berri deleted the litellm_rust_trace_normalizers branch October 2, 2026 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants