Repository navigation
fix(otel): map Langfuse trace user, session, name, and tags in the v2 mapper - #35210
devin-ai-integration[bot] wants to merge 2 commits into
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
|
| metadata = payload.get("metadata") | ||
| requester = metadata.get("requester_metadata") if metadata else None | ||
| requester_meta: Mapping[str, object] = requester if isinstance(requester, Mapping) else {} | ||
| return cls( | ||
| session_id=as_str(requester_meta.get("session_id")), | ||
| trace_name=as_str(requester_meta.get("trace_name")), | ||
| user_id=as_str(requester_meta.get("trace_user_id")), |
There was a problem hiding this comment.
SDK trace controls are dropped
When an SDK call supplies trace_user_id, session_id, or trace_name directly in its metadata, this parser reads only the proxy-created requester_metadata snapshot, causing the Langfuse span to omit user.id, session.id, and langfuse.trace.name.
Knowledge Base Used: Logging & Observability Integrations
| return { | ||
| **collect(cls._LLM_CALL_ATTRS, data), | ||
| **collect(cls._BLOB_ATTRS, data), | ||
| f"{TRACE_METADATA_PREFIX}{key}": value | ||
| for key, value in data.annotations.requester_metadata.items() | ||
| if key in self._trace_metadata_keys |
There was a problem hiding this comment.
Greptile SummaryThis PR adds typed request annotations and config-aware Langfuse mapping for trace user, session, name, tags, and allowlisted metadata.
Confidence Score: 2/5The PR should not merge until trace controls work on non-proxy logging paths and caller metadata cannot replace authoritative team attribution. The new parser depends on a proxy-created metadata snapshot, while the mapper’s final metadata merge permits configured requester keys to overwrite authenticated team fields. Files Needing Attention: litellm/integrations/otel/model/metadata.py, litellm/integrations/otel/mappers/langfuse.py, litellm/integrations/otel/README.md
|
| Filename | Overview |
|---|---|
| litellm/integrations/otel/model/metadata.py | Adds typed annotations, but the proxy-specific requester_metadata source drops trace controls on current non-proxy logging paths. |
| litellm/integrations/otel/mappers/langfuse.py | Adds the requested Langfuse attributes, but allowlisted caller metadata can overwrite authoritative team attribution. |
| litellm/integrations/otel/model/config.py | Adds and normalizes the Langfuse metadata allowlist and threads it into mapper construction. |
| litellm/integrations/otel/model/payloads.py | Propagates RequestAnnotations from RequestContext into LLMCallSpanData. |
| litellm/integrations/otel/mappers/init.py | Makes mapper factories config-aware while preserving default construction behavior. |
| tests/test_litellm/integrations/otel/test_otel_v2_vendor_mappers.py | Covers ordinary trace controls and allowlisting but misses SDK metadata sourcing and reserved-key collisions. |
| litellm/integrations/otel/README.md | Documents the new configuration in-tree despite the repository requirement to keep customer documentation in litellm-docs. |
Comments Outside Diff (1)
-
litellm/integrations/otel/README.md, line 165-169 (link)Product documentation is misplaced
The new customer-facing environment variable and YAML configuration guidance belongs in the
litellm-docsrepository; keeping it here splits product documentation across repositories and bypasses the established publishing workflow.Rule Used: Prevent documentation from being added - needs to ... (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Reviews (1): Last reviewed commit: "chore(otel): drop added inline comments" | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
TLDR
Problem this solves:
langfuse_otelto the v2 mapper lost trace attributionHow it solves it:
RequestAnnotationsuser.id,session.id, trace name and tagslangfuse.trace.metadata.*only via an operator allowlistRelevant issues
Fixes #35192
Linear ticket
Pre-Submission checklist
Screenshots / Proof of Fix
Live proxy, real Anthropic call, console span exporter,
capture_message_content: no_content, so no prompt or response content is capturedBefore, at
4d54324515and withlangfuse_trace_metadata_keysdropped from the config since the field does not exist yet, the exported span carried the generation but none of the trace controls:After, at
60194646fc:internal_noteis absent because it is not inlangfuse_trace_metadata_keys, whileenvironmentisType
🐛 Bug Fix
Changes
RequestAnnotations(new, inmodel/metadata.py) is the typed view of the caller-supplied labels of a request, sitting next to the proxy-authoritativeRequestIdentity. On the proxy,StandardLoggingMetadatadrops every key it does not declare, so the named controls only survive in the verbatimmetadata.requester_metadatasnapshot; tags instead come from the payload's already-mergedrequest_tagsIt hangs off
RequestContextandLLMCallSpanData, so it is parsed once per request and needs no content captureThe Langfuse mapper gains four extractor-table entries:
These are trace-level keys carried on the generation observation, which is how Langfuse derives a trace from an OTLP span; absent controls stay absent rather than being emitted empty
langfuse.trace.metadata.<key>is emitted only for keys in the newlangfuse_trace_metadata_keysconfig field (env varLITELLM_OTEL_LANGFUSE_TRACE_METADATA_KEYS), empty by default, so a request can never push arbitrary metadata into the backend. That matches the shape of the existing Baggage allowlists. To wire it through,resolve_mappers(names, config)now hands each mapper factory the config, and behaviour is unchanged when it is omittedOne deliberate difference from
langfuse_otel: tags come fromrequest_tags, the payload's single merged source of request, key/team and header tags, so user-agent tags show up inlangfuse.trace.tagstooFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/42496f6660644a69859036d4300764e7