Skip to content

Conversation

@RulaKhaled
Copy link
Member

@RulaKhaled RulaKhaled commented Oct 20, 2025

When using higher-level integrations that wrap underlying libraries, both the wrapper integration and the underlying library integration can instrument the same API calls, resulting in duplicate spans. This is particularly problematic for:

  • LangChain wrapping AI providers (OpenAI, Anthropic, Google GenAI)
  • Any future integrations that wrap other instrumented libraries

The disabled integrations mechanism can be used as follows:

// Any integration can disable others to prevent conflicts
import { disableIntegrations, isIntegrationDisabled } from '@sentry/node-core';

// In higher-level integration's setupOnce():
disableIntegrations('LowerLevelIntegration');

// In integration setupOnce() is not called for the disabled integrations 

and is used in LangChain to auto disable OpenAI, Anthropic AI, and Google GenAI integrations in setupOnce().

@github-actions
Copy link
Contributor

github-actions bot commented Oct 20, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.6 kB +0.01% +1 B 🔺
@sentry/browser - with treeshaking flags 23.09 kB +0.01% +2 B 🔺
@sentry/browser (incl. Tracing) 41.23 kB - -
@sentry/browser (incl. Tracing, Profiling) 45.51 kB - -
@sentry/browser (incl. Tracing, Replay) 79.7 kB +0.01% +1 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 69.38 kB +0.01% +1 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 84.39 kB +0.01% +1 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 96.56 kB -0.01% -5 B 🔽
@sentry/browser (incl. Feedback) 41.27 kB -0.01% -4 B 🔽
@sentry/browser (incl. sendFeedback) 29.27 kB +0.01% +1 B 🔺
@sentry/browser (incl. FeedbackAsync) 34.19 kB -0.01% -3 B 🔽
@sentry/react 26.28 kB -0.02% -3 B 🔽
@sentry/react (incl. Tracing) 43.2 kB +0.01% +2 B 🔺
@sentry/vue 29.08 kB +0.01% +1 B 🔺
@sentry/vue (incl. Tracing) 43.01 kB +0.01% +1 B 🔺
@sentry/svelte 24.61 kB +0.01% +1 B 🔺
CDN Bundle 26.9 kB +0.02% +3 B 🔺
CDN Bundle (incl. Tracing) 41.78 kB +0.01% +1 B 🔺
CDN Bundle (incl. Tracing, Replay) 78.31 kB +0.01% +2 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 83.78 kB +0.01% +3 B 🔺
CDN Bundle - uncompressed 78.86 kB -0.01% -4 B 🔽
CDN Bundle (incl. Tracing) - uncompressed 123.96 kB -0.01% -4 B 🔽
CDN Bundle (incl. Tracing, Replay) - uncompressed 239.99 kB -0.01% -4 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 252.75 kB -0.01% -4 B 🔽
@sentry/nextjs (client) 45.32 kB +0.01% +4 B 🔺
@sentry/sveltekit (client) 41.62 kB - -
@sentry/node-core 50.81 kB +0.1% +47 B 🔺
@sentry/node 157.99 kB +0.09% +141 B 🔺
@sentry/node - without tracing 92.69 kB +0.05% +46 B 🔺
@sentry/aws-serverless 106.45 kB +0.05% +46 B 🔺

View base workflow run

@github-actions
Copy link
Contributor

github-actions bot commented Oct 20, 2025

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 9,187 - 8,690 +6%
GET With Sentry 1,378 15% 1,397 -1%
GET With Sentry (error only) 6,143 67% 6,120 +0%
POST Baseline 1,206 - 1,213 -1%
POST With Sentry 553 46% 561 -1%
POST With Sentry (error only) 1,061 88% 1,072 -1%
MYSQL Baseline 3,342 - 3,363 -1%
MYSQL With Sentry 494 15% 482 +2%
MYSQL With Sentry (error only) 2,680 80% 2,713 -1%

View base workflow run

@RulaKhaled RulaKhaled force-pushed the disable-integrations branch 2 times, most recently from 470034b to 31cce57 Compare October 23, 2025 09:14
@RulaKhaled RulaKhaled marked this pull request as ready for review October 23, 2025 09:16
@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Race Condition in AI Provider Setup

A race condition exists where the LangChain integration's setupOnce() method disables other AI provider integrations to prevent duplicate spans. However, if an AI provider's setupOnce() runs before LangChain's due to unpredictable integration setup order, it will instrument itself, leading to duplicate spans that this disabling mechanism intends to prevent.

Fix in Cursor Fix in Web

@RulaKhaled RulaKhaled marked this pull request as draft October 23, 2025 12:44
@RulaKhaled RulaKhaled changed the title feat(node-core): Add integration disabling mechanism to prevent instrumentation conflicts wip feat(node-core): Add integration disabling mechanism to prevent instrumentation conflicts Oct 23, 2025
@RulaKhaled RulaKhaled changed the title wip feat(node-core): Add integration disabling mechanism to prevent instrumentation conflicts feat(node-core): Add integration disabling mechanism to prevent instrumentation conflicts Nov 4, 2025
@RulaKhaled RulaKhaled marked this pull request as ready for review November 4, 2025 15:52
Copy link
Member

@s1gr1d s1gr1d left a comment

Choose a reason for hiding this comment

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

Nice! I added some comments regarding the current naming of the functions as they kinda imply a different meaning to what they are actually doing and I think it would be good to give this another look when we expose those functions to our users.

And maybe it's also worth to add some tests

@RulaKhaled
Copy link
Member Author

@s1gr1d Aside from resolving the comments mentioned above, I made a quick refactor to the PR:

Previously, we unregistered all disabled integrations even if their modules weren’t required at runtime (i.e., when the patch wasn’t fired), which broke AI instrumentations. We also couldn’t have handled marking an integration as disabled in the patch while handling disabling in the setup logic, because that would’ve been too late, the integration would’ve already been registered during setup.

To fix this, I moved the registration of disabled integrations into the patch, ensuring it only happens when the module is actually used. Disabled integrations are now unregistered in _patch(), which serves as a good middle ground for now since we don’t want to require customers to disable integrations manually.

Ideally, we’ll support disabling integrations earlier (at setup time), possibly via lazy loading? but that’s TBD and out of scope for this PR.

Copy link
Member

@s1gr1d s1gr1d left a comment

Choose a reason for hiding this comment

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

I like the changes, thanks!

Copy link
Member

@andreiborza andreiborza left a comment

Choose a reason for hiding this comment

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

The approach we landed on seems okay to me, but I think we should be more specific with the naming of it.

Initially, we planned to disable integrations but after a few iterations we landed on skipping wrapping certain ai providers at runtime. I think we can reflect that change in the naming and really just scope this feature to ai providers.

I'd call the methods:

_skipAiProviderWrapping(providers: string[])
_shouldSkipAiProviderWrapping(provider: string)
_clearAiProviderSkips()

// (e.g., when LangChain skips OpenAI in one client, but a subsequent client uses OpenAI standalone)
_INTERNAL_clearAiProviderSkips();
super._setupIntegrations();
}
Copy link

Choose a reason for hiding this comment

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

Bug: Reinit Breaks Instrumentation Skip Logic

Calling _INTERNAL_clearAiProviderSkips() in _setupIntegrations() can cause incorrect instrumentation when Sentry.init() is called multiple times. If LangChain was imported during the first initialization and marked AI providers to skip, a second initialization clears those markers. Since LangChain's _patch won't run again (module already loaded), new AI provider client instances created after the second init will be incorrectly instrumented, even though LangChain is active. The skip markers should persist across client reinitializations or only be cleared when LangChain's patch logic runs.

Fix in Cursor Fix in Web

Copy link
Member

Choose a reason for hiding this comment

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

This is a limitation of the approach taken, should probably be fine in most cases.

@andreiborza andreiborza merged commit 2406e90 into develop Nov 12, 2025
195 checks passed
@andreiborza andreiborza deleted the disable-integrations branch November 12, 2025 13:06
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.

4 participants