Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions langfuse/_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,8 @@ def start_observation(
cast(otel_trace_api.Span, remote_parent_span)
):
otel_span = self._otel_tracer.start_span(name=name)
otel_span.set_attribute(LangfuseOtelSpanAttributes.AS_ROOT, True)
if parent_span_id is None:
otel_span.set_attribute(LangfuseOtelSpanAttributes.AS_ROOT, True)

return self._create_observation_from_otel_span(
otel_span=otel_span,
Expand Down Expand Up @@ -1099,6 +1100,7 @@ def start_as_current_observation(
as_type=as_type,
name=name,
remote_parent_span=remote_parent_span,
is_root=parent_span_id is None,
parent=None,
end_on_exit=end_on_exit,
input=input,
Expand Down Expand Up @@ -1164,6 +1166,7 @@ def start_as_current_observation(
as_type=as_type,
name=name,
remote_parent_span=remote_parent_span,
is_root=parent_span_id is None,
parent=None,
end_on_exit=end_on_exit,
input=input,
Expand Down Expand Up @@ -1270,13 +1273,23 @@ def _get_observation_type_from_otel_span(otel_span: otel_trace_api.Span) -> str:

return observation_type if isinstance(observation_type, str) else "span"

def _get_observation_type(
self,
span_class: Type[Any],
) -> ObservationTypeLiteralNoEvent:
"""Get the observation type string from a span class."""
observation_type = getattr(span_class, "_observation_type", "span")

return observation_type if isinstance(observation_type, str) else "span"

@_agnosticcontextmanager
def _create_span_with_parent_context(
self,
*,
name: str,
parent: Optional[otel_trace_api.Span] = None,
remote_parent_span: Optional[otel_trace_api.Span] = None,
is_root: bool = False,
as_type: ObservationTypeLiteralNoEvent,
end_on_exit: Optional[bool] = None,
input: Optional[Any] = None,
Expand Down Expand Up @@ -1312,7 +1325,7 @@ def _create_span_with_parent_context(
cost_details=cost_details,
prompt=prompt,
) as langfuse_span:
if remote_parent_span is not None:
if is_root:
langfuse_span._otel_span.set_attribute(
LangfuseOtelSpanAttributes.AS_ROOT, True
)
Expand Down Expand Up @@ -1693,7 +1706,8 @@ def create_event(
otel_span = self._otel_tracer.start_span(
name=name, start_time=timestamp
)
otel_span.set_attribute(LangfuseOtelSpanAttributes.AS_ROOT, True)
if parent_span_id is None:
otel_span.set_attribute(LangfuseOtelSpanAttributes.AS_ROOT, True)

return cast(
LangfuseEvent,
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_otel.py
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ def test_custom_parent_span_id(self, langfuse_client, memory_exporter):
spans = self.get_spans_by_name(memory_exporter, "custom-parent-span")
assert len(spans) == 1, "Expected one span"
assert spans[0]["trace_id"] == trace_id
assert spans[0]["attributes"][LangfuseOtelSpanAttributes.AS_ROOT] is True
assert LangfuseOtelSpanAttributes.AS_ROOT not in spans[0]["attributes"]

def test_multiple_generations_in_trace(self, langfuse_client, memory_exporter):
"""Test creating multiple generation spans within the same trace."""
Expand Down