Skip to content

feat(server-utils): Rewrite SentryLangChainInstrumentation to orchestrion#22266

Open
logaretm wants to merge 4 commits into
developfrom
feat/langchain-orchestrion
Open

feat(server-utils): Rewrite SentryLangChainInstrumentation to orchestrion#22266
logaretm wants to merge 4 commits into
developfrom
feat/langchain-orchestrion

Conversation

@logaretm

@logaretm logaretm commented Jul 14, 2026

Copy link
Copy Markdown
Member

Rewrites the LangChain integration to a node:diagnostics_channel listener instead of InstrumentationBase, with orchestrion injecting the channels. Follows the OpenAI/Anthropic/dataloader pattern; the vendored OTel path stays as the fallback when orchestrion isn't injected.

Some decisions due to some differences with other integrations:

  • Origin is auto.ai.langchain (spans come from the shared core handler/builder, not the subscriber). The dual-mode test still catches broken selectors: under orchestrion the OTel integration is filtered out, so wrong selectors yield zero spans.
  • Provider-skip (avoid double-instrumenting the underlying SDK) fires lazily on first langchain call, matching OTel timing; embeddings need it too since embedQuery/embedDocuments call the SDK internally.
  • @langchain/core range >=0.1.0 <2.0.0 covers langchain v0.3 and v1.

closes #20915

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 27.74 kB - -
@sentry/browser - with treeshaking flags 26.19 kB - -
@sentry/browser (incl. Tracing) 46.57 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.36 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.34 kB - -
@sentry/browser (incl. Tracing, Replay) 85.83 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 75.46 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 90.55 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 103.18 kB - -
@sentry/browser (incl. Feedback) 44.92 kB - -
@sentry/browser (incl. sendFeedback) 32.54 kB - -
@sentry/browser (incl. FeedbackAsync) 37.67 kB - -
@sentry/browser (incl. Metrics) 28.84 kB - -
@sentry/browser (incl. Logs) 29.07 kB - -
@sentry/browser (incl. Metrics & Logs) 29.76 kB - -
@sentry/react 29.54 kB - -
@sentry/react (incl. Tracing) 48.82 kB - -
@sentry/vue 33.17 kB - -
@sentry/vue (incl. Tracing) 48.55 kB - -
@sentry/svelte 27.77 kB - -
CDN Bundle 30.14 kB - -
CDN Bundle (incl. Tracing) 48.52 kB - -
CDN Bundle (incl. Logs, Metrics) 31.72 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 49.83 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 70.97 kB - -
CDN Bundle (incl. Tracing, Replay) 86.04 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 87.33 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 91.82 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 93.09 kB - -
CDN Bundle - uncompressed 89.85 kB - -
CDN Bundle (incl. Tracing) - uncompressed 146.66 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 94.56 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 150.64 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 219.28 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 265.86 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 269.82 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279.56 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 283.52 kB - -
@sentry/nextjs (client) 51.38 kB - -
@sentry/sveltekit (client) 47 kB - -
@sentry/core/server 78.66 kB -0.07% -49 B 🔽
@sentry/core/browser 65.09 kB +0.02% +8 B 🔺
@sentry/node-core 63.21 kB - -
@sentry/node 125.47 kB +0.02% +16 B 🔺
@sentry/node (incl. diagnostics channel injection) 143.15 kB +0.36% +508 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 70.03 kB +0.01% +2 B 🔺
@sentry/node/light 51.33 kB +0.01% +2 B 🔺
@sentry/node - without tracing 74.7 kB - -
@sentry/aws-serverless 83.92 kB - -
@sentry/cloudflare (withSentry) - minified 182.1 kB - -
@sentry/cloudflare (withSentry) 450.9 kB - -

View base workflow run

@logaretm logaretm marked this pull request as ready for review July 14, 2026 19:40
@logaretm logaretm requested a review from a team as a code owner July 14, 2026 19:40
@logaretm logaretm requested review from JPeer264, andreiborza, chargome, isaacs, s1gr1d and stephanie-anderson and removed request for a team, chargome and stephanie-anderson July 14, 2026 19:40

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6abf5e8. Configure here.

diagnosticsChannel.tracingChannel<EmbeddingsChannelContext>(channelName),
data => createEmbeddingsSpan(data, options),
{ captureError: () => ({ mechanism: { handled: false, type: 'auto.ai.langchain' } }) },
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedding errors double-reported

Medium Severity

The orchestrion LangChain embeddings binding enables captureError on bindTracingChannelToSpan, so rejected embedding calls call captureException while the underlying LangChain error still propagates to the caller. That can produce duplicate Sentry error events alongside the global unhandled-rejection path, unlike other orchestrion gen-AI channel integrations that omit captureError.

Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 6abf5e8. Configure here.

);

// Embeddings have no shared concrete method on the base class (each provider implements
// `embedQuery`/`embedDocuments`), so they're hooked per provider. Only `@langchain/openai` is wired

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: do we also only support openai in the otel path?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I wasn't sure how to do the others since unlike RITM/IITM we need exact matchers for the other providers and also need to check their implementations as it seems like not all 6 providers have the same capabilities.

Also some inherit from one another like Google's so it would cause double instrumentation. I had a clanker do it just now and document these cases.

@logaretm logaretm requested a review from nicohrubec July 16, 2026 14:50
@logaretm logaretm force-pushed the feat/langchain-orchestrion branch from 9c28a7a to 25b5c5c Compare July 16, 2026 15:02
logaretm added 3 commits July 16, 2026 11:37
Rewrites the LangChain integration to a diagnostics-channel listener
instead of `InstrumentationBase`, with orchestrion injecting the channels.

Chat models are hooked once on `@langchain/core`'s `BaseChatModel`
(`invoke` + `_streamIterator`), which every provider class inherits, so a
single module covers all providers. The listener injects the Sentry
callback handler into the call options, and LangChain's own callback
dispatch creates the spans exactly as before, so the span output is
identical. Embeddings have no shared base method, so they're hooked per
provider (`@langchain/openai` for now) and get their span via
`bindTracingChannelToSpan`, reusing the same core span builder as the
OTel path.

The OTel path stays as the fallback when orchestrion isn't injected. The
existing node-integration suite runs against both paths under
`INJECT_ORCHESTRION`, proving parity for langchain v0.3 and v1.
The OTel path covered 6 chat provider packages; chat is already handled by
the single @langchain/core BaseChatModel hook. For embeddings (the
per-package surface), wire the packages that ship an Embeddings subclass:
openai, google-genai, mistralai, and google-vertexai (whose methods live on
the shared @langchain/google-common base). anthropic and groq are chat-only.

The embeddings channel list is derived from the provider list so adding a
provider is a single edit.
@logaretm logaretm force-pushed the feat/langchain-orchestrion branch from 25b5c5c to e90583e Compare July 16, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite SentryLangChainInstrumentation to orchestrion

2 participants