From 99b240d66f5d0bb71dea5971ffb6d95e56059094 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Mon, 8 Jun 2026 15:55:41 -0700 Subject: [PATCH] fix(langchain): load LangChainTracer synchronously to avoid span loss The previous lazy `import("./tracer.js")` resolved on a later microtask, so any `_configureSync` call that landed before it resolved (typically the first compiled-StateGraph `invoke` after distro startup) silently fell through with no tracer attached. The outer `invoke_agent LangGraph` wrapper span was dropped and the trace fragmented into multiple roots. Bind LangChainTracer via a static import and field initializer, and remove the silent skip branch in the wrapped `_configureSync`. Safe because by the time `patch()` runs, `@langchain/core/callbacks/manager` is already loaded (it is the `module` argument). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../langchain/langchainTraceInstrumentor.ts | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/genai/instrumentations/langchain/langchainTraceInstrumentor.ts b/src/genai/instrumentations/langchain/langchainTraceInstrumentor.ts index ae6ebae..a8bb501 100644 --- a/src/genai/instrumentations/langchain/langchainTraceInstrumentor.ts +++ b/src/genai/instrumentations/langchain/langchainTraceInstrumentor.ts @@ -11,7 +11,7 @@ import { InstrumentationModuleDefinition, isWrapped, } from "@opentelemetry/instrumentation"; -import type { LangChainTracer } from "./tracer.js"; +import { LangChainTracer } from "./tracer.js"; type CallbackManagerModuleType = typeof CallbackManagerModule; type LangChainTracerCtor = new (tracer: Tracer) => LangChainTracer; @@ -21,10 +21,14 @@ class LangChainTraceInstrumentorImpl extends InstrumentationBase { - this._tracerCtor = m.LangChainTracer; - }, - (err) => { - diag.error( - `[LangChainTraceInstrumentor] Failed to load LangChainTracer: ${err instanceof Error ? err.message : String(err)}`, - ); - }, - ); - // eslint-disable-next-line @typescript-eslint/no-this-alias const instrumentor = this; this._wrap(CallbackManager, "_configureSync", (original) => { @@ -114,12 +102,8 @@ class LangChainTraceInstrumentorImpl extends InstrumentationBase ) { - if (instrumentor._tracerCtor) { - args[0] = addTracerToHandlers(instrumentor.otelTracer, args[0], instrumentor._tracerCtor); - diag.debug("[LangChainTraceInstrumentor] _configureSync wrapped to add LangChainTracer"); - } else { - diag.debug("[LangChainTraceInstrumentor] LangChainTracer not yet loaded, skipping"); - } + args[0] = addTracerToHandlers(instrumentor.otelTracer, args[0], instrumentor._tracerCtor); + diag.debug("[LangChainTraceInstrumentor] _configureSync wrapped to add LangChainTracer"); return original.apply(this, args); }; });