Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(llmobs): improve langchain llmobs span names #9333

Merged
merged 9 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions ddtrace/llmobs/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@
SPAN_START_WHILE_DISABLED_WARNING = (
"Span started while LLMObs is disabled." " Spans will not be sent to LLM Observability."
)

LANGCHAIN_APM_SPAN_NAME = "langchain.request"
3 changes: 2 additions & 1 deletion ddtrace/llmobs/_trace_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from ddtrace.llmobs._utils import _get_llmobs_parent_id
from ddtrace.llmobs._utils import _get_ml_app
from ddtrace.llmobs._utils import _get_session_id
from ddtrace.llmobs._utils import _get_span_name


log = get_logger(__name__)
Expand Down Expand Up @@ -105,7 +106,7 @@ def _llmobs_span_event(self, span: Span) -> Dict[str, Any]:
"span_id": str(span.span_id),
"parent_id": str(_get_llmobs_parent_id(span) or "undefined"),
"session_id": session_id,
"name": span.name,
"name": _get_span_name(span),
"tags": self._llmobs_tags(span, ml_app=ml_app, session_id=session_id),
"start_ns": span.start_ns,
"duration": span.duration_ns,
Expand Down
7 changes: 7 additions & 0 deletions ddtrace/llmobs/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from ddtrace import Span
from ddtrace import config
from ddtrace.ext import SpanTypes
from ddtrace.llmobs._constants import LANGCHAIN_APM_SPAN_NAME
from ddtrace.llmobs._constants import ML_APP
from ddtrace.llmobs._constants import SESSION_ID

Expand All @@ -27,6 +28,12 @@ def _get_llmobs_parent_id(span: Span) -> Optional[int]:
return None


def _get_span_name(span: Span) -> str:
if span.name == LANGCHAIN_APM_SPAN_NAME and span.resource != "":
return span.resource.lower()
Yun-Kim marked this conversation as resolved.
Show resolved Hide resolved
return span.name


def _get_ml_app(span: Span) -> str:
"""
Return the ML app name for a given span, by checking the span's nearest LLMObs span ancestor.
Expand Down
2 changes: 1 addition & 1 deletion tests/llmobs/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def _llmobs_base_span_event(
"trace_id": "{:x}".format(span.trace_id),
"parent_id": _get_llmobs_parent_id(span),
"session_id": session_id or "{:x}".format(span.trace_id),
"name": span.name,
"name": span.resource.lower(),
"tags": _expected_llmobs_tags(span, tags=tags, error=error, session_id=session_id),
"start_ns": span.start_ns,
"duration": span.duration_ns,
Expand Down
12 changes: 12 additions & 0 deletions tests/llmobs/test_llmobs_trace_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ddtrace.llmobs._constants import INPUT_MESSAGES
from ddtrace.llmobs._constants import INPUT_PARAMETERS
from ddtrace.llmobs._constants import INPUT_VALUE
from ddtrace.llmobs._constants import LANGCHAIN_APM_SPAN_NAME
from ddtrace.llmobs._constants import METADATA
from ddtrace.llmobs._constants import METRICS
from ddtrace.llmobs._constants import ML_APP
Expand Down Expand Up @@ -360,6 +361,17 @@ def test_metrics_are_set():
assert tp._llmobs_span_event(llm_span)["metrics"] == {"tokens": 100}


def test_langchain_span_name_is_set_to_class_name():
"""Test span names for langchain auto-instrumented spans is set correctly."""
dummy_tracer = DummyTracer()
mock_llmobs_span_writer = mock.MagicMock()
with override_global_config(dict(_llmobs_ml_app="unnamed-ml-app")):
with dummy_tracer.trace(LANGCHAIN_APM_SPAN_NAME, resource="expected_name", span_type=SpanTypes.LLM) as llm_span:
llm_span.set_tag(SPAN_KIND, "llm")
tp = LLMObsTraceProcessor(llmobs_span_writer=mock_llmobs_span_writer)
assert tp._llmobs_span_event(llm_span)["name"] == "expected_name"


def test_error_is_set():
"""Test that error is set on the span event if it is present on the span."""
dummy_tracer = DummyTracer()
Expand Down
Loading