From fe3a7f90933da2f343bdee26d07ada23753e544e Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 21 Aug 2026 11:23:46 +0200 Subject: [PATCH 01/18] feat(node): Always set up express, fastify, koa, hapi integrations --- .../node/src/integrations/tracing/index.ts | 12 +++----- packages/node/src/sdk/index.ts | 26 +++++++++------- packages/node/src/types.ts | 12 ++++++++ .../sdk/diagnosticsChannelInjection.test.ts | 30 +++++++++++++++---- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index e01d0d36bd38..925398d96a74 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -3,14 +3,11 @@ import { prismaIntegration, amqplibIntegration, anthropicAIIntegration, - expressIntegration, firebaseIntegration, genericPoolIntegration, googleGenAIIntegration, graphqlIntegration, - hapiIntegration, kafkaIntegration, - koaIntegration, langChainIntegration, langGraphIntegration, lruMemoizerIntegration, @@ -25,12 +22,13 @@ import { tediousIntegration, vercelAIIntegration, } from '@sentry/server-utils'; -import { fastifyIntegration } from './fastify'; export function getAutoPerformanceIntegrations(): Integration[] { + // The following integrations are not considered performance integrations because they are "framework"-level + // meaning they may also handle error capture and similar things. + // Thus, we add them by default: + // express, fastify, hapi, koa return [ - expressIntegration(), - fastifyIntegration(), graphqlIntegration(), mongoIntegration(), mongooseIntegration(), @@ -39,8 +37,6 @@ export function getAutoPerformanceIntegrations(): Integration[] { redisIntegration(), postgresIntegration(), prismaIntegration(), - hapiIntegration(), - koaIntegration(), tediousIntegration(), genericPoolIntegration(), kafkaIntegration(), diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index badfe207bc8c..7bc0231aed01 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -16,7 +16,7 @@ import { stackParserFromStackParserOptions, } from '@sentry/core'; import { isMainThread, parentPort } from 'node:worker_threads'; -import { detectOrchestrionSetup } from '@sentry/server-utils'; +import { detectOrchestrionSetup, expressIntegration, hapiIntegration, koaIntegration } from '@sentry/server-utils'; import { registerDiagnosticsChannelInjection } from '@sentry/server-utils/orchestrion/register'; import { DEBUG_BUILD } from '../debug-build'; import { childProcessIntegration } from '../integrations/childProcess'; @@ -41,6 +41,7 @@ import { getSpotlightConfig } from '../utils/spotlight'; import { defaultStackParser, getSentryRelease } from './api'; import { NodeClient } from './client'; import { initOpenTelemetry } from './initOtel'; +import { fastifyIntegration } from '../integrations/tracing/fastify'; /** * Get the base default integrations shared by all Node SDK default-integration sets. @@ -69,6 +70,11 @@ function getBaseDefaultIntegrations(): Integration[] { workerThreadsIntegration(), processSessionIntegration(), modulesIntegration(), + // Framework-level integrations + expressIntegration(), + fastifyIntegration(), + hapiIntegration(), + koaIntegration(), ]; } @@ -147,20 +153,20 @@ function _init( } } - // Resolve the tracing-affecting options (e.g. `SENTRY_TRACES_SAMPLE_RATE`) up front so that both - // the span-enablement gate below and default-integration selection see the final values. Without - // this, enabling tracing purely via env would leave `hasSpansEnabled` false at this point and skip - // the performance integrations. `getClientOptions` resolves the remaining options later. + // Resolve the tracing-affecting options (e.g. `SENTRY_TRACES_SAMPLE_RATE`) up front so that + // default-integration selection sees the final values. Without this, enabling tracing purely via + // env would leave `hasSpansEnabled` false at this point and skip the performance integrations. + // `getClientOptions` resolves the remaining options later. const optionsWithResolvedTracing = { ...options, tracesSampleRate: getTracesSampleRate(options.tracesSampleRate), }; - // Gate channel-based (orchestrion diagnostics-channel) instrumentation on span recording: the - // channel integrations only produce spans, so with tracing off there are no subscribers and - // injecting the module hooks would be pointless work. Install the hooks as early as possible, - // before the app imports its instrumented modules. - const useChannelInjection = hasSpansEnabled(optionsWithResolvedTracing); + // Install the channel-based (orchestrion diagnostics-channel) instrumentation hooks by default, + // independent of tracing — the channel integrations also capture errors, not just spans. Opt out + // with `enableRuntimeChannelInjection: false`. Install as early as possible, before the app imports + // its instrumented modules. + const useChannelInjection = options.enableRuntimeChannelInjection !== false; if (useChannelInjection) { registerDiagnosticsChannelInjection(); } diff --git a/packages/node/src/types.ts b/packages/node/src/types.ts index c15ba570b141..42c78ea5b556 100644 --- a/packages/node/src/types.ts +++ b/packages/node/src/types.ts @@ -22,6 +22,18 @@ export interface BaseNodeOptions extends ServerRuntimeOptions { */ enableOpenTelemetrySetup?: boolean; + /** + * Controls whether the SDK installs its runtime diagnostics-channel injection hooks. These hooks + * transform supported modules (e.g. Express) at load time so they emit the diagnostics channels + * that the channel-based integrations subscribe to. + * + * Set this to `false` to opt out — for example when the channels are injected at build + * time via the bundler plugin, or when the runtime module hooks are unavailable. + * + * @default true + */ + enableRuntimeChannelInjection?: boolean; + /** * Override the runtime name reported in events. * Defaults to 'node' with the current process version if not specified. diff --git a/packages/node/test/sdk/diagnosticsChannelInjection.test.ts b/packages/node/test/sdk/diagnosticsChannelInjection.test.ts index cbeee7171f7f..fbcfa292f2a9 100644 --- a/packages/node/test/sdk/diagnosticsChannelInjection.test.ts +++ b/packages/node/test/sdk/diagnosticsChannelInjection.test.ts @@ -22,10 +22,9 @@ declare var global: any; const PUBLIC_DSN = 'https://username@domain/123'; -// Channel-based (orchestrion diagnostics-channel) instrumentation is the default in v11: `init()` -// installs the injection hooks unconditionally when span recording is enabled, and skips them when -// tracing is off (there would be no channel subscribers to feed). -describe('diagnostics-channel injection default', () => { +// Runtime diagnostics-channel injection is installed by default, independent of tracing (the channel +// integrations capture errors as well as spans). It can be turned off via `enableRuntimeChannelInjection: false`. +describe('diagnostics-channel injection', () => { beforeEach(() => { global.__SENTRY__ = {}; vi.spyOn(debug, 'enable').mockImplementation(() => undefined); @@ -37,17 +36,36 @@ describe('diagnostics-channel injection default', () => { vi.clearAllMocks(); }); - it('registers the injection hooks and runs detection when span recording is enabled', () => { + it('registers the injection hooks and runs detection by default with tracing enabled', () => { init({ dsn: PUBLIC_DSN, tracesSampleRate: 1, enableOpenTelemetrySetup: false }); expect(registerDiagnosticsChannelInjection).toHaveBeenCalledTimes(1); expect(detectOrchestrionSetup).toHaveBeenCalledTimes(1); }); - it('does not register the injection hooks when tracing is disabled', () => { + it('registers the injection hooks by default even when tracing is disabled', () => { init({ dsn: PUBLIC_DSN, enableOpenTelemetrySetup: false }); + expect(registerDiagnosticsChannelInjection).toHaveBeenCalledTimes(1); + expect(detectOrchestrionSetup).toHaveBeenCalledTimes(1); + }); + + it('does not register the injection hooks when `enableRuntimeChannelInjection` is false', () => { + init({ + dsn: PUBLIC_DSN, + tracesSampleRate: 1, + enableRuntimeChannelInjection: false, + enableOpenTelemetrySetup: false, + }); + expect(registerDiagnosticsChannelInjection).not.toHaveBeenCalled(); expect(detectOrchestrionSetup).not.toHaveBeenCalled(); }); + + it('registers the injection hooks when `enableRuntimeChannelInjection` is true and tracing is disabled', () => { + init({ dsn: PUBLIC_DSN, enableRuntimeChannelInjection: true, enableOpenTelemetrySetup: false }); + + expect(registerDiagnosticsChannelInjection).toHaveBeenCalledTimes(1); + expect(detectOrchestrionSetup).toHaveBeenCalledTimes(1); + }); }); From 4c5fb709cb5d6b41a5fee3bf22851737e31d89c3 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 21 Aug 2026 12:02:58 +0200 Subject: [PATCH 02/18] feat(bun,deno): Add express, fastify, koa, hapi to default integrations Mirror the Node SDK change promoting the framework integrations (express, fastify, hapi, koa) to always-on defaults. Bun gains all four; Deno (which already listed express, hapi, koa) gains fastify, now also re-exported from `@sentry/server-utils/orchestrion`. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/bun/src/sdk.ts | 10 ++++++++++ packages/deno/src/sdk.ts | 2 ++ 2 files changed, 12 insertions(+) diff --git a/packages/bun/src/sdk.ts b/packages/bun/src/sdk.ts index ce5e08872542..2256969cc86f 100644 --- a/packages/bun/src/sdk.ts +++ b/packages/bun/src/sdk.ts @@ -12,9 +12,13 @@ import type { NodeClient } from '@sentry/node'; import { consoleIntegration, contextLinesIntegration, + expressIntegration, + fastifyIntegration, getAutoPerformanceIntegrations, + hapiIntegration, httpIntegration, init as initNode, + koaIntegration, modulesIntegration, nodeContextIntegration, onUncaughtExceptionIntegration, @@ -64,6 +68,12 @@ export function getDefaultIntegrationsWithoutPerformance(): Integration[] { nodeContextIntegration(), modulesIntegration(), processSessionIntegration(), + // Framework-level integrations. These are not performance-only: they also handle error capture, so + // they are added by default rather than gated behind tracing (matching the Node SDK). + expressIntegration(), + fastifyIntegration(), + hapiIntegration(), + koaIntegration(), // Bun Specific bunServerIntegration(), bunHttpServerIntegration(), diff --git a/packages/deno/src/sdk.ts b/packages/deno/src/sdk.ts index b4867e6f61b4..9266928ed917 100644 --- a/packages/deno/src/sdk.ts +++ b/packages/deno/src/sdk.ts @@ -16,6 +16,7 @@ import { anthropicAIIntegration, awsIntegration, expressIntegration, + fastifyIntegration, firebaseIntegration, genericPoolIntegration, googleGenAIIntegration, @@ -77,6 +78,7 @@ export function getDefaultIntegrations(_options: Options): Integration[] { anthropicAIIntegration(), awsIntegration(), expressIntegration(), + fastifyIntegration(), firebaseIntegration(), genericPoolIntegration(), googleGenAIIntegration(), From 9beccc2c1819681885bacbf1a1b5a758e9df700d Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 21 Aug 2026 12:49:14 +0200 Subject: [PATCH 03/18] bump size limits --- .size-limit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.size-limit.js b/.size-limit.js index cad73f5f5ceb..288258df7c06 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -430,7 +430,7 @@ module.exports = [ path: 'packages/node/build/esm/index.js', import: createImport('initWithoutDefaultIntegrations', 'getDefaultIntegrationsWithoutPerformance'), gzip: true, - limit: '87 KB', + limit: '92 KB', disablePlugins: ['@size-limit/esbuild'], ignore: [...builtinModules, ...nodePrefixedBuiltinModules], modifyWebpackConfig: function (config) { @@ -454,7 +454,7 @@ module.exports = [ import: createImport('init'), ignore: [...builtinModules, ...nodePrefixedBuiltinModules], gzip: true, - limit: '97 KB', + limit: '99 KB', disablePlugins: ['@size-limit/esbuild'], }, // Cloudflare SDK (ESM) - compressed, minified to match `wrangler deploy --dry-run --minify` output From 1a715f8c4afc825cc9102873049ce02afa6fe1c9 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 21 Aug 2026 12:56:47 +0200 Subject: [PATCH 04/18] fix test --- packages/deno/test/__snapshots__/mod.test.ts.snap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/deno/test/__snapshots__/mod.test.ts.snap b/packages/deno/test/__snapshots__/mod.test.ts.snap index 5e6a7f16eee3..78d37f153acb 100644 --- a/packages/deno/test/__snapshots__/mod.test.ts.snap +++ b/packages/deno/test/__snapshots__/mod.test.ts.snap @@ -63,6 +63,7 @@ snapshot[`captureMessage 1`] = ` "Anthropic_AI", "Aws", "Express", + "Fastify", "Firebase", "GenericPool", "Google_GenAI", @@ -168,6 +169,7 @@ snapshot[`captureMessage twice 1`] = ` "Anthropic_AI", "Aws", "Express", + "Fastify", "Firebase", "GenericPool", "Google_GenAI", @@ -280,6 +282,7 @@ snapshot[`captureMessage twice 2`] = ` "Anthropic_AI", "Aws", "Express", + "Fastify", "Firebase", "GenericPool", "Google_GenAI", From ce3a30156e045ed3c53334fedde2c36dcef90f01 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 21 Aug 2026 13:00:25 +0200 Subject: [PATCH 05/18] test(deno): Add orchestrion-fastify integration test Mirror the other orchestrion Deno suites: assert the Fastify integration is in the defaults and that the native `tracing:fastify.request.handler:error` channel captures the error (with mechanism `auto.function.fastify`). Adds a shared `errorSink` helper alongside `transactionSink`. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../deno-integration-tests/src/index.ts | 36 +++++++++++++- .../suites/orchestrion-fastify/test.ts | 47 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 dev-packages/deno-integration-tests/suites/orchestrion-fastify/test.ts diff --git a/dev-packages/deno-integration-tests/src/index.ts b/dev-packages/deno-integration-tests/src/index.ts index bc6b80087901..224204fb2af2 100644 --- a/dev-packages/deno-integration-tests/src/index.ts +++ b/dev-packages/deno-integration-tests/src/index.ts @@ -1,4 +1,4 @@ -import type { TransactionEvent } from '@sentry/core'; +import type { Event, TransactionEvent } from '@sentry/core'; import { getAsyncContextStrategy, getMainCarrier, setAsyncContextStrategy } from '@sentry/core'; /** @@ -51,6 +51,40 @@ export function transactionSink(): TransactionSink { }; } +export interface ErrorSink { + beforeSend: (event: Event) => null; + waitFor: (predicate: (event: Event) => boolean) => Promise; +} + +/** + * A `beforeSend` hook that records every error event and lets a test `await` the + * first one matching a predicate. Mirrors {@link transactionSink} for error events. + */ +export function errorSink(): ErrorSink { + const events: Event[] = []; + const waiters: { predicate: (e: Event) => boolean; resolve: (e: Event) => void }[] = []; + return { + beforeSend(event) { + events.push(event); + for (let i = waiters.length - 1; i >= 0; i--) { + const w = waiters[i]!; + if (w.predicate(event)) { + waiters.splice(i, 1); + w.resolve(event); + } + } + return null; + }, + waitFor(predicate) { + const already = events.find(predicate); + if (already) return Promise.resolve(already); + return new Promise(resolve => { + waiters.push({ predicate, resolve }); + }); + }, + }; +} + /** Reject with a descriptive message if `p` does not settle within `ms`. */ export function withTimeout(p: Promise, ms: number, what: string): Promise { let timer: ReturnType | undefined; diff --git a/dev-packages/deno-integration-tests/suites/orchestrion-fastify/test.ts b/dev-packages/deno-integration-tests/suites/orchestrion-fastify/test.ts new file mode 100644 index 000000000000..276a74eda91c --- /dev/null +++ b/dev-packages/deno-integration-tests/suites/orchestrion-fastify/test.ts @@ -0,0 +1,47 @@ +// + +import { channel } from 'node:diagnostics_channel'; +import type { DenoClient } from '@sentry/deno'; +import { init } from '@sentry/deno'; +import { assert } from 'https://deno.land/std@0.212.0/assert/assert.ts'; +import { assertEquals } from 'https://deno.land/std@0.212.0/assert/assert_equals.ts'; +import { assertExists } from 'https://deno.land/std@0.212.0/assert/assert_exists.ts'; +import { errorSink, resetGlobals, withTimeout } from '../../src/index.ts'; + +Deno.test('fastify instrumentation: included in default integrations (Deno 2.8.0+)', () => { + resetGlobals(); + const client = init({ traceLifecycle: 'static', dsn: 'https://username@domain/123' }) as DenoClient; + const names = client.getOptions().integrations.map(i => i.name); + assert(names.includes('Fastify'), `Fastify should be in defaults, got ${names.join(', ')}`); +}); + +Deno.test('fastify instrumentation: tracing:fastify.request.handler:error channel captures the error', async () => { + resetGlobals(); + const sink = errorSink(); + init({ + traceLifecycle: 'static', + dsn: 'https://username@domain/123', + beforeSend: sink.beforeSend, + }); + + const error = new Error('fastify boom'); + + // Fastify v5 publishes this native diagnostics channel when a request handler errors; the + // integration subscribes to it directly (no orchestrion injection needed). A 5xx reply passes the + // default `shouldHandleError`, so the error is captured. + channel('tracing:fastify.request.handler:error').publish({ + error, + request: { method: 'GET', routeOptions: { url: '/boom' } }, + reply: { statusCode: 500 }, + }); + + const event = await withTimeout( + sink.waitFor(e => e.exception?.values?.[0]?.value === 'fastify boom'), + 5000, + "the captured 'fastify boom' error", + ); + + assertExists(event.exception?.values?.[0]); + assertEquals(event.exception?.values?.[0]?.mechanism?.type, 'auto.function.fastify'); + assertEquals(event.exception?.values?.[0]?.mechanism?.handled, false); +}); From 5c6aafe4c54f9c72dddd7db7d7e6e02307e636bd Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 24 Aug 2026 10:31:46 +0200 Subject: [PATCH 06/18] fix flake --- .../node-integration-tests/suites/anr/stop-and-start.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dev-packages/node-integration-tests/suites/anr/stop-and-start.js b/dev-packages/node-integration-tests/suites/anr/stop-and-start.js index 6f1e4a7d6339..966f3b227e87 100644 --- a/dev-packages/node-integration-tests/suites/anr/stop-and-start.js +++ b/dev-packages/node-integration-tests/suites/anr/stop-and-start.js @@ -1,4 +1,5 @@ const Sentry = require('@sentry/node'); +const { waitForDebuggerReady } = require('@sentry-internal/test-utils'); setTimeout(() => { process.exit(); @@ -52,7 +53,9 @@ setTimeout(() => { setTimeout(() => { anr.startWorker(); - setTimeout(() => { + // Wait for the restarted worker's debugger session to reconnect before blocking the event + // loop, otherwise on slow CI the worker isn't ready to sample and the ANR is missed entirely. + waitForDebuggerReady(() => { longWork(); }); }, 2000); From fd550a4041a80e6556cc9485544b25928ff22219 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 24 Aug 2026 13:24:13 +0200 Subject: [PATCH 07/18] better comment --- packages/node/src/sdk/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index 7bc0231aed01..6346379f1f5f 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -90,9 +90,8 @@ export function getDefaultIntegrations(options: Options): Integration[] { return [ ...getDefaultIntegrationsWithoutPerformance(), // We only add performance integrations if tracing is enabled - // Note that this means that without tracing enabled, e.g. `expressIntegration()` will not be added - // This means that generally request isolation will work (because that is done by httpIntegration) - // But `transactionName` will not be set automatically + // Note that integrations like `httpIntegration` or `expressIntegration` are always added, + // because they also handle non-tracing related functionality. ...(hasSpansEnabled(options) ? getAutoPerformanceIntegrations() : []), ]; } From feb3dee256d08260ddb3a4e35703e398d89ecfb6 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 09:59:46 +0200 Subject: [PATCH 08/18] streamline deno integration test sink --- .../deno-integration-tests/src/index.ts | 80 +++++++------------ 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/dev-packages/deno-integration-tests/src/index.ts b/dev-packages/deno-integration-tests/src/index.ts index 224204fb2af2..377aaffccb21 100644 --- a/dev-packages/deno-integration-tests/src/index.ts +++ b/dev-packages/deno-integration-tests/src/index.ts @@ -16,75 +16,55 @@ export function resetGlobals(): void { setAsyncContextStrategy(acs); } -export interface TransactionSink { - beforeSendTransaction: (event: TransactionEvent) => null; - waitFor: (predicate: (event: TransactionEvent) => boolean) => Promise; +interface EventSink { + beforeSend: (event: T) => null; + waitFor: (predicate: (event: T) => boolean) => Promise; } -/** - * A `beforeSendTransaction` hook that records every transaction and lets a test - * `await` the first one matching a predicate. `waitFor` resolves immediately if - * a match already arrived, so there is no ordering race with the hook. - */ -export function transactionSink(): TransactionSink { - const transactions: TransactionEvent[] = []; - const waiters: { predicate: (e: TransactionEvent) => boolean; resolve: (e: TransactionEvent) => void }[] = []; +function eventSink(): EventSink { + const events: T[] = []; + const waiters: { predicate: (e: T) => boolean; resolve: (e: T) => void }[] = []; return { - beforeSendTransaction(event) { - transactions.push(event); - for (let i = waiters.length - 1; i >= 0; i--) { - const w = waiters[i]!; - if (w.predicate(event)) { - waiters.splice(i, 1); - w.resolve(event); - } - } + beforeSend(event) { + events.push(event); return null; }, waitFor(predicate) { - const already = transactions.find(predicate); + const already = events.find(predicate); if (already) return Promise.resolve(already); - return new Promise(resolve => { + return new Promise(resolve => { waiters.push({ predicate, resolve }); }); }, }; } -export interface ErrorSink { - beforeSend: (event: Event) => null; - waitFor: (predicate: (event: Event) => boolean) => Promise; -} - /** - * A `beforeSend` hook that records every error event and lets a test `await` the - * first one matching a predicate. Mirrors {@link transactionSink} for error events. + * A `beforeSend` hook that records every transaction event and lets a test + * `await` the first one matching a predicate. `waitFor` resolves immediately if + * a match already arrived, so there is no ordering race with the hook. */ -export function errorSink(): ErrorSink { - const events: Event[] = []; - const waiters: { predicate: (e: Event) => boolean; resolve: (e: Event) => void }[] = []; +export function transactionSink(): { + waitFor: (predicate: (event: TransactionEvent) => boolean) => Promise; + beforeSendTransaction: (event: TransactionEvent) => null; +} { + const sink = eventSink(); + return { - beforeSend(event) { - events.push(event); - for (let i = waiters.length - 1; i >= 0; i--) { - const w = waiters[i]!; - if (w.predicate(event)) { - waiters.splice(i, 1); - w.resolve(event); - } - } - return null; - }, - waitFor(predicate) { - const already = events.find(predicate); - if (already) return Promise.resolve(already); - return new Promise(resolve => { - waiters.push({ predicate, resolve }); - }); - }, + waitFor: sink.waitFor, + beforeSendTransaction: sink.beforeSend, }; } +/** + * A `beforeSend` hook that records every error and lets a test + * `await` the first one matching a predicate. `waitFor` resolves immediately if + * a match already arrived, so there is no ordering race with the hook. + */ +export function errorSink(): EventSink { + return eventSink(); +} + /** Reject with a descriptive message if `p` does not settle within `ms`. */ export function withTimeout(p: Promise, ms: number, what: string): Promise { let timer: ReturnType | undefined; From f99b760c683b35d7fcbceb2fd53b8f244517e2b4 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 09:59:56 +0200 Subject: [PATCH 09/18] remove comment --- packages/node/src/integrations/tracing/index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 925398d96a74..a7ec1988569a 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -24,10 +24,6 @@ import { } from '@sentry/server-utils'; export function getAutoPerformanceIntegrations(): Integration[] { - // The following integrations are not considered performance integrations because they are "framework"-level - // meaning they may also handle error capture and similar things. - // Thus, we add them by default: - // express, fastify, hapi, koa return [ graphqlIntegration(), mongoIntegration(), From 7741e30b965a470940ce1c4c175b8781dede4ce5 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 10:09:58 +0200 Subject: [PATCH 10/18] unify intergation getters into reusable functions --- packages/bun/src/sdk.ts | 15 ++--- packages/deno/src/sdk.ts | 62 ++----------------- .../node/src/integrations/tracing/index.ts | 53 ++-------------- packages/node/src/sdk/index.ts | 15 ++--- packages/server-utils/src/index.ts | 2 + .../server-utils/src/integrations/index.ts | 60 ++++++++++++++++++ 6 files changed, 79 insertions(+), 128 deletions(-) create mode 100644 packages/server-utils/src/integrations/index.ts diff --git a/packages/bun/src/sdk.ts b/packages/bun/src/sdk.ts index 2256969cc86f..ba77f87ef9a9 100644 --- a/packages/bun/src/sdk.ts +++ b/packages/bun/src/sdk.ts @@ -12,13 +12,8 @@ import type { NodeClient } from '@sentry/node'; import { consoleIntegration, contextLinesIntegration, - expressIntegration, - fastifyIntegration, - getAutoPerformanceIntegrations, - hapiIntegration, httpIntegration, init as initNode, - koaIntegration, modulesIntegration, nodeContextIntegration, onUncaughtExceptionIntegration, @@ -30,6 +25,7 @@ import { fetchIntegration } from './integrations/fetch'; import { makeFetchTransport } from './transports'; import type { BunOptions } from './types'; import { bunHttpServerIntegration } from './integrations/bunHttpServer'; +import { getErrorIntegrations, getTracingIntegrations } from '@sentry/server-utils'; /** * The performance integrations for bun: the OTel auto-performance set, but with @@ -44,7 +40,7 @@ function getPerformanceIntegrations(options: Options): Integration[] { return []; } - return getAutoPerformanceIntegrations(); + return getTracingIntegrations(); } /** Get the default integrations for the Bun SDK, excluding performance integrations. */ @@ -69,11 +65,8 @@ export function getDefaultIntegrationsWithoutPerformance(): Integration[] { modulesIntegration(), processSessionIntegration(), // Framework-level integrations. These are not performance-only: they also handle error capture, so - // they are added by default rather than gated behind tracing (matching the Node SDK). - expressIntegration(), - fastifyIntegration(), - hapiIntegration(), - koaIntegration(), + // they are added by default rather than gated behind tracing + ...getErrorIntegrations(), // Bun Specific bunServerIntegration(), bunHttpServerIntegration(), diff --git a/packages/deno/src/sdk.ts b/packages/deno/src/sdk.ts index 9266928ed917..0b33f933e337 100644 --- a/packages/deno/src/sdk.ts +++ b/packages/deno/src/sdk.ts @@ -11,33 +11,7 @@ import { requestDataIntegration, stackParserFromStackParserOptions, } from '@sentry/core'; -import { - amqplibIntegration, - anthropicAIIntegration, - awsIntegration, - expressIntegration, - fastifyIntegration, - firebaseIntegration, - genericPoolIntegration, - googleGenAIIntegration, - graphqlIntegration, - hapiIntegration, - kafkaIntegration, - koaIntegration, - langChainIntegration, - langGraphIntegration, - lruMemoizerIntegration, - mongoIntegration, - mongooseIntegration, - mysqlIntegration, - mysql2Integration, - openAIIntegration, - postgresIntegration, - postgresJsIntegration, - tediousIntegration, - vercelAIIntegration, - redisIntegration, -} from '@sentry/server-utils'; +import { getTracingIntegrations, getErrorIntegrations } from '@sentry/server-utils'; import { DenoClient } from './client'; import { breadcrumbsIntegration } from './integrations/breadcrumbs'; import { denoContextIntegration } from './integrations/context'; @@ -65,40 +39,12 @@ export function getDefaultIntegrations(_options: Options): Integration[] { denoContextIntegration(), denoServeIntegration(), denoHttpIntegration(), - redisIntegration(), - graphqlIntegration(), - vercelAIIntegration(), - // orchestrion-based instrumentations. We add a deliberate list here rather - // than every channel integration: each one needs a Deno test proving it - // records spans. - // - // The orchestrion channels may be injected after (or while) the SDK loads. - // If they never load, these are no-ops. - amqplibIntegration(), - anthropicAIIntegration(), - awsIntegration(), - expressIntegration(), - fastifyIntegration(), - firebaseIntegration(), - genericPoolIntegration(), - googleGenAIIntegration(), - hapiIntegration(), - kafkaIntegration(), - koaIntegration(), - langChainIntegration(), - langGraphIntegration(), - lruMemoizerIntegration(), - mongoIntegration(), - mongooseIntegration(), - mysqlIntegration(), - mysql2Integration(), - openAIIntegration(), - postgresIntegration(), - postgresJsIntegration(), - tediousIntegration(), contextLinesIntegration(), normalizePathsIntegration(), globalHandlersIntegration(), + // server-utils integrations + ...getErrorIntegrations(), + ...getTracingIntegrations(), ]; } diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index a7ec1988569a..1c866a438b02 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -1,52 +1,9 @@ import type { Integration } from '@sentry/core'; -import { - prismaIntegration, - amqplibIntegration, - anthropicAIIntegration, - firebaseIntegration, - genericPoolIntegration, - googleGenAIIntegration, - graphqlIntegration, - kafkaIntegration, - langChainIntegration, - langGraphIntegration, - lruMemoizerIntegration, - mongoIntegration, - mongooseIntegration, - mysqlIntegration, - mysql2Integration, - openAIIntegration, - postgresIntegration, - postgresJsIntegration, - redisIntegration, - tediousIntegration, - vercelAIIntegration, -} from '@sentry/server-utils'; +import { getTracingIntegrations } from '@sentry/server-utils'; +/** + * @deprecated Use getTracingIntegrations instead. + */ export function getAutoPerformanceIntegrations(): Integration[] { - return [ - graphqlIntegration(), - mongoIntegration(), - mongooseIntegration(), - mysqlIntegration(), - mysql2Integration(), - redisIntegration(), - postgresIntegration(), - prismaIntegration(), - tediousIntegration(), - genericPoolIntegration(), - kafkaIntegration(), - amqplibIntegration(), - lruMemoizerIntegration(), - // AI providers - // LangChain must come first to disable AI provider integrations before they instrument - langChainIntegration(), - langGraphIntegration(), - vercelAIIntegration(), - openAIIntegration(), - anthropicAIIntegration(), - googleGenAIIntegration(), - postgresJsIntegration(), - firebaseIntegration(), - ]; + return getTracingIntegrations(); } diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index 6346379f1f5f..5f4155c51b6b 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -16,7 +16,7 @@ import { stackParserFromStackParserOptions, } from '@sentry/core'; import { isMainThread, parentPort } from 'node:worker_threads'; -import { detectOrchestrionSetup, expressIntegration, hapiIntegration, koaIntegration } from '@sentry/server-utils'; +import { detectOrchestrionSetup, getErrorIntegrations, getTracingIntegrations } from '@sentry/server-utils'; import { registerDiagnosticsChannelInjection } from '@sentry/server-utils/orchestrion/register'; import { DEBUG_BUILD } from '../debug-build'; import { childProcessIntegration } from '../integrations/childProcess'; @@ -32,7 +32,6 @@ import { onUnhandledRejectionIntegration } from '../integrations/onunhandledreje import { processSessionIntegration } from '../integrations/processSession'; import { INTEGRATION_NAME as SPOTLIGHT_INTEGRATION_NAME, spotlightIntegration } from '../integrations/spotlight'; import { systemErrorIntegration } from '../integrations/systemError'; -import { getAutoPerformanceIntegrations } from '../integrations/tracing'; import { workerThreadsIntegration } from '../integrations/workerThreads'; import { makeNodeTransport } from '../transports'; import type { NodeClientOptions, NodeOptions } from '../types'; @@ -41,7 +40,6 @@ import { getSpotlightConfig } from '../utils/spotlight'; import { defaultStackParser, getSentryRelease } from './api'; import { NodeClient } from './client'; import { initOpenTelemetry } from './initOtel'; -import { fastifyIntegration } from '../integrations/tracing/fastify'; /** * Get the base default integrations shared by all Node SDK default-integration sets. @@ -71,10 +69,7 @@ function getBaseDefaultIntegrations(): Integration[] { processSessionIntegration(), modulesIntegration(), // Framework-level integrations - expressIntegration(), - fastifyIntegration(), - hapiIntegration(), - koaIntegration(), + ...getErrorIntegrations(), ]; } @@ -89,10 +84,8 @@ export function getDefaultIntegrationsWithoutPerformance(): Integration[] { export function getDefaultIntegrations(options: Options): Integration[] { return [ ...getDefaultIntegrationsWithoutPerformance(), - // We only add performance integrations if tracing is enabled - // Note that integrations like `httpIntegration` or `expressIntegration` are always added, - // because they also handle non-tracing related functionality. - ...(hasSpansEnabled(options) ? getAutoPerformanceIntegrations() : []), + // We only add tracing-only integrations if tracing is enabled + ...(hasSpansEnabled(options) ? getTracingIntegrations() : []), ]; } diff --git a/packages/server-utils/src/index.ts b/packages/server-utils/src/index.ts index 0ad0598dedfd..4309a6f1b859 100644 --- a/packages/server-utils/src/index.ts +++ b/packages/server-utils/src/index.ts @@ -46,3 +46,5 @@ export { tediousIntegration } from './integrations/tedious'; export { vercelAIIntegration } from './integrations/vercel-ai'; export { expressIntegration } from './integrations/express'; export { firebaseIntegration } from './integrations/firebase'; + +export { getTracingIntegrations, getErrorIntegrations } from './integrations'; diff --git a/packages/server-utils/src/integrations/index.ts b/packages/server-utils/src/integrations/index.ts new file mode 100644 index 000000000000..d2b8a628b2ef --- /dev/null +++ b/packages/server-utils/src/integrations/index.ts @@ -0,0 +1,60 @@ +import { amqplibIntegration } from './amqplib'; +import { mongoIntegration } from './mongodb'; +import { graphqlIntegration } from './graphql'; +import { redisIntegration } from './redis'; +import { mysqlIntegration } from './mysql'; +import { mysql2Integration } from './mysql2'; +import { postgresIntegration } from './postgres'; +import { prismaIntegration } from './prisma'; +import { tediousIntegration } from './tedious'; +import { genericPoolIntegration } from './generic-pool'; +import { kafkaIntegration } from './kafkajs'; +import { mongooseIntegration } from './mongoose'; +import { lruMemoizerIntegration } from './lru-memoizer'; +import { langChainIntegration } from './langchain'; +import { langGraphIntegration } from './langgraph'; +import { vercelAIIntegration } from './vercel-ai'; +import { openAIIntegration } from './openai'; +import { anthropicAIIntegration } from './anthropic'; +import { googleGenAIIntegration } from './google-genai'; +import { postgresJsIntegration } from './postgres-js'; +import { firebaseIntegration } from './firebase'; +import { expressIntegration } from './express'; +import { fastifyIntegration } from './fastify'; +import { hapiIntegration } from './hapi'; +import { koaIntegration } from './koa'; +import type { Integration } from '@sentry/core'; + +/** These are integrations that are tracing-only integrations. */ +export function getTracingIntegrations(): Integration[] { + return [ + graphqlIntegration(), + mongoIntegration(), + mongooseIntegration(), + mysqlIntegration(), + mysql2Integration(), + redisIntegration(), + postgresIntegration(), + prismaIntegration(), + tediousIntegration(), + genericPoolIntegration(), + kafkaIntegration(), + amqplibIntegration(), + lruMemoizerIntegration(), + // AI providers + // LangChain must come first to disable AI provider integrations before they instrument + langChainIntegration(), + langGraphIntegration(), + vercelAIIntegration(), + openAIIntegration(), + anthropicAIIntegration(), + googleGenAIIntegration(), + postgresJsIntegration(), + firebaseIntegration(), + ]; +} + +/** These are integrations that cover error capture, in addition to tracing. */ +export function getErrorIntegrations(): Integration[] { + return [expressIntegration(), fastifyIntegration(), hapiIntegration(), koaIntegration()]; +} From d8d0ab18f5bc0e3f04db2f090667201e4e6031c4 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 10:11:25 +0200 Subject: [PATCH 11/18] always detect orchestrion --- packages/node/src/sdk/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index 5f4155c51b6b..b4249a0ec89a 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -214,9 +214,7 @@ function _init( // Warn about missing or doubled channel injection. Runs after the client // is created so the debug logger is enabled and the warning is emitted. - if (useChannelInjection) { - detectOrchestrionSetup(); - } + detectOrchestrionSetup(); return client; } From 410aec1dd86104daab74712bd7759f4777e2ea9d Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 10:12:02 +0200 Subject: [PATCH 12/18] no deprecate --- packages/node/src/integrations/tracing/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 1c866a438b02..c22d22451271 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -1,9 +1,6 @@ import type { Integration } from '@sentry/core'; import { getTracingIntegrations } from '@sentry/server-utils'; -/** - * @deprecated Use getTracingIntegrations instead. - */ export function getAutoPerformanceIntegrations(): Integration[] { return getTracingIntegrations(); } From 5ec9fc28c4225fd640036b61904f2137caf9b8b6 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 10:18:51 +0200 Subject: [PATCH 13/18] fix deno integration test --- dev-packages/deno-integration-tests/src/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dev-packages/deno-integration-tests/src/index.ts b/dev-packages/deno-integration-tests/src/index.ts index 377aaffccb21..cef98cfc8ee5 100644 --- a/dev-packages/deno-integration-tests/src/index.ts +++ b/dev-packages/deno-integration-tests/src/index.ts @@ -27,6 +27,15 @@ function eventSink(): EventSink { return { beforeSend(event) { events.push(event); + + for (let i = waiters.length - 1; i >= 0; i--) { + const w = waiters[i]!; + if (w.predicate(event)) { + waiters.splice(i, 1); + w.resolve(event); + } + } + return null; }, waitFor(predicate) { From 6a8f86693594d246f179fb8f5ecfe0f6727f2211 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 10:18:58 +0200 Subject: [PATCH 14/18] add aws to tracing integrations --- packages/server-utils/src/integrations/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/server-utils/src/integrations/index.ts b/packages/server-utils/src/integrations/index.ts index d2b8a628b2ef..22bd0f0f1664 100644 --- a/packages/server-utils/src/integrations/index.ts +++ b/packages/server-utils/src/integrations/index.ts @@ -24,6 +24,7 @@ import { fastifyIntegration } from './fastify'; import { hapiIntegration } from './hapi'; import { koaIntegration } from './koa'; import type { Integration } from '@sentry/core'; +import { awsIntegration } from './aws-sdk'; /** These are integrations that are tracing-only integrations. */ export function getTracingIntegrations(): Integration[] { @@ -41,6 +42,7 @@ export function getTracingIntegrations(): Integration[] { kafkaIntegration(), amqplibIntegration(), lruMemoizerIntegration(), + awsIntegration(), // AI providers // LangChain must come first to disable AI provider integrations before they instrument langChainIntegration(), From 48af046eeacd91a8d8621567e8830f0cd368d90b Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 10:19:20 +0200 Subject: [PATCH 15/18] fix test --- packages/node/test/sdk/diagnosticsChannelInjection.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node/test/sdk/diagnosticsChannelInjection.test.ts b/packages/node/test/sdk/diagnosticsChannelInjection.test.ts index fbcfa292f2a9..5132f8cf6544 100644 --- a/packages/node/test/sdk/diagnosticsChannelInjection.test.ts +++ b/packages/node/test/sdk/diagnosticsChannelInjection.test.ts @@ -50,7 +50,7 @@ describe('diagnostics-channel injection', () => { expect(detectOrchestrionSetup).toHaveBeenCalledTimes(1); }); - it('does not register the injection hooks when `enableRuntimeChannelInjection` is false', () => { + it('does not register the injection hooks but still runs detection when `enableRuntimeChannelInjection` is false', () => { init({ dsn: PUBLIC_DSN, tracesSampleRate: 1, @@ -59,7 +59,7 @@ describe('diagnostics-channel injection', () => { }); expect(registerDiagnosticsChannelInjection).not.toHaveBeenCalled(); - expect(detectOrchestrionSetup).not.toHaveBeenCalled(); + expect(detectOrchestrionSetup).toHaveBeenCalledTimes(1); }); it('registers the injection hooks when `enableRuntimeChannelInjection` is true and tracing is disabled', () => { From 1e7e1fc1082a08ef817caacb0b825b47e50d0162 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 13:11:24 +0200 Subject: [PATCH 16/18] fix deno test --- .../deno/test/__snapshots__/mod.test.ts.snap | 111 +++++++++--------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/packages/deno/test/__snapshots__/mod.test.ts.snap b/packages/deno/test/__snapshots__/mod.test.ts.snap index 78d37f153acb..4ce1aea47cd0 100644 --- a/packages/deno/test/__snapshots__/mod.test.ts.snap +++ b/packages/deno/test/__snapshots__/mod.test.ts.snap @@ -56,34 +56,35 @@ snapshot[`captureMessage 1`] = ` "DenoContext", "DenoServe", "DenoHttp", - "Redis", - "Graphql", - "VercelAI", - "Amqplib", - "Anthropic_AI", - "Aws", + "ContextLines", + "NormalizePaths", + "GlobalHandlers", "Express", "Fastify", - "Firebase", - "GenericPool", - "Google_GenAI", "Hapi", - "Kafka", "Koa", - "LangChain", - "LangGraph", - "LruMemoizer", + "Graphql", "Mongo", "Mongoose", "Mysql", "Mysql2", - "OpenAI", + "Redis", "Postgres", - "PostgresJs", + "Prisma", "Tedious", - "ContextLines", - "NormalizePaths", - "GlobalHandlers", + "GenericPool", + "Kafka", + "Amqplib", + "LruMemoizer", + "Aws", + "LangChain", + "LangGraph", + "VercelAI", + "OpenAI", + "Anthropic_AI", + "Google_GenAI", + "PostgresJs", + "Firebase", ], name: "sentry.javascript.deno", packages: [ @@ -162,34 +163,35 @@ snapshot[`captureMessage twice 1`] = ` "DenoContext", "DenoServe", "DenoHttp", - "Redis", - "Graphql", - "VercelAI", - "Amqplib", - "Anthropic_AI", - "Aws", + "ContextLines", + "NormalizePaths", + "GlobalHandlers", "Express", "Fastify", - "Firebase", - "GenericPool", - "Google_GenAI", "Hapi", - "Kafka", "Koa", - "LangChain", - "LangGraph", - "LruMemoizer", + "Graphql", "Mongo", "Mongoose", "Mysql", "Mysql2", - "OpenAI", + "Redis", "Postgres", - "PostgresJs", + "Prisma", "Tedious", - "ContextLines", - "NormalizePaths", - "GlobalHandlers", + "GenericPool", + "Kafka", + "Amqplib", + "LruMemoizer", + "Aws", + "LangChain", + "LangGraph", + "VercelAI", + "OpenAI", + "Anthropic_AI", + "Google_GenAI", + "PostgresJs", + "Firebase", ], name: "sentry.javascript.deno", packages: [ @@ -275,34 +277,35 @@ snapshot[`captureMessage twice 2`] = ` "DenoContext", "DenoServe", "DenoHttp", - "Redis", - "Graphql", - "VercelAI", - "Amqplib", - "Anthropic_AI", - "Aws", + "ContextLines", + "NormalizePaths", + "GlobalHandlers", "Express", "Fastify", - "Firebase", - "GenericPool", - "Google_GenAI", "Hapi", - "Kafka", "Koa", - "LangChain", - "LangGraph", - "LruMemoizer", + "Graphql", "Mongo", "Mongoose", "Mysql", "Mysql2", - "OpenAI", + "Redis", "Postgres", - "PostgresJs", + "Prisma", "Tedious", - "ContextLines", - "NormalizePaths", - "GlobalHandlers", + "GenericPool", + "Kafka", + "Amqplib", + "LruMemoizer", + "Aws", + "LangChain", + "LangGraph", + "VercelAI", + "OpenAI", + "Anthropic_AI", + "Google_GenAI", + "PostgresJs", + "Firebase", ], name: "sentry.javascript.deno", packages: [ From c642d5a197ac0bf19df559596a4cfeb898607fe9 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 13:18:26 +0200 Subject: [PATCH 17/18] fix bin test --- packages/bun/test/init.test.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/bun/test/init.test.ts b/packages/bun/test/init.test.ts index 022d7a95043f..8338f61c6805 100644 --- a/packages/bun/test/init.test.ts +++ b/packages/bun/test/init.test.ts @@ -1,5 +1,6 @@ import { type Integration } from '@sentry/core'; import * as sentryNode from '@sentry/node'; +import * as sentryServerUtils from '@sentry/server-utils'; import type { Mock } from 'bun:test'; import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from 'bun:test'; import { @@ -22,15 +23,14 @@ class MockIntegration implements Integration { } describe('init()', () => { - let mockAutoPerformanceIntegrations: Mock<() => Integration[]>; + let mockGetTracingIntegrations: Mock<() => Integration[]>; beforeEach(() => { - // @ts-expect-error weird - mockAutoPerformanceIntegrations = spyOn(sentryNode, 'getAutoPerformanceIntegrations'); + mockGetTracingIntegrations = spyOn(sentryServerUtils, 'getTracingIntegrations'); }); afterEach(() => { - mockAutoPerformanceIntegrations.mockRestore(); + mockGetTracingIntegrations.mockRestore(); }); describe('integrations', () => { @@ -41,7 +41,7 @@ describe('init()', () => { expect(client?.getOptions().integrations).toEqual([]); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('enables spotlight with default URL from config `true`', () => { @@ -75,7 +75,7 @@ describe('init()', () => { expect(mockDefaultIntegrations[1]?.setupOnce).toHaveBeenCalledTimes(1); expect(mockIntegrations[0]?.setupOnce).toHaveBeenCalledTimes(1); expect(mockIntegrations[1]?.setupOnce).toHaveBeenCalledTimes(1); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('installs integrations returned from a callback function', () => { @@ -99,12 +99,12 @@ describe('init()', () => { expect(mockDefaultIntegrations[0]?.setupOnce).toHaveBeenCalledTimes(1); expect(mockDefaultIntegrations[1]?.setupOnce).toHaveBeenCalledTimes(0); expect(newIntegration.setupOnce).toHaveBeenCalledTimes(1); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('installs performance default instrumentations if tracing is enabled', () => { const autoPerformanceIntegrations = [new MockIntegration('Performance integration')]; - mockAutoPerformanceIntegrations.mockImplementation(() => autoPerformanceIntegrations); + mockGetTracingIntegrations.mockImplementation(() => autoPerformanceIntegrations); const mockIntegrations = [ new MockIntegration('Some mock integration 4.1'), @@ -120,7 +120,7 @@ describe('init()', () => { expect(mockIntegrations[0]?.setupOnce).toHaveBeenCalledTimes(1); expect(mockIntegrations[1]?.setupOnce).toHaveBeenCalledTimes(1); expect(autoPerformanceIntegrations[0]?.setupOnce).toHaveBeenCalledTimes(1); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(1); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(1); const integrations = getClient()?.getOptions().integrations; expect(integrations).toBeArray(); @@ -137,7 +137,7 @@ describe('init()', () => { const client = getClient(); expect(client?.getOptions().integrations).toEqual([]); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('still installs user-provided integrations', () => { @@ -162,12 +162,12 @@ describe('init()', () => { const full = getDefaultIntegrations({}).map(({ name }) => name); expect(withoutPerformance).toEqual(full); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('omits the performance integrations that the full set adds when tracing is enabled', () => { const performanceIntegration = new MockIntegration('Performance integration'); - mockAutoPerformanceIntegrations.mockImplementation(() => [performanceIntegration]); + mockGetTracingIntegrations.mockImplementation(() => [performanceIntegration]); const withoutPerformance = getDefaultIntegrationsWithoutPerformance().map(({ name }) => name); const full = getDefaultIntegrations({ tracesSampleRate: 1 }).map(({ name }) => name); From ee17f3db9bec8de74b925b9b82580fd4d9e372c3 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 25 Aug 2026 13:21:38 +0200 Subject: [PATCH 18/18] fix test --- packages/bun/test/init.test.ts | 1 - packages/node/test/sdk/init.test.ts | 19 +++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/bun/test/init.test.ts b/packages/bun/test/init.test.ts index 8338f61c6805..abf3aabf060e 100644 --- a/packages/bun/test/init.test.ts +++ b/packages/bun/test/init.test.ts @@ -1,5 +1,4 @@ import { type Integration } from '@sentry/core'; -import * as sentryNode from '@sentry/node'; import * as sentryServerUtils from '@sentry/server-utils'; import type { Mock } from 'bun:test'; import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from 'bun:test'; diff --git a/packages/node/test/sdk/init.test.ts b/packages/node/test/sdk/init.test.ts index b16ad41c41b4..3a9af657e3d9 100644 --- a/packages/node/test/sdk/init.test.ts +++ b/packages/node/test/sdk/init.test.ts @@ -4,7 +4,6 @@ import * as SentryOpentelemetry from '@sentry/opentelemetry'; import * as SentryServerUtils from '@sentry/server-utils'; import { afterEach, beforeEach, describe, expect, it, type Mock, type MockInstance, vi } from 'vitest'; import { getClient, NodeClient } from '../../src/'; -import * as auto from '../../src/integrations/tracing'; import { init } from '../../src/sdk'; import { cleanupOtel } from '../helpers/mockSdkInit'; @@ -24,7 +23,7 @@ class MockIntegration implements Integration { } describe('init()', () => { - let mockAutoPerformanceIntegrations: MockInstance = vi.fn(() => []); + let mockGetTracingIntegrations: MockInstance = vi.fn(() => []); beforeEach(() => { global.__SENTRY__ = {}; @@ -32,7 +31,7 @@ describe('init()', () => { // prevent the debug from being enabled, resulting in console.log calls vi.spyOn(debug, 'enable').mockImplementation(() => {}); - mockAutoPerformanceIntegrations = vi.spyOn(auto, 'getAutoPerformanceIntegrations').mockImplementation(() => []); + mockGetTracingIntegrations = vi.spyOn(SentryServerUtils, 'getTracingIntegrations').mockImplementation(() => []); }); afterEach(() => { @@ -67,7 +66,7 @@ describe('init()', () => { expect(client?.getOptions().integrations.map(integration => integration.name)).toEqual(['SpanStreaming']); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('installs merged default integrations, with overrides provided through options', () => { @@ -87,7 +86,7 @@ describe('init()', () => { expect(mockDefaultIntegrations[1]?.setupOnce as Mock).toHaveBeenCalledTimes(1); expect(mockIntegrations[0]?.setupOnce as Mock).toHaveBeenCalledTimes(1); expect(mockIntegrations[1]?.setupOnce as Mock).toHaveBeenCalledTimes(1); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('installs integrations returned from a callback function', () => { @@ -111,13 +110,13 @@ describe('init()', () => { expect(mockDefaultIntegrations[0]?.setupOnce as Mock).toHaveBeenCalledTimes(1); expect(mockDefaultIntegrations[1]?.setupOnce as Mock).toHaveBeenCalledTimes(0); expect(newIntegration.setupOnce).toHaveBeenCalledTimes(1); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(0); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(0); }); it('installs performance default instrumentations if tracing is enabled', () => { const autoPerformanceIntegration = new MockIntegration('Some mock integration 4.4'); - mockAutoPerformanceIntegrations.mockReset().mockImplementation(() => [autoPerformanceIntegration]); + mockGetTracingIntegrations.mockReset().mockImplementation(() => [autoPerformanceIntegration]); const mockIntegrations = [ new MockIntegration('Some mock integration 4.1'), @@ -133,7 +132,7 @@ describe('init()', () => { expect(mockIntegrations[0]?.setupOnce as Mock).toHaveBeenCalledTimes(1); expect(mockIntegrations[1]?.setupOnce as Mock).toHaveBeenCalledTimes(1); expect(autoPerformanceIntegration.setupOnce).toHaveBeenCalledTimes(1); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(1); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(1); const client = getClient(); expect(client?.getOptions()).toEqual( @@ -145,7 +144,7 @@ describe('init()', () => { it('installs performance default instrumentations if tracing is enabled via `SENTRY_TRACES_SAMPLE_RATE`', () => { const autoPerformanceIntegration = new MockIntegration('Some mock integration 4.5'); - mockAutoPerformanceIntegrations.mockReset().mockImplementation(() => [autoPerformanceIntegration]); + mockGetTracingIntegrations.mockReset().mockImplementation(() => [autoPerformanceIntegration]); process.env.SENTRY_TRACES_SAMPLE_RATE = '1'; @@ -156,7 +155,7 @@ describe('init()', () => { } expect(autoPerformanceIntegration.setupOnce).toHaveBeenCalledTimes(1); - expect(mockAutoPerformanceIntegrations).toHaveBeenCalledTimes(1); + expect(mockGetTracingIntegrations).toHaveBeenCalledTimes(1); const client = getClient(); expect(client?.getOptions()).toEqual(