Subject: Accessing and Modifying Auto-Instrumented LangChain Spans in Async LangGraph - Help Needed! Hi everyone, I’m facing an issue trying to access and modify the auto-instrumented spans generated by LangChain within my asynchronous LangGraph workflow. I’m hoping someone can point me in the right direction. Problem: When I use trace.get_current_span() inside my data_retriever_node function, I’m getting a NonRecordingSpan with all zeros for trace and span IDs. This indicates I’m not accessing the actual LangChain-generated span, which I need to modify. Code Snippets: Initialization Code (set_trace_provider):
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace.exporter import OTLPSpanExporter
from opentelemetry.instrumentation.langchain import LangchainInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.trace import SpanContext, TraceFlags, NonRecordingSpan
from opentelemetry.context import attach, detach
from openinference.instrumentation.openai import OpenAIInstrumentor
from phoenix.otel import register
import logging
import uuid
import random
import os
def set_trace_provider(service_name: str = "copilot", is_instrument_langchain_enable: bool = False, is_openai_instrument_enable: bool = False) -> None:
_tracer_provider = None
otlp_exporter_enpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", None)
if is_instrument_langchain_enable or is_openai_instrument_enable:
_tracer_provider = register(project_name=service_name, set_global_tracer_provider=False)
else:
resource = Resource.create({"service.name": service_name})
_tracer_provider = TracerProvider(resource=resource)
grpc_exporter = OTLPSpanExporter(endpoint=otlp_exporter_enpoint,
insecure=os.getenv("OTEL_EXPORTER_OTLP_INSECURE", True))
_tracer_provider.add_span_processor(BatchSpanProcessor(grpc_exporter))
trace.set_tracer_provider(_tracer_provider)
if is_instrument_langchain_enable:
LangchainInstrumentor().instrument()
if is_openai_instrument_enable:
OpenAIInstrumentor().instrument(tracer_provider=_tracer_provider)
def gettracer(name: str = __name__) -> trace.Tracer:
return trace.get_tracer(name)Code where I’m trying to access the span (data_retriever_node):
from opentelemetry import trace
from opentelemetry.util.context import context_with_attributes
async def data_retriever_node(state: dict) -> dict:
# Trying to get current span
current_span = trace.get_current_span()
print("\n= Current Auto-instrumented Span =")
print(f"Span Type: {type(current_span)}")
print(f"Span Context: {current_span.get_span_context()}")
print("=")
tool_call = state["messages"][-1].tool_calls[0]
query = tool_call["args"]["query"]
metadata = {
"tool_query": query,
"tool_type": "data_retriever",
"tool_call_id": tool_call["id"]
}
with context_with_attributes(attributes=metadata):
# Rest of the code...
passOutput:
query: What are the top brands by sales?
= Current Auto-instrumented Span =
Span Type: <class 'opentelemetry.trace.span.NonRecordingSpan'>
Span Context: SpanContext(trace_id=0x00000000000000000000000000000000, span_id=0x0000000000000000, trace_flags=0x00, trace_state=[], is_remote=False)
=Question: How can I correctly access and modify the auto-instrumented LangChain span within my data_retriever_node function in this asynchronous LangGraph context? I need to add custom attributes to the existing spans, not create new ones. Additional Context:
LangChain auto-instrumentation is enabled.
The code runs in an asynchronous LangGraph environment.
I can see LangChain spans in my telemetry system, so the instrumentation is generally working.
I want to add custom attributes to the existing LangChain spans using context_with_attributes.
To correctly access and modify the auto-instrumented LangChain spans within your asynchronous LangGraph context, you need to ensure that the OpenTelemetry context is properly propagated across asynchronous boundaries. The issue you're facing with NonRecordingSpan typically arises because the context is not being maintained across async calls. Here are some steps to address this: 1. Ensure Proper Context Propagation: Use context managers or ensure that the OpenTelemetry context is properly maintained across async calls. You can use context.with to set the active context for your async operations.2. Use LangChain's Instrumentation: Instead of using trace.get_current_span(), import get_current_span from openinference.instrumentation.langchain to access the current span in LangChain's context. This is specifically designed to work with LangChain's auto-instrumentation.Here's how you can modify your data_retriever_node function: LBKSfrom openinference.instrumentation.langchain import get_current_span from opentelemetry.context import context_with_attributesLBKSasync def data_retriever_node(state: dict) -> dict: # Get the current span using LangChain's instrumentation current_span = get_current_span()LBKS if current_span is not None: print("\n= Current Auto-instrumented Span =") print(f"Span Type: {type(current_span)}") print(f"Span Context: {current_span.get_span_context()}") print("=")LBKS tool_call = state["messages"][-1].tool_calls[0] query = tool_call["args"]["query"]LBKS metadata = { "tool_query": query, "tool_type": "data_retriever", "tool_call_id": tool_call["id"] }LBKS # Use context_with_attributes to add custom attributes with context_with_attributes(attributes=metadata): # Add attributes to the current span current_span.set_attributes(metadata) # Rest of the code... pass else: print("No active span found.")LBKSBy using get_current_span from LangChain's instrumentation, you should be able to access the correct span and modify it with custom attributes.Sources:
- Capture Feedback
- Custom Spans
💡 Hint: Mention RunLLM in the thread for followups.
from opentelemetry.context import context_with_attributesfrom what sdk do we get this ?
can you try importing from openinference instead? like this
from openinference.instrumentation.langchain import get_current_span
span = get_current_span()
if span is not None:
span.set_attribute(...)This error trace tells us several important things:
The core error is: python AttributeError: 'LangChainInstrumentor' object has no attribute '_tracer'
The error occurs in OpenInference’s implementation: python File ".../openinference/instrumentation/langchain/__init__.py", line 65, in get_span return self._tracer.get_span(run_id) if self._tracer else None
The error propagation path:
Starts in data_retriever_node when calling get_current_span()
Goes through LangGraph’s async execution chain
Eventually results in a PlatformException
was instrumentation enabled?
yes, i can see auto instrumented traces on UI
ok thanks. i’m not sure how to reproduce this yet. Can you please provide a bit more context in terms of where and how you are calling get_current_span()?
i can see auto instrumented traces on UI
do you see langchain spans in particular? in other words, has the code excerpt below been executed?
if is_instrument_langchain_enable:
LangchainInstrumentor().instrument(tracer_provider=tracer_provider)