Hi all! I was wondering if somebody might be able to help me with getting the span ID I need to add feedback. I鈥檝e searched here for get_current_span langchain and read related GitHub issues on getting the current span/anscestors with auto-instrumenting a LangChain app and I still can鈥檛 get this to work. I鈥檓 initializing tracing in a Django app like so:
if INSTRUMENT_PHOENIX:
PHOENIX_BASE_URL = env.str(
"PHOENIX_BASE_URL",
default="",
)
from phoenix.otel import register
from openinference.instrumentation.langchain import LangChainInstrumentor
TRACER_PROVIDER = register(
project_name=env.str("PHOENIX_PROJECT_NAME", default="default"),
endpoint=env.str(
"PHOENIX_COLLECTOR_ENDPOINT", default=""
),
)
LangChainInstrumentor().instrument(tracer_provider=TRACER_PROVIDER)and I can鈥檛 seem to get the spans in any context:
from openinference.instrumentation.langchain import (
get_ancestor_spans,
get_current_span,
)
log.info(f"Ancestor Spans: {get_ancestor_spans()}")
log.info(f"Current span: {get_current_span()}")
2025-03-20 15:02:28 2025-03-20T15:02:28.246523Z [info ] Ancestor Spans: []
2025-03-20 15:02:28 2025-03-20T15:02:28.246834Z [info ] Current span: NoneHere are my dependencies:
arize-phoenix-otel==0.8.0
arize-phoenix-client==1.1.0
openinference-instrumentation-langchain==0.1.37The issue you're encountering with get_current_span and get_ancestor_spans returning None or empty lists might be related to context propagation in asynchronous operations or the setup of the LangChain instrumentation. According to the LangChain Instrumentation documentation, the LangChainInstrumentor should be initialized before any application code that creates spans. Ensure that the instrumentation is applied before any spans are created or retrieved.Additionally, the problem might be due to the context not being properly propagated across asynchronous boundaries. This is a known issue in some setups, as mentioned in this GitHub issue. You might want to verify that the context is correctly propagated and that the LangChainInstrumentor is correctly set up. If the issue persists, consider testing with synchronous code to see if the spans are correctly retrieved, which can help isolate whether the issue is specific to asynchronous execution.Would you like more detailed steps on how to troubleshoot this issue?Sources:
- LangChain Instrumentation documentation
- this GitHub issue
馃挕聽Hint: Mention RunLLM in the thread for followups.
sure, the workflow is like this:
create a chain in an async view
chain is created with RunnableWithMessageHistory and create_retrieval_chain
call the chain like so:
with get_openai_callback() as callback:
async for chunk in rag_chain.astreamI tried getting the span in the with get_openai_callback() as callback context and also the async for chunk loop. I basically tried getting the span everywhere, including he function that creates the chain. If there is an example that uses langchain instead of langgraph, that might be helpful.
we create the RunnableWithMessageHistory like so:
RunnableWithMessageHistory().with_config(
metadata=metadata,
run_name=run_name,
run_id=uuid.UUID(str(chat_run_id)),
)we assign a run id there but it鈥檚 not the same trace ID that is shown by Phoenix.
Hey Andrew S. - agree this is a bit confusing and we need a bit more examples. The engineer that added this utility is out so I'll try to see if anyone on the team can try to help. If it helps at all this is the commit that added this functionality (https://github.com/Arize-ai/openinference/commit/b4d78b0c2e48558c4e55ba3345badef22034f693) Sorry gotta run to a meeting but will follow-up if I can find an example.
Thanks, 馃敀[private user]! I tried your solution but still having issues. Just to clarify, should the trace ID in Phoenix correspond to the run_id assigned here:
RunnableWithMessageHistory().with_config(
metadata=metadata,
run_name=run_name,
run_id=uuid.UUID(str(chat_run_id)),
)They don鈥檛 match up and I鈥檓 wondering if Phoenix is somehow not respecting the custom run_id that we assign to our chain. gonna try this to next to see if I can get a run ID that matches up with the trace ID: https://docs.smith.langchain.com/observability/how_to_guides/trace_with_langchain#access-run-span-id-for-langchain-invocations
Maybe the run id we add to the chain config is being used for the session id in Phoenix as opposed to the trace id. I鈥檒l check that
Anyways, all the more reason to refactor and migrate away from langchain.
figured it out. adding this callback when I invoke the chain did the trick:
class LogSpansCallback(BaseCallbackHandler):
def on_llm_end(
self,
response: LLMResult,
*,
run_id: UUID,
parent_run_id: Optional[UUID] = None,
**kwargs: Any,
) -> Any:
log_spans(run_id, "on_llm_end")
def on_llm_start(
self,
serialized: dict[str, Any],
prompts: list[str],
*,
run_id: UUID,
parent_run_id: Optional[UUID] = None,
tags: Optional[list[str]] = None,
metadata: Optional[dict[str, Any]] = None,
**kwargs: Any,
) -> Any:
log_spans(run_id, "on_llm_start")
with get_openai_callback() as callback:
async for chunk in rag_chain.astream(
data,
{
"configurable": {"session_id": chat_session_id},
"callbacks": [LogSpansCallback()],
},
):Hey Andrew S. - really appreciate you digging in. I'm not an expert of LangChain so I'm glad you figured it out. In general you are correct - the run_ids in langchain are not the span or trace_ids since LangChain doesn't use opentelemetry. We maintain a mapping that you can resolve at runtime. Please let Roger Y. know if there are any ergonomic improvements we can make here and John G. and I will ensure we document this better. Thanks a bunch!
