fix(langchain): propagate run name as trace name#1743
Conversation
| tags=parsed_trace_attributes.get("tags", None), | ||
| metadata=parsed_trace_attributes.get("metadata", None), | ||
| trace_name=parsed_trace_attributes.get("trace_name", None), | ||
| trace_name=parsed_trace_attributes.get("trace_name", span_name), |
There was a problem hiding this comment.
When
serialized carries no name information and the name kwarg is absent, get_langchain_run_name returns the sentinel string "<unknown>". With this change, "<unknown>" will now be propagated as the explicit trace name (it is non-None, so propagate_attributes won't filter it out and will write it into the OTel context). Before this PR the None default caused the trace_name attribute to be omitted entirely. Consider guarding against the sentinel so the pre-existing "no-name" behaviour is preserved for that edge case.
| trace_name=parsed_trace_attributes.get("trace_name", span_name), | |
| trace_name=parsed_trace_attributes.get( | |
| "trace_name", | |
| span_name if span_name != "<unknown>" else None, | |
| ), |
Prompt To Fix With AI
This is a comment left during a code review.
Path: langfuse/langchain/CallbackHandler.py
Line: 597
Comment:
When `serialized` carries no name information and the `name` kwarg is absent, `get_langchain_run_name` returns the sentinel string `"<unknown>"`. With this change, `"<unknown>"` will now be propagated as the explicit trace name (it is non-`None`, so `propagate_attributes` won't filter it out and will write it into the OTel context). Before this PR the `None` default caused the `trace_name` attribute to be omitted entirely. Consider guarding against the sentinel so the pre-existing "no-name" behaviour is preserved for that edge case.
```suggestion
trace_name=parsed_trace_attributes.get(
"trace_name",
span_name if span_name != "<unknown>" else None,
),
```
How can I resolve this? If you propose a fix, please make it concise.|
|
82edecc to
59dbb4d
Compare
59dbb4d to
1ba08f7
Compare
Summary
langfuse_trace_namemetadata as the override when providedFixes #1602
Tests
Greptile Summary
This PR fixes #1602 by propagating the LangChain root run name as the default trace name in Langfuse when no explicit
langfuse_trace_nameis provided in metadata.on_chain_start:parsed_trace_attributes.get(\"trace_name\", None)→parsed_trace_attributes.get(\"trace_name\", span_name), so the LangChain run name flows through as the trace name unless a user-specified override exists.propagate_attributesand asserts thattrace_nameequals thenamekwarg passed toon_chain_start, covering the primary regression path.Confidence Score: 4/5
The fix is minimal and correct — it threads the LangChain run name through to Langfuse when no explicit override is provided, and does not touch any other code paths.
The core change is a one-line default swap that works as described. The only wrinkle is that
get_langchain_run_namecan return"<unknown>"as a sentinel, and that sentinel will now be written into the OTel propagation context as an explicit trace name instead of being silently omitted. This is a narrow edge case (unnamed chains with no serialized id), but the behaviour change is observable in Langfuse traces.langfuse/langchain/CallbackHandler.py — specifically the
"<unknown>"sentinel path inget_langchain_run_nameFlowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A["on_chain_start called\n(parent_run_id is None)"] --> B["get_langchain_run_name()\n→ span_name"] B --> C["_parse_langfuse_trace_attributes(metadata, tags)\n→ parsed_trace_attributes"] C --> D{langfuse_trace_name\nin metadata?} D -- "Yes" --> E["trace_name = parsed_trace_attributes['trace_name']\n(explicit override)"] D -- "No (before PR)" --> F["trace_name = None\n(no name propagated)"] D -- "No (after PR)" --> G["trace_name = span_name\n(LangChain run name)"] G --> H{span_name resolved?} H -- "kwargs['name'] set" --> I["trace_name = kwargs['name']"] H -- "serialized['name'] set" --> J["trace_name = serialized['name']"] H -- "serialized['id'] set" --> K["trace_name = serialized['id'][-1]"] H -- "nothing set" --> L["trace_name = 'unknown'"] E --> M["propagate_attributes(trace_name=...)"] F --> N["propagate_attributes(trace_name=None)\n→ filtered out, no name set"] I --> M J --> M K --> M L --> M%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A["on_chain_start called\n(parent_run_id is None)"] --> B["get_langchain_run_name()\n→ span_name"] B --> C["_parse_langfuse_trace_attributes(metadata, tags)\n→ parsed_trace_attributes"] C --> D{langfuse_trace_name\nin metadata?} D -- "Yes" --> E["trace_name = parsed_trace_attributes['trace_name']\n(explicit override)"] D -- "No (before PR)" --> F["trace_name = None\n(no name propagated)"] D -- "No (after PR)" --> G["trace_name = span_name\n(LangChain run name)"] G --> H{span_name resolved?} H -- "kwargs['name'] set" --> I["trace_name = kwargs['name']"] H -- "serialized['name'] set" --> J["trace_name = serialized['name']"] H -- "serialized['id'] set" --> K["trace_name = serialized['id'][-1]"] H -- "nothing set" --> L["trace_name = 'unknown'"] E --> M["propagate_attributes(trace_name=...)"] F --> N["propagate_attributes(trace_name=None)\n→ filtered out, no name set"] I --> M J --> M K --> M L --> MPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "fix langchain trace name propagation" | Re-trigger Greptile