diff --git a/dev-packages/e2e-tests/test-applications/astro-4/package.json b/dev-packages/e2e-tests/test-applications/astro-4/package.json index 0afd444f6d3d..e5a3b963dc10 100644 --- a/dev-packages/e2e-tests/test-applications/astro-4/package.json +++ b/dev-packages/e2e-tests/test-applications/astro-4/package.json @@ -26,5 +26,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "astro-4 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/astro-4/sentry.server.config.js b/dev-packages/e2e-tests/test-applications/astro-4/sentry.server.config.js index 0662d678dc7c..2599cb4541e0 100644 --- a/dev-packages/e2e-tests/test-applications/astro-4/sentry.server.config.js +++ b/dev-packages/e2e-tests/test-applications/astro-4/sentry.server.config.js @@ -4,6 +4,13 @@ Sentry.init({ dsn: import.meta.env.PUBLIC_E2E_TEST_DSN, environment: 'qa', tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), spotlight: true, tunnel: 'http://localhost:3031/', // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/astro-5/package.json b/dev-packages/e2e-tests/test-applications/astro-5/package.json index 268ce9ed82ca..718c0edf4882 100644 --- a/dev-packages/e2e-tests/test-applications/astro-5/package.json +++ b/dev-packages/e2e-tests/test-applications/astro-5/package.json @@ -26,5 +26,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "astro-5 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/astro-5/sentry.server.config.js b/dev-packages/e2e-tests/test-applications/astro-5/sentry.server.config.js index 2b79ec0ed337..e429642768ed 100644 --- a/dev-packages/e2e-tests/test-applications/astro-5/sentry.server.config.js +++ b/dev-packages/e2e-tests/test-applications/astro-5/sentry.server.config.js @@ -4,5 +4,12 @@ Sentry.init({ dsn: import.meta.env.PUBLIC_E2E_TEST_DSN, environment: 'qa', tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/astro-6/package.json b/dev-packages/e2e-tests/test-applications/astro-6/package.json index 9ba8edb97274..c04b24c0f04b 100644 --- a/dev-packages/e2e-tests/test-applications/astro-6/package.json +++ b/dev-packages/e2e-tests/test-applications/astro-6/package.json @@ -9,7 +9,9 @@ "astro": "astro", "start": "node ./dist/server/entry.mjs", "test:build": "pnpm install && pnpm build", - "test:assert": "TEST_ENV=production playwright test" + "test:build:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "test:assert": "TEST_ENV=production playwright test", + "test:assert:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert" }, "dependencies": { "@astrojs/node": "^10.0.0", @@ -21,5 +23,14 @@ "volta": { "node": "22.22.0", "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "pnpm test:build:sentry-trace-provider", + "assert-command": "pnpm test:assert:sentry-trace-provider", + "label": "astro-6 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/astro-6/sentry.server.config.js b/dev-packages/e2e-tests/test-applications/astro-6/sentry.server.config.js index bc90470cef38..91af273dc4b7 100644 --- a/dev-packages/e2e-tests/test-applications/astro-6/sentry.server.config.js +++ b/dev-packages/e2e-tests/test-applications/astro-6/sentry.server.config.js @@ -4,6 +4,13 @@ Sentry.init({ dsn: import.meta.env.PUBLIC_E2E_TEST_DSN, environment: 'qa', tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server debug: true, }); diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/package.json b/dev-packages/e2e-tests/test-applications/aws-serverless/package.json index f74e7a670c50..1f214e20f4f9 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/package.json +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/package.json @@ -21,5 +21,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "aws-serverless (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-npm/TracingCjs/sentry-trace-provider-auto.mjs b/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-npm/TracingCjs/sentry-trace-provider-auto.mjs new file mode 100644 index 000000000000..7aa885da2405 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-npm/TracingCjs/sentry-trace-provider-auto.mjs @@ -0,0 +1,14 @@ +import * as Sentry from '@sentry/aws-serverless'; + +const optionsWithTracingEnabled = process.env.SENTRY_TRACES_SAMPLE_RATE + ? { + tracesSampleRate: parseFloat(process.env.SENTRY_TRACES_SAMPLE_RATE), + } + : {}; + +Sentry.init({ + integrations: Sentry.getDefaultIntegrations(optionsWithTracingEnabled), + _experiments: { + useSentryTraceProvider: true, + }, +}); diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-npm/TracingEsm/sentry-trace-provider-auto.mjs b/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-npm/TracingEsm/sentry-trace-provider-auto.mjs new file mode 100644 index 000000000000..7aa885da2405 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-npm/TracingEsm/sentry-trace-provider-auto.mjs @@ -0,0 +1,14 @@ +import * as Sentry from '@sentry/aws-serverless'; + +const optionsWithTracingEnabled = process.env.SENTRY_TRACES_SAMPLE_RATE + ? { + tracesSampleRate: parseFloat(process.env.SENTRY_TRACES_SAMPLE_RATE), + } + : {}; + +Sentry.init({ + integrations: Sentry.getDefaultIntegrations(optionsWithTracingEnabled), + _experiments: { + useSentryTraceProvider: true, + }, +}); diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts index 26db26e21659..6eeabe1d6239 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts @@ -9,6 +9,10 @@ import { execFileSync } from 'node:child_process'; const LAMBDA_FUNCTIONS_DIR = './src/lambda-functions-npm'; const LAMBDA_FUNCTION_TIMEOUT = 10; +const LAMBDA_AUTO_INIT_IMPORT = + process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? './sentry-trace-provider-auto.mjs' + : '@sentry/aws-serverless/awslambda-auto'; export const SAM_PORT = 3001; /** Match SAM / Docker to this machine so Apple Silicon does not mix arm64 images with an x86_64 template default. */ @@ -113,7 +117,7 @@ export class LocalLambdaStack extends Stack { SENTRY_DSN: dsn, SENTRY_TRACES_SAMPLE_RATE: 1.0, SENTRY_DEBUG: true, - NODE_OPTIONS: `--import=@sentry/aws-serverless/awslambda-auto`, + NODE_OPTIONS: `--import=${LAMBDA_AUTO_INIT_IMPORT}`, }, }, }, diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs b/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs index b52053445456..290544241a70 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/instrument.mjs @@ -3,6 +3,13 @@ import * as process from 'process'; Sentry.init({ tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/package.json b/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/package.json index 01c5fc44e5ed..cb85cdc9d1f1 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/package.json +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-express-vite-dev/package.json @@ -48,5 +48,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "create-remix-app-express-vite-dev (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs b/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs index a23e60d854bd..9f025a174241 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-express/instrument.mjs @@ -3,6 +3,13 @@ import process from 'process'; Sentry.init({ tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-express/package.json b/dev-packages/e2e-tests/test-applications/create-remix-app-express/package.json index 2dc4f42dd34d..584521625cbe 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-express/package.json +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-express/package.json @@ -52,5 +52,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "create-remix-app-express (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/app/entry.server.tsx b/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/app/entry.server.tsx index 41974897eeae..d3ec2c5e489d 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/app/entry.server.tsx +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/app/entry.server.tsx @@ -23,6 +23,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); const handleErrorImpl = () => { diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/instrument.server.cjs b/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/instrument.server.cjs index 557ab8d18f17..7efece8057fb 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/instrument.server.cjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/instrument.server.cjs @@ -2,6 +2,13 @@ const Sentry = require('@sentry/remix'); Sentry.init({ tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3032/', // proxy server diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/package.json b/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/package.json index 38a7e231ddf1..d2ad0a78b1ff 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/package.json +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2-non-vite/package.json @@ -35,5 +35,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "create-remix-app-v2-non-vite (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs index 6d211cac4592..023cd91bd8cd 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs @@ -2,6 +2,13 @@ const Sentry = require('@sentry/remix'); Sentry.init({ tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server diff --git a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/package.json b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/package.json index fd57d2920d5a..8d5734eac613 100644 --- a/dev-packages/e2e-tests/test-applications/create-remix-app-v2/package.json +++ b/dev-packages/e2e-tests/test-applications/create-remix-app-v2/package.json @@ -38,5 +38,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "create-remix-app-v2 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/elysia-node/package.json b/dev-packages/e2e-tests/test-applications/elysia-node/package.json index fcd2a4e8f71b..84e363973b3a 100644 --- a/dev-packages/e2e-tests/test-applications/elysia-node/package.json +++ b/dev-packages/e2e-tests/test-applications/elysia-node/package.json @@ -8,7 +8,9 @@ "test": "playwright test", "clean": "npx rimraf node_modules pnpm-lock.yaml", "test:build": "pnpm install", - "test:assert": "pnpm test" + "test:build:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "test:assert": "pnpm test", + "test:assert:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert" }, "dependencies": { "@sentry/elysia": "file:../../packed/sentry-elysia-packed.tgz", @@ -22,5 +24,14 @@ "volta": { "extends": "../../package.json", "node": "24.11.0" + }, + "sentryTest": { + "variants": [ + { + "build-command": "pnpm test:build:sentry-trace-provider", + "assert-command": "pnpm test:assert:sentry-trace-provider", + "label": "elysia-node (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/elysia-node/src/app.ts b/dev-packages/e2e-tests/test-applications/elysia-node/src/app.ts index 375ca9a29c6d..365ced0c99ac 100644 --- a/dev-packages/e2e-tests/test-applications/elysia-node/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/elysia-node/src/app.ts @@ -8,6 +8,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); const app = Sentry.withElysia(new Elysia({ adapter: node() })); diff --git a/dev-packages/e2e-tests/test-applications/hono-4/package.json b/dev-packages/e2e-tests/test-applications/hono-4/package.json index df2031e0f52b..6cca4cc497b0 100644 --- a/dev-packages/e2e-tests/test-applications/hono-4/package.json +++ b/dev-packages/e2e-tests/test-applications/hono-4/package.json @@ -10,7 +10,11 @@ "dev:deno": "deno run --allow-net --allow-env --allow-read src/entry.deno.ts", "build": "wrangler deploy --dry-run", "test:build": "pnpm install && pnpm build", - "test:assert": "TEST_ENV=production playwright test" + "test:build:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "test:assert": "TEST_ENV=production playwright test", + "test:assert:node": "RUNTIME=node pnpm test:assert", + "test:assert:bun": "RUNTIME=bun pnpm test:assert", + "test:assert:sentry-trace-provider": "RUNTIME=node E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert" }, "dependencies": { "@sentry/bun": "latest || *", @@ -36,16 +40,21 @@ "sentryTest": { "variants": [ { - "assert-command": "RUNTIME=node pnpm test:assert", + "assert-command": "pnpm test:assert:node", "label": "hono-4 (node)" }, { - "assert-command": "RUNTIME=bun pnpm test:assert", + "assert-command": "pnpm test:assert:bun", "label": "hono-4 (bun)" }, { "assert-command": "RUNTIME=deno pnpm test:assert", "label": "hono-4 (deno)" + }, + { + "build-command": "pnpm test:build:sentry-trace-provider", + "assert-command": "pnpm test:assert:sentry-trace-provider", + "label": "hono-4 (node, sentry-trace-provider)" } ] } diff --git a/dev-packages/e2e-tests/test-applications/hono-4/src/instrument.node.ts b/dev-packages/e2e-tests/test-applications/hono-4/src/instrument.node.ts index 2e33e6493361..5e35c58cddfd 100644 --- a/dev-packages/e2e-tests/test-applications/hono-4/src/instrument.node.ts +++ b/dev-packages/e2e-tests/test-applications/hono-4/src/instrument.node.ts @@ -5,5 +5,12 @@ Sentry.init({ environment: 'qa', tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', }); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-11/package.json b/dev-packages/e2e-tests/test-applications/nestjs-11/package.json index 2a230d9d5a68..3562a5beca55 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-11/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-11/package.json @@ -49,5 +49,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-11 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-11/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-11/src/instrument.ts index 4f16ebb36d11..439b222f1229 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-11/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-11/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-8/package.json b/dev-packages/e2e-tests/test-applications/nestjs-8/package.json index 3bd765774d2e..c38e541d37e5 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-8/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-8/package.json @@ -43,5 +43,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-8 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-8/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-8/src/instrument.ts index 4f16ebb36d11..439b222f1229 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-8/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-8/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json b/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json index e429f8cbb328..263ac0775513 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json @@ -45,5 +45,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-basic-with-graphql (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/src/instrument.ts index f1f4de865435..b7ca310219a8 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/src/instrument.ts @@ -5,4 +5,11 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json b/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json index 0640e39f77a1..76275f603133 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json @@ -44,5 +44,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-basic (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/instrument.ts index 4f16ebb36d11..439b222f1229 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-bullmq/package.json b/dev-packages/e2e-tests/test-applications/nestjs-bullmq/package.json index c4cfcd118f53..7a5351a1e945 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-bullmq/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-bullmq/package.json @@ -32,5 +32,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-bullmq (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/instrument.ts index 4f16ebb36d11..439b222f1229 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json index c8fe82cff563..acb9281e1123 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json @@ -42,5 +42,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-distributed-tracing (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/src/instrument.ts index 1cf7b8ee1f76..34864c22d67f 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], transportOptions: { // We expect the app to send a lot of events in a short time diff --git a/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json b/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json index 720cfe158eae..e644c81d64a9 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json @@ -43,5 +43,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-fastify (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-fastify/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-fastify/src/instrument.ts index 4f16ebb36d11..439b222f1229 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-fastify/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-fastify/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json b/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json index 05a38d691807..130d18ba33ce 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json @@ -45,5 +45,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-graphql (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-graphql/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-graphql/src/instrument.ts index f1f4de865435..b7ca310219a8 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-graphql/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-graphql/src/instrument.ts @@ -5,4 +5,11 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-microservices/package.json b/dev-packages/e2e-tests/test-applications/nestjs-microservices/package.json index 4bfc4eee7710..3f0d8619ec21 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-microservices/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-microservices/package.json @@ -35,5 +35,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-microservices (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-microservices/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-microservices/src/instrument.ts index e0a1cead1153..42a1c592640e 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-microservices/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-microservices/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { bufferSize: 1000, }, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-websockets/package.json b/dev-packages/e2e-tests/test-applications/nestjs-websockets/package.json index c859d4e49791..2860e378eacf 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-websockets/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-websockets/package.json @@ -30,5 +30,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-websockets (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-websockets/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-websockets/src/instrument.ts index e0a1cead1153..42a1c592640e 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-websockets/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-websockets/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { bufferSize: 1000, }, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json index 35ce0bc009e1..9b6a84f72ce3 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json @@ -41,5 +41,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-with-submodules-decorator (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts index 4f16ebb36d11..439b222f1229 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json index e9da4c97ae26..9351fffd671a 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json @@ -41,5 +41,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nestjs-with-submodules (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/instrument.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/instrument.ts index 4f16ebb36d11..439b222f1229 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/instrument.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/instrument.ts @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/instrumentation.ts b/dev-packages/e2e-tests/test-applications/nextjs-13/instrumentation.ts index 979e0f0abedb..b70657c5724e 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/instrumentation.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/instrumentation.ts @@ -7,6 +7,13 @@ export function register() { dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.NEXT_RUNTIME === 'nodejs' && process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), dataCollection: { userInfo: true }, transportOptions: { // We are doing a lot of events at once in this test app diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/package.json b/dev-packages/e2e-tests/test-applications/nextjs-13/package.json index f6137db6843c..82c9562d515c 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/package.json @@ -34,6 +34,13 @@ "build-command": "pnpm test:build-latest", "label": "nextjs-13 (latest)" } + ], + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-13 (sentry-trace-provider)" + } ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/instrumentation.ts b/dev-packages/e2e-tests/test-applications/nextjs-14/instrumentation.ts index 05811c256c2d..bfbe839e6883 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/instrumentation.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/instrumentation.ts @@ -7,6 +7,13 @@ export function register() { dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.NEXT_RUNTIME === 'nodejs' && process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), dataCollection: { userInfo: true }, transportOptions: { // We are doing a lot of events at once in this test diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/package.json b/dev-packages/e2e-tests/test-applications/nextjs-14/package.json index 09a928eddfa0..bf64ca2ce398 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/package.json @@ -40,6 +40,13 @@ "build-command": "pnpm test:build-latest", "label": "nextjs-14 (latest)" } + ], + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-14 (sentry-trace-provider)" + } ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/package.json b/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/package.json index ce63c62aeefa..2c42348c803b 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/package.json @@ -26,5 +26,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-15-basepath (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/sentry.server.config.ts index 6966e28cacb0..6dcc10359469 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-15-basepath/sentry.server.config.ts @@ -6,6 +6,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We are doing a lot of events at once in this test bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15-intl/package.json b/dev-packages/e2e-tests/test-applications/nextjs-15-intl/package.json index d935f67fa39e..6bbf0dd6c927 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15-intl/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-15-intl/package.json @@ -27,5 +27,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-15-intl (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15-intl/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-15-intl/sentry.server.config.ts index e0bc14d47ffd..33c091a5576d 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15-intl/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-15-intl/sentry.server.config.ts @@ -6,6 +6,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { bufferSize: 1000, }, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15-t3/package.json b/dev-packages/e2e-tests/test-applications/nextjs-15-t3/package.json index 24fde175baea..2cfd893adcae 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15-t3/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-15-t3/package.json @@ -46,5 +46,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-15-t3 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15-t3/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-15-t3/sentry.server.config.ts index ad780407a5b7..5d5953afc52c 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15-t3/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-15-t3/sentry.server.config.ts @@ -5,4 +5,11 @@ Sentry.init({ dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/package.json b/dev-packages/e2e-tests/test-applications/nextjs-15/package.json index 25fc16f8702e..2cca87cd3542 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/package.json @@ -44,6 +44,13 @@ "assert-command": "pnpm test:prod-turbo && pnpm test:dev-turbo", "label": "nextjs-15 (turbo)" } + ], + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-15 (sentry-trace-provider)" + } ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-15/sentry.server.config.ts index a5e60d7787c6..909898ca251a 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/sentry.server.config.ts @@ -6,6 +6,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We are doing a lot of events at once in this test bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/package.json b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/package.json index 22beb292ca79..2035cfc1f4e6 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/package.json @@ -46,6 +46,13 @@ "extends": "../../package.json" }, "sentryTest": { - "//": "TODO: Add variants for webpack once supported" + "//": "TODO: Add variants for webpack once supported", + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-16-cacheComponents (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/sentry.server.config.ts index 737bfa3e9ec7..7edcadf0f035 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/sentry.server.config.ts @@ -6,6 +6,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), // debug: true, integrations: [Sentry.vercelAIIntegration()], }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/package.json b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/package.json index 4fbc3bf64c27..79fd792e7a2b 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/package.json @@ -37,5 +37,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-16-streaming (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/sentry.server.config.ts index 924844386908..9528ab9adabb 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/sentry.server.config.ts @@ -7,6 +7,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), traceLifecycle: 'stream', integrations: [ Sentry.vercelAIIntegration(), diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/package.json b/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/package.json index 98896eae5d1b..8d6e6c885928 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/package.json @@ -37,6 +37,11 @@ { "build-command": "pnpm test:build-latest", "label": "nextjs-16-trailing-slash (latest, turbopack)" + }, + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-16-trailing-slash (sentry-trace-provider)" } ] } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/sentry.server.config.ts index 11e0e9e3c30f..8a7cb4dbe34b 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-trailing-slash/sentry.server.config.ts @@ -6,4 +6,11 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/package.json b/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/package.json index 7dfa8f923f6e..ca21224df739 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/package.json @@ -57,6 +57,11 @@ "build-command": "pnpm test:build", "label": "nextjs-16-tunnel (turbopack)", "assert-command": "pnpm test:assert" + }, + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-16-tunnel (sentry-trace-provider)" } ] } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/sentry.server.config.ts index 98d677005900..4daf5b6842db 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-tunnel/sentry.server.config.ts @@ -7,5 +7,12 @@ Sentry.init({ // No tunnel option - using tunnelRoute from withSentryConfig tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), // debug: true, }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/package.json b/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/package.json index b30636cd3576..e58498572ded 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/package.json @@ -28,5 +28,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-16-userfeedback (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/sentry.server.config.ts index c6de72d3a791..03f4e458589e 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-userfeedback/sentry.server.config.ts @@ -6,6 +6,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { bufferSize: 1000, }, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/package.json b/dev-packages/e2e-tests/test-applications/nextjs-16/package.json index beda2252d915..b99f9e7a8d02 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/package.json @@ -62,6 +62,11 @@ { "build-command": "pnpm test:build-latest", "label": "nextjs-16 (latest, turbopack)" + }, + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-16 (sentry-trace-provider)" } ], "optionalVariants": [ diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/sentry.server.config.ts index 8b9eaa651f6d..6dd064f20bb1 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/sentry.server.config.ts @@ -7,6 +7,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), // debug: true, integrations: [Sentry.vercelAIIntegration(), Sentry.nodeRuntimeMetricsIntegration({ collectionIntervalMs: 1_000 })], streamGenAiSpans: true, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/instrumentation.ts b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/instrumentation.ts index 2f72cbf2ad75..b3de0ecd3786 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/instrumentation.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/instrumentation.ts @@ -7,6 +7,13 @@ export function register() { dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.NEXT_RUNTIME === 'nodejs' && process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), dataCollection: { userInfo: true }, transportOptions: { // We are doing a lot of events at once in this test diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json index cb7927e9b0d8..7f1be88ebe99 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json @@ -41,6 +41,11 @@ { "build-command": "pnpm test:build-15", "label": "nextjs-app-dir (next@15)" + }, + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-app-dir (sentry-trace-provider)" } ] } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json b/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json index 21f835e2ecd4..de89d8aa8c42 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-orpc/package.json @@ -43,6 +43,13 @@ "extends": "../../package.json" }, "sentryTest": { - "optional": true + "optional": true, + "optionalVariants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-orpc (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-orpc/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-orpc/sentry.server.config.ts index ad780407a5b7..5d5953afc52c 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-orpc/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-orpc/sentry.server.config.ts @@ -5,4 +5,11 @@ Sentry.init({ dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/instrumentation.ts b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/instrumentation.ts index 2f72cbf2ad75..b3de0ecd3786 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/instrumentation.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/instrumentation.ts @@ -7,6 +7,13 @@ export function register() { dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.NEXT_RUNTIME === 'nodejs' && process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), dataCollection: { userInfo: true }, transportOptions: { // We are doing a lot of events at once in this test diff --git a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json index f677e02dd954..d8cfe9d59e16 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/package.json @@ -42,6 +42,11 @@ { "build-command": "pnpm test:build-15", "label": "nextjs-pages-dir (next@15)" + }, + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nextjs-pages-dir (sentry-trace-provider)" } ], "optionalVariants": [] diff --git a/dev-packages/e2e-tests/test-applications/nitro-3/instrument.mjs b/dev-packages/e2e-tests/test-applications/nitro-3/instrument.mjs index 53b80d309a5b..cc5fa7028c51 100644 --- a/dev-packages/e2e-tests/test-applications/nitro-3/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/nitro-3/instrument.mjs @@ -5,4 +5,11 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/nitro-3/package.json b/dev-packages/e2e-tests/test-applications/nitro-3/package.json index 85713dccc138..58c8b9f5b14e 100644 --- a/dev-packages/e2e-tests/test-applications/nitro-3/package.json +++ b/dev-packages/e2e-tests/test-applications/nitro-3/package.json @@ -25,5 +25,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nitro-3 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-connect/package.json b/dev-packages/e2e-tests/test-applications/node-connect/package.json index 729cfbe6c095..8e4d515b6765 100644 --- a/dev-packages/e2e-tests/test-applications/node-connect/package.json +++ b/dev-packages/e2e-tests/test-applications/node-connect/package.json @@ -24,5 +24,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-connect (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-connect/src/app.ts b/dev-packages/e2e-tests/test-applications/node-connect/src/app.ts index 375554845d6f..a3026c71a244 100644 --- a/dev-packages/e2e-tests/test-applications/node-connect/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-connect/src/app.ts @@ -6,6 +6,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, integrations: [], tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-connect/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-connect/tests/transactions.test.ts index 9b06ad052f58..9dca6119b360 100644 --- a/dev-packages/e2e-tests/test-applications/node-connect/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-connect/tests/transactions.test.ts @@ -1,6 +1,8 @@ import { expect, test } from '@playwright/test'; import { waitForTransaction } from '@sentry-internal/test-utils'; +const useSentryTraceProvider = process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1'; + test('Sends an API route transaction', async ({ baseURL }) => { const pageloadTransactionEventPromise = waitForTransaction('node-connect', transactionEvent => { return ( @@ -54,41 +56,51 @@ test('Sends an API route transaction', async ({ baseURL }) => { origin: 'auto.http.otel.http', }); + const manualSpanExpectation = { + data: { + 'sentry.origin': 'manual', + }, + description: 'test-span', + parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + status: 'ok', + timestamp: expect.any(Number), + trace_id: expect.stringMatching(/[a-f0-9]{32}/), + origin: 'manual', + }; + + const connectSpanExpectation = { + data: { + 'sentry.origin': 'auto.http.otel.connect', + 'sentry.op': 'request_handler.connect', + 'http.route': '/test-transaction', + 'connect.type': 'request_handler', + 'connect.name': '/test-transaction', + }, + op: 'request_handler.connect', + description: '/test-transaction', + parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + status: 'ok', + timestamp: expect.any(Number), + trace_id: expect.stringMatching(/[a-f0-9]{32}/), + origin: 'auto.http.otel.connect', + }; + expect(transactionEvent).toEqual( expect.objectContaining({ - spans: [ - { - data: { - 'sentry.origin': 'manual', - }, - description: 'test-span', - parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), - span_id: expect.stringMatching(/[a-f0-9]{16}/), - start_timestamp: expect.any(Number), - status: 'ok', - timestamp: expect.any(Number), - trace_id: expect.stringMatching(/[a-f0-9]{32}/), - origin: 'manual', - }, - { - data: { - 'sentry.origin': 'auto.http.otel.connect', - 'sentry.op': 'request_handler.connect', - 'http.route': '/test-transaction', - 'connect.type': 'request_handler', - 'connect.name': '/test-transaction', - }, - op: 'request_handler.connect', - description: '/test-transaction', - parent_span_id: expect.stringMatching(/[a-f0-9]{16}/), - span_id: expect.stringMatching(/[a-f0-9]{16}/), - start_timestamp: expect.any(Number), - status: 'ok', - timestamp: expect.any(Number), - trace_id: expect.stringMatching(/[a-f0-9]{32}/), - origin: 'auto.http.otel.connect', - }, - ], + spans: useSentryTraceProvider + ? [ + // TODO: Investigate whether transaction span array ordering is expected to stay + // compatible with the legacy OTel exporter path. SentryTraceProvider serializes + // native child spans in start/tree order, so the Connect handler span appears + // before the manual span created inside it. + connectSpanExpectation, + manualSpanExpectation, + ] + : [manualSpanExpectation, connectSpanExpectation], transaction: 'GET /test-transaction', type: 'transaction', transaction_info: { diff --git a/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/package.json b/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/package.json index 125372c4501a..696dddbaeed0 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/package.json @@ -19,5 +19,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-cjs-preload (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/src/app.js b/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/src/app.js index b41d99ab6440..3f6278256b00 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/src/app.js +++ b/dev-packages/e2e-tests/test-applications/node-express-cjs-preload/src/app.js @@ -42,6 +42,13 @@ async function run() { dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); app.listen(port, () => { diff --git a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/package.json b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/package.json index a2d2c720e92a..5fb064435314 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/package.json @@ -19,5 +19,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-esm-loader (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs index 544c773e5e7c..f6afd668b278 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/src/instrument.mjs @@ -5,4 +5,11 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/node-express-esm-preload/package.json b/dev-packages/e2e-tests/test-applications/node-express-esm-preload/package.json index 4a602b6bd304..6397a953d3c6 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-esm-preload/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-esm-preload/package.json @@ -19,5 +19,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-esm-preload (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-esm-preload/src/app.mjs b/dev-packages/e2e-tests/test-applications/node-express-esm-preload/src/app.mjs index cc680866ab1a..69e4f57d5783 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-esm-preload/src/app.mjs +++ b/dev-packages/e2e-tests/test-applications/node-express-esm-preload/src/app.mjs @@ -57,6 +57,13 @@ async function run() { dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); app.listen(port, () => { diff --git a/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json b/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json index 84afe281c642..0f98c5dadf89 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json @@ -26,5 +26,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-incorrect-instrumentation (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/src/app.ts b/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/src/app.ts index 2ab5d1ace5a0..41c28299f819 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/src/app.ts @@ -18,6 +18,13 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); app.get('/test-exception/:id', function (req, _res) { diff --git a/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/instrument.mjs b/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/instrument.mjs index f3dd95215d03..39e5b0f5bdaf 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/instrument.mjs @@ -6,4 +6,11 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); diff --git a/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/package.json b/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/package.json index 4460adbd034c..52cada285930 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-mcp-v2/package.json @@ -32,6 +32,13 @@ "extends": "../../package.json" }, "sentryTest": { - "optional": true + "optional": true, + "optionalVariants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-mcp-v2 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json b/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json index e5ec85096dce..b0f57c15c571 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json @@ -24,6 +24,13 @@ "extends": "../../package.json" }, "sentryTest": { - "optional": true + "optional": true, + "optionalVariants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-send-to-sentry (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/src/app.ts b/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/src/app.ts index ca5d61f742d9..fa39a66779f7 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/src/app.ts @@ -7,6 +7,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, includeLocalVariables: true, tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), beforeSendTransaction(event) { lastTransactionId = event.event_id; return event; diff --git a/dev-packages/e2e-tests/test-applications/node-express-streaming/package.json b/dev-packages/e2e-tests/test-applications/node-express-streaming/package.json index 77124040ff6f..44783dee360e 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-streaming/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-streaming/package.json @@ -31,5 +31,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-streaming (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-streaming/src/app.ts b/dev-packages/e2e-tests/test-applications/node-express-streaming/src/app.ts index 5a0d1afa4141..49cfb19d9a19 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-streaming/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-streaming/src/app.ts @@ -7,6 +7,13 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), enableLogs: true, traceLifecycle: 'stream', integrations: [ diff --git a/dev-packages/e2e-tests/test-applications/node-express-v5/package.json b/dev-packages/e2e-tests/test-applications/node-express-v5/package.json index cf33b86e8669..0a7a415876ce 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-v5/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-v5/package.json @@ -31,5 +31,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express-v5 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-v5/src/app.ts b/dev-packages/e2e-tests/test-applications/node-express-v5/src/app.ts index 9a7f6f07d8bc..ef59f1449d5b 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-v5/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-v5/src/app.ts @@ -14,6 +14,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, enableLogs: true, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), integrations: [Sentry.nodeRuntimeMetricsIntegration({ collectionIntervalMs: 1_000 })], }); diff --git a/dev-packages/e2e-tests/test-applications/node-express/package.json b/dev-packages/e2e-tests/test-applications/node-express/package.json index 4d2ad1833a58..78580049f846 100644 --- a/dev-packages/e2e-tests/test-applications/node-express/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express/package.json @@ -31,5 +31,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-express (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express/src/app.ts b/dev-packages/e2e-tests/test-applications/node-express/src/app.ts index dc755f95d062..f429777e6767 100644 --- a/dev-packages/e2e-tests/test-applications/node-express/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-express/src/app.ts @@ -14,6 +14,13 @@ Sentry.init({ tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, enableLogs: true, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), integrations: [ Sentry.nativeNodeFetchIntegration({ headersToSpanAttributes: { diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-3/package.json b/dev-packages/e2e-tests/test-applications/node-fastify-3/package.json index 3fa36adbbbd5..c6e944333a65 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-3/package.json +++ b/dev-packages/e2e-tests/test-applications/node-fastify-3/package.json @@ -25,5 +25,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-fastify-3 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app-handle-error-override.ts b/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app-handle-error-override.ts index 378ef99fa309..3f7b06aafe11 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app-handle-error-override.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app-handle-error-override.ts @@ -25,6 +25,13 @@ Sentry.init({ }), ], tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app.ts b/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app.ts index 5b4a2f0d16ac..ad057a278584 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-3/src/app.ts @@ -31,6 +31,13 @@ Sentry.init({ }), ], tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-4/package.json b/dev-packages/e2e-tests/test-applications/node-fastify-4/package.json index 086ec85fac7a..c43933b8baae 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-4/package.json +++ b/dev-packages/e2e-tests/test-applications/node-fastify-4/package.json @@ -25,5 +25,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-fastify-4 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app-handle-error-override.ts b/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app-handle-error-override.ts index 72270efc05de..0287292a710b 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app-handle-error-override.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app-handle-error-override.ts @@ -25,6 +25,13 @@ Sentry.init({ }), ], tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app.ts b/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app.ts index 1c428c0486f9..47a98e1a9964 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-4/src/app.ts @@ -30,6 +30,13 @@ Sentry.init({ }), ], tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json b/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json index dc0fa7770c70..92163b2552ef 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json @@ -25,5 +25,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-fastify-5 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app-handle-error-override.ts b/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app-handle-error-override.ts index 91f0353816bb..39921c6b6ecc 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app-handle-error-override.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app-handle-error-override.ts @@ -25,6 +25,13 @@ Sentry.init({ }), ], tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app.ts b/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app.ts index 610a42f6fc00..71a5c0cd8038 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/src/app.ts @@ -35,6 +35,13 @@ Sentry.init({ }), ], tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server tracePropagationTargets: ['http://localhost:3030', '/external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-firebase/firestore-app/src/init.ts b/dev-packages/e2e-tests/test-applications/node-firebase/firestore-app/src/init.ts index c3b4a642375a..13c387c15520 100644 --- a/dev-packages/e2e-tests/test-applications/node-firebase/firestore-app/src/init.ts +++ b/dev-packages/e2e-tests/test-applications/node-firebase/firestore-app/src/init.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), integrations: [Sentry.firebaseIntegration()], defaultIntegrations: false, tunnel: `http://localhost:3031/`, // proxy server diff --git a/dev-packages/e2e-tests/test-applications/node-firebase/functions/src/init.ts b/dev-packages/e2e-tests/test-applications/node-firebase/functions/src/init.ts index c3b4a642375a..13c387c15520 100644 --- a/dev-packages/e2e-tests/test-applications/node-firebase/functions/src/init.ts +++ b/dev-packages/e2e-tests/test-applications/node-firebase/functions/src/init.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), integrations: [Sentry.firebaseIntegration()], defaultIntegrations: false, tunnel: `http://localhost:3031/`, // proxy server diff --git a/dev-packages/e2e-tests/test-applications/node-firebase/package.json b/dev-packages/e2e-tests/test-applications/node-firebase/package.json index a1d4965e9745..0243e906cb6e 100644 --- a/dev-packages/e2e-tests/test-applications/node-firebase/package.json +++ b/dev-packages/e2e-tests/test-applications/node-firebase/package.json @@ -26,5 +26,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-firebase (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-hapi/package.json b/dev-packages/e2e-tests/test-applications/node-hapi/package.json index ae87544644bf..e5675084d44a 100644 --- a/dev-packages/e2e-tests/test-applications/node-hapi/package.json +++ b/dev-packages/e2e-tests/test-applications/node-hapi/package.json @@ -21,5 +21,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-hapi (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js b/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js index 8b68e8412aba..663c0086609f 100644 --- a/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js +++ b/dev-packages/e2e-tests/test-applications/node-hapi/src/app.js @@ -7,6 +7,13 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); const Hapi = require('@hapi/hapi'); diff --git a/dev-packages/e2e-tests/test-applications/node-koa/index.js b/dev-packages/e2e-tests/test-applications/node-koa/index.js index 629c9bb82c04..d1f0416ab23e 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/index.js +++ b/dev-packages/e2e-tests/test-applications/node-koa/index.js @@ -7,6 +7,13 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tracePropagationTargets: ['http://localhost:3030', 'external-allowed'], }); diff --git a/dev-packages/e2e-tests/test-applications/node-koa/package.json b/dev-packages/e2e-tests/test-applications/node-koa/package.json index f4ef47cd0940..7c22dfe4df57 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/package.json +++ b/dev-packages/e2e-tests/test-applications/node-koa/package.json @@ -23,5 +23,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-koa (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-profiling-cjs/index.ts b/dev-packages/e2e-tests/test-applications/node-profiling-cjs/index.ts index e956a1d9de33..85da32bd4e9d 100644 --- a/dev-packages/e2e-tests/test-applications/node-profiling-cjs/index.ts +++ b/dev-packages/e2e-tests/test-applications/node-profiling-cjs/index.ts @@ -7,6 +7,13 @@ Sentry.init({ dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302', integrations: [nodeProfilingIntegration()], tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), profilesSampleRate: 1.0, }); diff --git a/dev-packages/e2e-tests/test-applications/node-profiling-cjs/package.json b/dev-packages/e2e-tests/test-applications/node-profiling-cjs/package.json index b136ea49dd4c..cc3c3a4e246d 100644 --- a/dev-packages/e2e-tests/test-applications/node-profiling-cjs/package.json +++ b/dev-packages/e2e-tests/test-applications/node-profiling-cjs/package.json @@ -19,5 +19,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-profiling-cjs (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-profiling-esm/index.ts b/dev-packages/e2e-tests/test-applications/node-profiling-esm/index.ts index e956a1d9de33..85da32bd4e9d 100644 --- a/dev-packages/e2e-tests/test-applications/node-profiling-esm/index.ts +++ b/dev-packages/e2e-tests/test-applications/node-profiling-esm/index.ts @@ -7,6 +7,13 @@ Sentry.init({ dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302', integrations: [nodeProfilingIntegration()], tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), profilesSampleRate: 1.0, }); diff --git a/dev-packages/e2e-tests/test-applications/node-profiling-esm/package.json b/dev-packages/e2e-tests/test-applications/node-profiling-esm/package.json index 44288c562a92..b87271410f59 100644 --- a/dev-packages/e2e-tests/test-applications/node-profiling-esm/package.json +++ b/dev-packages/e2e-tests/test-applications/node-profiling-esm/package.json @@ -19,5 +19,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "node-profiling-esm (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/package.json b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/package.json index a61e1da1bdcd..a472a47537f9 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/package.json @@ -23,5 +23,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nuxt-3-dynamic-import (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/sentry.server.config.ts index 729b2296c683..eb662e854b22 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/sentry.server.config.ts @@ -4,5 +4,12 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json b/dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json index 73b0c59e8a24..cfdefe2ad209 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json @@ -33,5 +33,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nuxt-3-min (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.server.config.ts index 729b2296c683..eb662e854b22 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.server.config.ts @@ -4,5 +4,12 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/package.json b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/package.json index 21acb5644735..770b7dbb125b 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/package.json @@ -24,5 +24,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "nuxt-3-top-level-import (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/sentry.server.config.ts index f08dea23ae03..33cd7fc4928d 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/sentry.server.config.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server debug: !!process.env.DEBUG, }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/package.json b/dev-packages/e2e-tests/test-applications/nuxt-3/package.json index b7481e044b3e..dd2d3f7a98b9 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/package.json @@ -12,8 +12,10 @@ "clean": "npx nuxi cleanup", "test": "playwright test", "test:build": "pnpm install && pnpm build", + "test:build:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", "test:build-canary": "pnpm add nuxt@npm:nuxt-nightly@3x && pnpm add nitropack@npm:nitropack-nightly@latest && pnpm install --force && pnpm build", - "test:assert": "pnpm test" + "test:assert": "pnpm test", + "test:assert:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert" }, "dependencies": { "@sentry/nuxt": "file:../../packed/sentry-nuxt-packed.tgz", @@ -30,6 +32,13 @@ "build-command": "pnpm test:build-canary", "label": "nuxt-3 (canary)" } + ], + "variants": [ + { + "build-command": "pnpm test:build:sentry-trace-provider", + "assert-command": "pnpm test:assert:sentry-trace-provider", + "label": "nuxt-3 (sentry-trace-provider)" + } ] }, "volta": { diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.server.config.ts index e04331934f99..a3ee4c3a9ced 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.server.config.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server enableNitroErrorHandler: false, // Error handler is defined in server/plugins/customNitroErrorHandler.ts }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/package.json b/dev-packages/e2e-tests/test-applications/nuxt-4/package.json index 02477111483d..cb6d446911b2 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/package.json @@ -14,8 +14,10 @@ "test:prod": "TEST_ENV=production playwright test", "test:dev": "bash ./nuxt-start-dev-server.bash && TEST_ENV=development playwright test environment", "test:build": "pnpm install && pnpm build", + "test:build:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", "test:build-canary": "pnpm add nuxt@npm:nuxt-nightly@latest && pnpm add nitropack@npm:nitropack-nightly@latest && pnpm install --force && pnpm build", - "test:assert": "pnpm test:prod && pnpm test:dev" + "test:assert": "pnpm test:prod && pnpm test:dev", + "test:assert:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert" }, "dependencies": { "@pinia/nuxt": "^0.5.5", @@ -36,6 +38,13 @@ "build-command": "pnpm test:build-canary", "label": "nuxt-4 (canary)" } + ], + "variants": [ + { + "build-command": "pnpm test:build:sentry-trace-provider", + "assert-command": "pnpm test:assert:sentry-trace-provider", + "label": "nuxt-4 (sentry-trace-provider)" + } ] } } diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.server.config.ts index 26519911072b..228f0dcccbd1 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.server.config.ts @@ -3,5 +3,12 @@ import * as Sentry from '@sentry/nuxt'; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-5/package.json b/dev-packages/e2e-tests/test-applications/nuxt-5/package.json index 12830c98e6de..e46cad085167 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-5/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-5/package.json @@ -14,8 +14,10 @@ "test:prod": "TEST_ENV=production playwright test", "test:dev": "bash ./nuxt-start-dev-server.bash && TEST_ENV=development playwright test environment", "test:build": "pnpm install && pnpm build", + "test:build:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", "test:build-canary": "pnpm add nuxt@npm:nuxt-nightly@latest && pnpm add nitro@npm:nitro-nightly@latest && pnpm install --force && pnpm build", - "test:assert": "pnpm test:prod && pnpm test:dev" + "test:assert": "pnpm test:prod && pnpm test:dev", + "test:assert:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert" }, "//": [ "Currently, we need to install the latest version of Nitro and the Nuxt nightlies as those contain Nuxt v5", diff --git a/dev-packages/e2e-tests/test-applications/nuxt-5/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-5/sentry.server.config.ts index 26519911072b..228f0dcccbd1 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-5/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-5/sentry.server.config.ts @@ -3,5 +3,12 @@ import * as Sentry from '@sentry/nuxt'; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/instrument.mjs b/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/instrument.mjs index c16240141b6d..48a130bd25d6 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/instrument.mjs @@ -4,5 +4,12 @@ Sentry.init({ dsn: 'https://username@domain/123', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: `http://localhost:3031/`, // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/package.json b/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/package.json index 20fdccf46f4c..4c76a7bc3eb6 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/package.json +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework-custom/package.json @@ -54,5 +54,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "react-router-7-framework-custom (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/instrument.mjs b/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/instrument.mjs index bb1dad2e5da9..22e362a9b1bd 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/instrument.mjs @@ -6,5 +6,12 @@ Sentry.init({ dsn: 'https://username@domain/123', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: `http://localhost:3031/`, // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/package.json b/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/package.json index 0ce52dd6cca2..6b461baccb94 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/package.json +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/package.json @@ -57,6 +57,13 @@ "extends": "../../package.json" }, "sentryTest": { - "optional": true + "optional": true, + "optionalVariants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "react-router-7-framework-instrumentation (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/instrument.mjs b/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/instrument.mjs index 48e4b7b61ff3..aef6f9cb866e 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/instrument.mjs @@ -4,5 +4,12 @@ Sentry.init({ dsn: 'https://username@domain/123', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: `http://localhost:3031/`, // proxy server, }); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/package.json b/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/package.json index 65f4a96b0165..91b44e1e4aac 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/package.json +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework-node-20-18/package.json @@ -30,7 +30,9 @@ "typecheck": "react-router typegen && tsc", "clean": "npx rimraf node_modules pnpm-lock.yaml", "test:build": "pnpm install && pnpm build", + "test:build:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", "test:assert": "pnpm test:ts && pnpm test:playwright", + "test:assert:sentry-trace-provider": "E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", "test:ts": "pnpm typecheck", "test:playwright": "playwright test" }, @@ -60,5 +62,14 @@ "overrides": { "p-map": "^4.0.0" } + }, + "sentryTest": { + "variants": [ + { + "build-command": "pnpm test:build:sentry-trace-provider", + "assert-command": "pnpm test:assert:sentry-trace-provider", + "label": "react-router-7-framework-node-20-18 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework/app/routes/performance/with-middleware.tsx b/dev-packages/e2e-tests/test-applications/react-router-7-framework/app/routes/performance/with-middleware.tsx index c86f78e17164..e0cd8c004cf5 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework/app/routes/performance/with-middleware.tsx +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework/app/routes/performance/with-middleware.tsx @@ -12,7 +12,8 @@ async function getUser() { } const authMiddleware: Route.MiddlewareFunction = async ({ request, context }, next) => { - Sentry.startSpan({ name: 'authMiddleware', op: 'middleware.auth' }, async () => { + // React Router middleware must keep the async `next()` chain alive until it completes. + await Sentry.startSpan({ name: 'authMiddleware', op: 'middleware.auth' }, async () => { const user: User = await getUser(); context.set(userContext, user); await next(); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework/instrument.mjs b/dev-packages/e2e-tests/test-applications/react-router-7-framework/instrument.mjs index c16240141b6d..48a130bd25d6 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework/instrument.mjs @@ -4,5 +4,12 @@ Sentry.init({ dsn: 'https://username@domain/123', environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: `http://localhost:3031/`, // proxy server }); diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework/package.json b/dev-packages/e2e-tests/test-applications/react-router-7-framework/package.json index 033fc63fec72..3c591cb08d30 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework/package.json +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework/package.json @@ -62,6 +62,11 @@ { "build-command": "pnpm test:build-latest", "label": "react-router-7-framework (latest)" + }, + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "react-router-7-framework (sentry-trace-provider)" } ] } diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework/tests/performance/middleware.server.test.ts b/dev-packages/e2e-tests/test-applications/react-router-7-framework/tests/performance/middleware.server.test.ts index dbce05350ad9..971541eb7536 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework/tests/performance/middleware.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework/tests/performance/middleware.server.test.ts @@ -12,27 +12,28 @@ test.describe('server - middleware', () => { return transactionEvent.transaction === '/performance/with-middleware'; }); - const customMiddlewareTxPromise = waitForTransaction(APP_NAME, async transactionEvent => { - return transactionEvent.transaction === 'authMiddleware'; - }); - await page.goto(`/performance/with-middleware`); const serverTx = await serverTxPromise; const pageloadTx = await pageloadTxPromise; - const customMiddlewareTx = await customMiddlewareTxPromise; const traceIds = { server: serverTx?.contexts?.trace?.trace_id, pageload: pageloadTx?.contexts?.trace?.trace_id, - customMiddleware: customMiddlewareTx?.contexts?.trace?.trace_id, }; expect(pageloadTx).toBeDefined(); - expect(customMiddlewareTx).toBeDefined(); + + // The app awaits Sentry.startSpan around the middleware `next()` call, so the manual + // middleware span belongs to the request transaction instead of becoming a root transaction. + const customMiddlewareSpans = + serverTx.spans?.filter(span => { + return span.description === 'authMiddleware' && span.op === 'middleware.auth'; + }) ?? []; + + expect(customMiddlewareSpans).toHaveLength(1); // Assert that all transactions belong to the same trace expect(traceIds.server).toBe(traceIds.pageload); - expect(traceIds.server).toBe(traceIds.customMiddleware); }); }); diff --git a/dev-packages/e2e-tests/test-applications/remix-server-timing/instrument.server.cjs b/dev-packages/e2e-tests/test-applications/remix-server-timing/instrument.server.cjs index 6d211cac4592..023cd91bd8cd 100644 --- a/dev-packages/e2e-tests/test-applications/remix-server-timing/instrument.server.cjs +++ b/dev-packages/e2e-tests/test-applications/remix-server-timing/instrument.server.cjs @@ -2,6 +2,13 @@ const Sentry = require('@sentry/remix'); Sentry.init({ tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), environment: 'qa', // dynamic sampling bias to keep transactions dsn: process.env.E2E_TEST_DSN, tunnel: 'http://localhost:3031/', // proxy server diff --git a/dev-packages/e2e-tests/test-applications/remix-server-timing/package.json b/dev-packages/e2e-tests/test-applications/remix-server-timing/package.json index fd57d2920d5a..d0f4b3f96fe5 100644 --- a/dev-packages/e2e-tests/test-applications/remix-server-timing/package.json +++ b/dev-packages/e2e-tests/test-applications/remix-server-timing/package.json @@ -38,5 +38,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "remix-server-timing (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/package.json b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/package.json index 747162d0bd75..77379c98288d 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/package.json +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/package.json @@ -34,5 +34,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "solidstart-dynamic-import (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts index 3dd5d8933b7b..16897c2903d0 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-dynamic-import/src/instrument.server.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server debug: !!process.env.DEBUG, }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/package.json b/dev-packages/e2e-tests/test-applications/solidstart-spa/package.json index a9d1d6b91da3..cf2f7db4f0f9 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/package.json +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/package.json @@ -34,5 +34,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "solidstart-spa (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts b/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts index 3dd5d8933b7b..16897c2903d0 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-spa/src/instrument.server.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server debug: !!process.env.DEBUG, }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/package.json b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/package.json index c97a130c92b1..fb4a82cddac2 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/package.json +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/package.json @@ -34,5 +34,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "solidstart-top-level-import (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts index 3dd5d8933b7b..16897c2903d0 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart-top-level-import/src/instrument.server.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server debug: !!process.env.DEBUG, }); diff --git a/dev-packages/e2e-tests/test-applications/solidstart/package.json b/dev-packages/e2e-tests/test-applications/solidstart/package.json index 7e382b6dc54b..f7e00d311aad 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/package.json +++ b/dev-packages/e2e-tests/test-applications/solidstart/package.json @@ -34,5 +34,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "solidstart (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/solidstart/src/instrument.server.ts b/dev-packages/e2e-tests/test-applications/solidstart/src/instrument.server.ts index 3dd5d8933b7b..16897c2903d0 100644 --- a/dev-packages/e2e-tests/test-applications/solidstart/src/instrument.server.ts +++ b/dev-packages/e2e-tests/test-applications/solidstart/src/instrument.server.ts @@ -4,6 +4,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1.0, // Capture 100% of the transactions + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server debug: !!process.env.DEBUG, }); diff --git a/dev-packages/e2e-tests/test-applications/supabase-nextjs/package.json b/dev-packages/e2e-tests/test-applications/supabase-nextjs/package.json index c5c86c0d31ae..a572a2780c16 100644 --- a/dev-packages/e2e-tests/test-applications/supabase-nextjs/package.json +++ b/dev-packages/e2e-tests/test-applications/supabase-nextjs/package.json @@ -36,5 +36,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "supabase-nextjs (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/supabase-nextjs/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/supabase-nextjs/sentry.server.config.ts index 3992352ec961..7201d5d081e1 100644 --- a/dev-packages/e2e-tests/test-applications/supabase-nextjs/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/supabase-nextjs/sentry.server.config.ts @@ -9,6 +9,13 @@ Sentry.init({ environment: 'qa', // dynamic sampling bias to keep transactions tracesSampleRate: 1, dataCollection: { userInfo: true }, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), tunnel: 'http://localhost:3031/', // proxy server transportOptions: { // We expect the app to send a lot of events in a short time diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json index 12f39178da15..61bb0f73ec40 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/package.json @@ -33,5 +33,14 @@ "type": "module", "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "sveltekit-2-kit-tracing (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/src/instrumentation.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/src/instrumentation.server.ts index 136b51a44dee..8c3ea06e3a5f 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/src/instrumentation.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-kit-tracing/src/instrumentation.server.ts @@ -7,5 +7,12 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), spotlight: import.meta.env.DEV, }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json index ff87d0e863d3..cd0dd9dd5b62 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/package.json @@ -33,5 +33,14 @@ "type": "module", "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "sveltekit-2-svelte-5 (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/src/hooks.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/src/hooks.server.ts index 99bf4a17aa96..ab30c4682fd7 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/src/hooks.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/src/hooks.server.ts @@ -8,6 +8,13 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), spotlight: import.meta.env.DEV, }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/package.json index 23f059eaee43..a83c53ee5f82 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/package.json @@ -32,5 +32,14 @@ "type": "module", "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "sveltekit-2.5.0-twp (sentry-trace-provider)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/src/hooks.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/src/hooks.server.ts index e60e51b25968..4292c5b676b0 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/src/hooks.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2.5.0-twp/src/hooks.server.ts @@ -5,6 +5,13 @@ Sentry.init({ environment: 'qa', // dynamic sampling bias to keep transactions dsn: E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); // not logging anything to console to avoid noise in the test output diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json index 75b1967d802f..538a51fbabc9 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/package.json @@ -32,5 +32,14 @@ "volta": { "extends": "../../package.json" }, - "type": "module" + "type": "module", + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "sveltekit-2 (sentry-trace-provider)" + } + ] + } } diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts index 92909c53a24c..719a12efc391 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/hooks.server.ts @@ -7,6 +7,13 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), }); // not logging anything to console to avoid noise in the test output diff --git a/dev-packages/e2e-tests/test-applications/tanstackstart-react/instrument.server.mjs b/dev-packages/e2e-tests/test-applications/tanstackstart-react/instrument.server.mjs index 8bc20de7578b..a607a0046c5b 100644 --- a/dev-packages/e2e-tests/test-applications/tanstackstart-react/instrument.server.mjs +++ b/dev-packages/e2e-tests/test-applications/tanstackstart-react/instrument.server.mjs @@ -5,6 +5,13 @@ Sentry.init({ dsn: process.env.E2E_TEST_DSN, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), transportOptions: { // We expect the app to send a lot of events in a short time bufferSize: 1000, diff --git a/dev-packages/e2e-tests/test-applications/tanstackstart-react/package.json b/dev-packages/e2e-tests/test-applications/tanstackstart-react/package.json index 0525acfad587..910d2586b994 100644 --- a/dev-packages/e2e-tests/test-applications/tanstackstart-react/package.json +++ b/dev-packages/e2e-tests/test-applications/tanstackstart-react/package.json @@ -66,6 +66,11 @@ "label": "tanstackstart-react (tunnel-object)", "build-command": "pnpm test:build:tunnel-object", "assert-command": "pnpm test:assert:tunnel-object" + }, + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "tanstackstart-react (sentry-trace-provider)" } ] } diff --git a/dev-packages/e2e-tests/test-applications/tsx-express/instrument.mjs b/dev-packages/e2e-tests/test-applications/tsx-express/instrument.mjs index ddc96c7c17fc..809ca41f133b 100644 --- a/dev-packages/e2e-tests/test-applications/tsx-express/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/tsx-express/instrument.mjs @@ -6,5 +6,12 @@ Sentry.init({ debug: !!process.env.DEBUG, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1, + ...(process.env.E2E_USE_SENTRY_TRACE_PROVIDER === '1' + ? { + _experiments: { + useSentryTraceProvider: true, + }, + } + : {}), enableLogs: true, }); diff --git a/dev-packages/e2e-tests/test-applications/tsx-express/package.json b/dev-packages/e2e-tests/test-applications/tsx-express/package.json index 7794d2c7ac52..d12206ae9ceb 100644 --- a/dev-packages/e2e-tests/test-applications/tsx-express/package.json +++ b/dev-packages/e2e-tests/test-applications/tsx-express/package.json @@ -31,5 +31,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:build", + "assert-command": "env E2E_USE_SENTRY_TRACE_PROVIDER=1 pnpm test:assert", + "label": "tsx-express (sentry-trace-provider)" + } + ] } } diff --git a/packages/core/src/tracing/index.ts b/packages/core/src/tracing/index.ts index 57303947249b..66a8e89fea13 100644 --- a/packages/core/src/tracing/index.ts +++ b/packages/core/src/tracing/index.ts @@ -13,6 +13,7 @@ export { SPAN_STATUS_ERROR, SPAN_STATUS_OK, SPAN_STATUS_UNSET } from './spanstat export { startSpan, startInactiveSpan, + _INTERNAL_startInactiveSpan, startSpanManual, continueTrace, withActiveSpan, diff --git a/packages/core/src/tracing/sentrySpan.ts b/packages/core/src/tracing/sentrySpan.ts index 8387c788d5fd..390ca3eb90e6 100644 --- a/packages/core/src/tracing/sentrySpan.ts +++ b/packages/core/src/tracing/sentrySpan.ts @@ -143,7 +143,7 @@ export class SentrySpan implements Span { * @hidden * @internal */ - public recordException(_exception: unknown, _time?: number | undefined): void { + public recordException(_exception: unknown, _time?: SpanTimeInput | undefined): void { // noop } diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index 7a31217fe51a..fd6385fd63d9 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -181,6 +181,20 @@ export function startInactiveSpan(options: StartSpanOptions): Span { return acs.startInactiveSpan(options); } + return _startInactiveSpanImpl(options); +} + +/** + * Internal version of startInactiveSpan that bypasses the ACS check. + * Used by SentryTraceProvider to create spans without triggering recursion + * through ACS overrides. + * @hidden + */ +export function _INTERNAL_startInactiveSpan(options: StartSpanOptions): Span { + return _startInactiveSpanImpl(options); +} + +function _startInactiveSpanImpl(options: StartSpanOptions): Span { const spanArguments = parseSentrySpanArguments(options); const { forceTransaction, parentSpan: customParentSpan } = options; diff --git a/packages/core/src/types/options.ts b/packages/core/src/types/options.ts index f40a79c04ecf..6c8854bf32f1 100644 --- a/packages/core/src/types/options.ts +++ b/packages/core/src/types/options.ts @@ -466,6 +466,14 @@ export interface ClientOptions { - public traceProvider: BasicTracerProvider | undefined; + public traceProvider: OpenTelemetryTraceProvider | undefined; public asyncLocalStorageLookup: AsyncLocalStorageLookup | undefined; private _tracer: Tracer | undefined; diff --git a/packages/node-core/src/sdk/index.ts b/packages/node-core/src/sdk/index.ts index 31493a273d4a..42b0c01a3638 100644 --- a/packages/node-core/src/sdk/index.ts +++ b/packages/node-core/src/sdk/index.ts @@ -168,7 +168,9 @@ export function validateOpenTelemetrySetup(): void { const required: ReturnType = ['SentryContextManager', 'SentryPropagator']; - if (hasSpansEnabled()) { + const hasSentryTraceProvider = setup.includes('SentryTraceProvider'); + + if (hasSpansEnabled() && !hasSentryTraceProvider) { required.push('SentrySpanProcessor'); } @@ -180,7 +182,7 @@ export function validateOpenTelemetrySetup(): void { } } - if (!setup.includes('SentrySampler')) { + if (!hasSentryTraceProvider && !setup.includes('SentrySampler')) { debug.warn( 'You have to set up the SentrySampler. Without this, the OpenTelemetry & Sentry integration may still work, but sample rates set for the Sentry SDK will not be respected. If you use a custom sampler, make sure to use `wrapSamplingDecision`.', ); diff --git a/packages/node/src/sdk/initOtel.ts b/packages/node/src/sdk/initOtel.ts index e3794097b2b7..5b03501aea5e 100644 --- a/packages/node/src/sdk/initOtel.ts +++ b/packages/node/src/sdk/initOtel.ts @@ -9,11 +9,16 @@ import { setupOpenTelemetryLogger, } from '@sentry/node-core'; import { + applyOtelSpanData, type AsyncLocalStorageLookup, getSentryResource, + type OpenTelemetryTraceProvider, SentryPropagator, SentrySampler, SentrySpanProcessor, + SentryTraceProvider, + setIsSetup, + setOpenTelemetryContextAsyncContextStrategy, } from '@sentry/opentelemetry'; import { DEBUG_BUILD } from '../debug-build'; import { getOpenTelemetryInstrumentationToPreload } from '../integrations/tracing'; @@ -86,7 +91,12 @@ function getPreloadMethods(integrationNames?: string[]): ((() => void) & { id: s export function setupOtel( client: NodeClient, options: AdditionalOpenTelemetryOptions = {}, -): [BasicTracerProvider, AsyncLocalStorageLookup] { +): [OpenTelemetryTraceProvider | undefined, AsyncLocalStorageLookup | undefined] { + if (client.getOptions()._experiments?.useSentryTraceProvider) { + setOpenTelemetryContextAsyncContextStrategy(); + return setupSentryTraceProvider(client, options); + } + // Create and configure NodeTracerProvider const provider = new BasicTracerProvider({ sampler: new SentrySampler(client), @@ -111,6 +121,66 @@ export function setupOtel( return [provider, ctxManager.getAsyncLocalStorageLookup()]; } +function setupSentryTraceProvider( + client: NodeClient, + options: AdditionalOpenTelemetryOptions = {}, +): [SentryTraceProvider | undefined, AsyncLocalStorageLookup | undefined] { + if (options.spanProcessors?.length) { + DEBUG_BUILD && + coreDebug.warn( + 'Ignoring `openTelemetrySpanProcessors` because `_experiments.useSentryTraceProvider` is enabled.', + ); + } + + const provider = new SentryTraceProvider({ resource: getSentryResource('node') }); + + if (!trace.setGlobalTracerProvider(provider)) { + DEBUG_BUILD && + coreDebug.warn( + 'Could not register SentryTraceProvider because another OpenTelemetry tracer provider is already registered.', + ); + return [undefined, undefined]; + } + + // Only mark the provider as set up once it is actually the registered global + // tracer provider, so setup validation doesn't skip required checks when + // registration failed. + setIsSetup('SentryTraceProvider'); + + propagation.setGlobalPropagator(new SentryPropagator()); + + const ctxManager = new SentryContextManager(); + context.setGlobalContextManager(ctxManager); + + client.on('spanEnd', span => { + applyOtelSpanData(span, { finalizeStatus: true }); + }); + + client.on('preprocessEvent', event => { + if (event.type !== 'transaction' || client.getOptions().traceLifecycle === 'stream') { + return; + } + + event.contexts = { + ...event.contexts, + ...(typeof event.contexts?.trace?.data?.['http.response.status_code'] === 'number' + ? { + response: { + ...event.contexts.response, + status_code: event.contexts.trace.data['http.response.status_code'], + }, + } + : undefined), + otel: { + resource: provider.resource?.attributes, + ...event.contexts?.otel, + }, + }; + }); + + return [provider, ctxManager.getAsyncLocalStorageLookup()]; +} + /** Just exported for tests. */ export function _clampSpanProcessorTimeout(maxSpanWaitDuration: number | undefined): number | undefined { if (maxSpanWaitDuration == null) { diff --git a/packages/node/test/sdk/init.test.ts b/packages/node/test/sdk/init.test.ts index 26fe2d9933e6..266adce5f677 100644 --- a/packages/node/test/sdk/init.test.ts +++ b/packages/node/test/sdk/init.test.ts @@ -1,3 +1,4 @@ +import { trace } from '@opentelemetry/api'; import type { Integration } from '@sentry/core'; import { debug, SDK_VERSION } from '@sentry/core'; import * as SentryOpentelemetry from '@sentry/opentelemetry'; @@ -194,6 +195,53 @@ describe('init()', () => { expect(client?.traceProvider).not.toBeDefined(); }); + + it('uses the minimal Sentry trace provider when the experiment is enabled', () => { + init({ dsn: PUBLIC_DSN, _experiments: { useSentryTraceProvider: true } }); + + const client = getClient(); + + expect(client?.traceProvider).toBeInstanceOf(SentryOpentelemetry.SentryTraceProvider); + }); + + it('warns and ignores additional span processors when the minimal Sentry trace provider is enabled', () => { + const warnSpy = vi.spyOn(debug, 'warn').mockImplementation(() => {}); + + init({ + dsn: PUBLIC_DSN, + _experiments: { useSentryTraceProvider: true }, + openTelemetrySpanProcessors: [ + { + forceFlush: () => Promise.resolve(), + onStart: () => undefined, + onEnd: () => undefined, + shutdown: () => Promise.resolve(), + }, + ], + }); + + expect(warnSpy).toHaveBeenCalledWith( + 'Ignoring `openTelemetrySpanProcessors` because `_experiments.useSentryTraceProvider` is enabled.', + ); + }); + + it('does not mark SentryTraceProvider as set up when global registration fails', () => { + // Simulate another OpenTelemetry tracer provider already being registered. + const setGlobalSpy = vi.spyOn(trace, 'setGlobalTracerProvider').mockReturnValue(false); + const setIsSetupSpy = vi.spyOn(SentryOpentelemetry, 'setIsSetup'); + const warnSpy = vi.spyOn(debug, 'warn').mockImplementation(() => {}); + + init({ dsn: PUBLIC_DSN, _experiments: { useSentryTraceProvider: true } }); + + expect(getClient()?.traceProvider).not.toBeDefined(); + expect(setIsSetupSpy).not.toHaveBeenCalledWith('SentryTraceProvider'); + expect(warnSpy).toHaveBeenCalledWith( + 'Could not register SentryTraceProvider because another OpenTelemetry tracer provider is already registered.', + ); + + setGlobalSpy.mockRestore(); + setIsSetupSpy.mockRestore(); + }); }); it('returns initialized client', () => { diff --git a/packages/opentelemetry/README.md b/packages/opentelemetry/README.md index 18f2589a8701..164bcf87bd0c 100644 --- a/packages/opentelemetry/README.md +++ b/packages/opentelemetry/README.md @@ -85,6 +85,39 @@ function setupSentry() { A full setup example can be found in [node-experimental](https://github.com/getsentry/sentry-javascript/blob/develop/packages/node-experimental). +## Experimental Sentry Trace Provider + +`SentryTraceProvider` is an experimental minimal OpenTelemetry tracer provider which creates native Sentry spans directly. +It is useful when code uses the global OpenTelemetry API and you do not need the full OpenTelemetry SDK span processor +and exporter pipeline. + +```js +import { trace } from '@opentelemetry/api'; +import { SentryTraceProvider } from '@sentry/opentelemetry'; + +trace.setGlobalTracerProvider(new SentryTraceProvider()); + +const span = trace.getTracer('example').startSpan('work'); +span.end(); +``` + +In `@sentry/node`, this provider can be enabled with the experimental option: + +```js +Sentry.init({ + dsn: 'xxx', + _experiments: { + useSentryTraceProvider: true, + }, +}); +``` + +This only captures spans from code that uses the global OpenTelemetry tracer provider. Spans created from a separate +custom provider instance still belong to that provider and should be sent to Sentry with `SentrySpanProcessor`. + +When this provider is enabled, additional OpenTelemetry span processors are ignored because Sentry spans are created +directly. OpenTelemetry logs and metrics are not handled by this provider. + ## Links - [Official SDK Docs](https://docs.sentry.io/quickstart/) diff --git a/packages/opentelemetry/src/asyncContextStrategy.ts b/packages/opentelemetry/src/asyncContextStrategy.ts index 7cb8dc0f54eb..71344841e22e 100644 --- a/packages/opentelemetry/src/asyncContextStrategy.ts +++ b/packages/opentelemetry/src/asyncContextStrategy.ts @@ -37,11 +37,6 @@ export function setOpenTelemetryContextAsyncContextStrategy(): void { function withScope(callback: (scope: Scope) => T): T { const ctx = api.context.active(); - // We depend on the otelContextManager to handle the context/hub - // We set the `SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY` context value, which is picked up by - // the OTEL context manager, which uses the presence of this key to determine if it should - // fork the isolation scope, or not - // as by default, we don't want to fork this, unless triggered explicitly by `withScope` return api.context.with(ctx, () => { return callback(getCurrentScope()); }); @@ -50,9 +45,6 @@ export function setOpenTelemetryContextAsyncContextStrategy(): void { function withSetScope(scope: Scope, callback: (scope: Scope) => T): T { const ctx = getContextFromScope(scope) || api.context.active(); - // We depend on the otelContextManager to handle the context/hub - // We set the `SENTRY_FORK_SET_SCOPE_CONTEXT_KEY` context value, which is picked up by - // the OTEL context manager, which picks up this scope as the current scope return api.context.with(ctx.setValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY, scope), () => { return callback(scope); }); @@ -61,10 +53,6 @@ export function setOpenTelemetryContextAsyncContextStrategy(): void { function withIsolationScope(callback: (isolationScope: Scope) => T): T { const ctx = api.context.active(); - // We depend on the otelContextManager to handle the context/hub - // We set the `SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY` context value, which is picked up by - // the OTEL context manager, which uses the presence of this key to determine if it should - // fork the isolation scope, or not return api.context.with(ctx.setValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY, true), () => { return callback(getIsolationScope()); }); @@ -73,10 +61,6 @@ export function setOpenTelemetryContextAsyncContextStrategy(): void { function withSetIsolationScope(isolationScope: Scope, callback: (isolationScope: Scope) => T): T { const ctx = api.context.active(); - // We depend on the otelContextManager to handle the context/hub - // We set the `SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY` context value, which is picked up by - // the OTEL context manager, which uses the presence of this key to determine if it should - // fork the isolation scope, or not return api.context.with(ctx.setValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, isolationScope), () => { return callback(getIsolationScope()); }); @@ -105,8 +89,6 @@ export function setOpenTelemetryContextAsyncContextStrategy(): void { getTraceData, continueTrace, startNewTrace, - // The types here don't fully align, because our own `Span` type is narrower - // than the OTEL one - but this is OK for here, as we now we'll only have OTEL spans passed around withActiveSpan: withActiveSpan as typeof defaultWithActiveSpan, }); } diff --git a/packages/opentelemetry/src/custom/client.ts b/packages/opentelemetry/src/custom/client.ts index a1f0e4792048..ed97faae4f62 100644 --- a/packages/opentelemetry/src/custom/client.ts +++ b/packages/opentelemetry/src/custom/client.ts @@ -1,9 +1,8 @@ import type { Tracer } from '@opentelemetry/api'; import { trace } from '@opentelemetry/api'; -import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; import type { Client } from '@sentry/core'; import { SDK_VERSION } from '@sentry/core'; -import type { OpenTelemetryClient as OpenTelemetryClientInterface } from '../types'; +import type { OpenTelemetryClient as OpenTelemetryClientInterface, OpenTelemetryTraceProvider } from '../types'; // Typescript complains if we do not use `...args: any[]` for the mixin, with: // A mixin class must have a constructor with a single rest parameter of type 'any[]'.ts(2545) @@ -23,7 +22,7 @@ export function wrapClientClass< >(ClientClass: ClassConstructor): WrappedClassConstructor { // @ts-expect-error We just assume that this is non-abstract, if you pass in an abstract class this would make it non-abstract class OpenTelemetryClient extends ClientClass implements OpenTelemetryClientInterface { - public traceProvider: BasicTracerProvider | undefined; + public traceProvider: OpenTelemetryTraceProvider | undefined; private _tracer: Tracer | undefined; public constructor(...args: any[]) { diff --git a/packages/opentelemetry/src/exports.ts b/packages/opentelemetry/src/exports.ts index 5eac9d3a7a4a..06d5df1f3576 100644 --- a/packages/opentelemetry/src/exports.ts +++ b/packages/opentelemetry/src/exports.ts @@ -46,8 +46,10 @@ export { wrapContextManagerClass } from './contextManager'; export { SentryPropagator, shouldPropagateTraceForUrl } from './propagator'; export { SentrySpanProcessor } from './spanProcessor'; export { SentrySampler, wrapSamplingDecision } from './sampler'; +export { applyOtelSpanData, SentryTraceProvider } from './sentryTraceProvider'; +export type { OpenTelemetryTraceProvider } from './types'; -export { openTelemetrySetupCheck } from './utils/setupCheck'; +export { openTelemetrySetupCheck, setIsSetup } from './utils/setupCheck'; export { getSentryResource } from './resource'; diff --git a/packages/opentelemetry/src/sentryTraceProvider.ts b/packages/opentelemetry/src/sentryTraceProvider.ts new file mode 100644 index 000000000000..89e7fcefe897 --- /dev/null +++ b/packages/opentelemetry/src/sentryTraceProvider.ts @@ -0,0 +1,356 @@ +/* eslint-disable max-lines */ +import type { + Context, + Span as OpenTelemetrySpan, + SpanOptions, + Tracer, + TracerOptions, + TracerProvider, +} from '@opentelemetry/api'; +import { context, SpanKind, trace } from '@opentelemetry/api'; +import { isTracingSuppressed } from '@opentelemetry/core'; +import { + _INTERNAL_safeMathRandom, + _INTERNAL_setSpanForScope, + addChildSpanToSpan, + addNonEnumerableProperty, + getCurrentScope, + getDynamicSamplingContextFromSpan, + getIsolationScope, + markSpanForOtelSourceInference, + SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME, + SEMANTIC_ATTRIBUTE_SENTRY_OP, + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + SentryNonRecordingSpan, + getCapturedScopesOnSpan, + getSpanStatusFromHttpCode, + setCapturedScopesOnSpan, + spanShouldInferOtelSource, + spanToJSON, + SPAN_STATUS_ERROR, + SPAN_STATUS_OK, + _INTERNAL_startInactiveSpan, + startNewTrace, + withScope, +} from '@sentry/core'; +import type { Span, SpanAttributes, SpanLink, SpanStatus } from '@sentry/core'; +import { SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY } from './constants'; +import { getSamplingDecision } from './utils/getSamplingDecision'; +import { inferSpanData } from './utils/parseSpanDescription'; + +type SentrySpanWithOtelKind = Span & { kind?: SpanKind }; + +const HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE = 'http.response.status_code'; +const LEGACY_HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE = 'http.status_code'; +const RPC_GRPC_STATUS_CODE_ATTRIBUTE = 'rpc.grpc.status_code'; + +const VALID_SPAN_STATUS_MESSAGES = new Set([ + 'ok', + 'deadline_exceeded', + 'unauthenticated', + 'permission_denied', + 'not_found', + 'resource_exhausted', + 'invalid_argument', + 'unimplemented', + 'unavailable', + 'internal_error', + 'unknown_error', + 'cancelled', + 'already_exists', + 'failed_precondition', + 'aborted', + 'out_of_range', + 'data_loss', +]); + +const GRPC_STATUS_CODE_MAP: Record = { + '1': 'cancelled', + '2': 'unknown_error', + '3': 'invalid_argument', + '4': 'deadline_exceeded', + '5': 'not_found', + '6': 'already_exists', + '7': 'permission_denied', + '8': 'resource_exhausted', + '9': 'failed_precondition', + '10': 'aborted', + '11': 'out_of_range', + '12': 'unimplemented', + '13': 'internal_error', + '14': 'unavailable', + '15': 'data_loss', + '16': 'unauthenticated', +}; + +/** + * A minimal OpenTelemetry TracerProvider which creates native Sentry spans. + */ +export class SentryTraceProvider implements TracerProvider { + public readonly resource?: { attributes: SpanAttributes }; + + private readonly _tracers = new Map(); + + public constructor(options: { resource?: { attributes: SpanAttributes } } = {}) { + this.resource = options.resource; + } + + /** @inheritdoc */ + public getTracer(name: string, version?: string, options?: TracerOptions): Tracer { + const key = JSON.stringify([name, version, options]); + const cachedTracer = this._tracers.get(key); + if (cachedTracer) { + return cachedTracer; + } + + const tracer = new SentryTracer(); + this._tracers.set(key, tracer); + return tracer; + } + + /** Compatibility with SDK tracer providers. */ + public forceFlush(): Promise { + return Promise.resolve(); + } + + /** Compatibility with SDK tracer providers. */ + public shutdown(): Promise { + return Promise.resolve(); + } +} + +class SentryTracer implements Tracer { + /** @inheritdoc */ + public startSpan(name: string, options: SpanOptions = {}, ctx?: Context): OpenTelemetrySpan { + const parentContext = ctx || context.active(); + const parentSpan = options.root ? undefined : trace.getSpan(parentContext); + + if (isTracingSuppressed(parentContext)) { + return this._createNonRecordingSpan(parentSpan); + } + + const span = this._startSentrySpan(name, options, parentSpan, ctx !== undefined); + + applyOtelSpanKind(span, options.kind); + if (options.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === undefined) { + markSpanForOtelSourceInference(span); + } + applyOtelSpanData(span); + return span as OpenTelemetrySpan; + } + + /** @inheritdoc */ + public startActiveSpan unknown>(name: string, fn: F): ReturnType; + public startActiveSpan unknown>( + name: string, + options: SpanOptions, + fn: F, + ): ReturnType; + public startActiveSpan unknown>( + name: string, + options: SpanOptions, + ctx: Context, + fn: F, + ): ReturnType; + public startActiveSpan unknown>( + name: string, + optionsOrFn: SpanOptions | F, + contextOrFn?: Context | F, + fn?: F, + ): ReturnType { + const options = typeof optionsOrFn === 'function' ? {} : optionsOrFn; + const ctx = typeof contextOrFn === 'function' || contextOrFn === undefined ? context.active() : contextOrFn; + const callback = ( + typeof optionsOrFn === 'function' ? optionsOrFn : typeof contextOrFn === 'function' ? contextOrFn : fn + ) as F; + + const span = this.startSpan(name, options, ctx); + let ctxWithSpan = trace.setSpan(ctx, span); + + const capturedIsolationScope = getCapturedScopesOnSpan(span as unknown as Span).isolationScope; + if (capturedIsolationScope) { + ctxWithSpan = ctxWithSpan.setValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, capturedIsolationScope); + } + + return context.with(ctxWithSpan, () => { + _INTERNAL_setSpanForScope(getCurrentScope(), span as unknown as Span); + return callback(span) as ReturnType; + }); + } + + private _startSentrySpan( + name: string, + options: SpanOptions, + parentSpan: OpenTelemetrySpan | undefined, + hasExplicitContext: boolean, + ): Span { + const sentryOptions = { + name, + attributes: options.attributes as SpanAttributes | undefined, + links: options.links as SpanLink[] | undefined, + startTime: options.startTime, + }; + + if (options.root) { + return startNewTrace(() => _INTERNAL_startInactiveSpan({ ...sentryOptions, parentSpan: null })); + } + + if (parentSpan?.spanContext().isRemote) { + return this._startRootSpanWithRemoteParent(sentryOptions, parentSpan); + } + + if (parentSpan) { + return _INTERNAL_startInactiveSpan({ ...sentryOptions, parentSpan: parentSpan as unknown as Span }); + } + + return _INTERNAL_startInactiveSpan({ + ...sentryOptions, + parentSpan: hasExplicitContext ? null : undefined, + }); + } + + private _startRootSpanWithRemoteParent( + options: Parameters[0], + parentSpan: OpenTelemetrySpan, + ): Span { + const { spanId, traceId } = parentSpan.spanContext(); + const dsc = getDynamicSamplingContextFromSpan(parentSpan as unknown as Span); + const sampleRand = typeof dsc.sample_rand === 'string' ? Number(dsc.sample_rand) : undefined; + + return withScope(scope => { + scope.setPropagationContext({ + traceId, + parentSpanId: spanId, + sampled: getSamplingDecision(parentSpan.spanContext()), + dsc, + sampleRand: + typeof sampleRand === 'number' && !Number.isNaN(sampleRand) ? sampleRand : _INTERNAL_safeMathRandom(), + }); + _INTERNAL_setSpanForScope(scope, undefined); + + return _INTERNAL_startInactiveSpan({ ...options, parentSpan: null }); + }); + } + + private _createNonRecordingSpan(parentSpan: OpenTelemetrySpan | undefined): OpenTelemetrySpan { + const span = new SentryNonRecordingSpan({ traceId: parentSpan?.spanContext().traceId }); + // Link to the parent (like core's `createChildOrRootSpan`) so `getRootSpan` and DSC + // resolution reach the parent. Non-recording spans no longer carry a `parentSpanId`. + if (parentSpan) { + addChildSpanToSpan(parentSpan as unknown as Span, span); + } + // Capture the scopes (mirroring `createChildOrRootSpan`) so `startActiveSpan` can + // fork the isolation scope onto the OTel context for work inside a suppressed span. + setCapturedScopesOnSpan(span, getCurrentScope(), getIsolationScope()); + return span as OpenTelemetrySpan; + } +} + +/** Apply OTel semantic inference to a Sentry span. */ +export function applyOtelSpanData(span: Span, options: { finalizeStatus?: boolean } = {}): void { + const spanJSON = spanToJSON(span); + const attributes = spanJSON.data; + const kind = (span as SentrySpanWithOtelKind).kind ?? SpanKind.INTERNAL; + const mayInferSource = spanShouldInferOtelSource(span); + const hasCustomSpanName = attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME] !== undefined; + const attributesForInference = + mayInferSource && !hasCustomSpanName && attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === 'custom' + ? { ...attributes, [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: undefined } + : attributes; + const inferred = inferSpanData(spanJSON.description || '', attributesForInference, kind); + + if (kind !== SpanKind.INTERNAL && attributes['otel.kind'] === undefined) { + span.setAttribute('otel.kind', SpanKind[kind]); + } + + if (inferred.op && attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === undefined) { + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, inferred.op); + } + + // Don't apply 'url' source at creation time — only at span end (finalizeStatus). + // At creation, http.route may not be set yet, so inference falls back to 'url'. + // Keeping the default 'custom' source from _startRootSpan allows + // enhanceDscWithOpenTelemetryRootSpanName to include the transaction name in + // the DSC. At span end, http.route is typically available and inference returns + // 'route' instead. If it's still 'url', it's applied then. + const shouldApplyInferredSource = + inferred.source !== undefined && + inferred.source !== 'custom' && + (options.finalizeStatus || inferred.source !== 'url') && + (spanJSON.parent_span_id === undefined || kind === SpanKind.SERVER); + + if ( + shouldApplyInferredSource && + (attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === undefined || (mayInferSource && !hasCustomSpanName)) + ) { + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, inferred.source); + } + + if (inferred.data) { + Object.entries(inferred.data).forEach(([key, value]) => { + if (value !== undefined && attributes[key] === undefined) { + span.setAttribute(key, value); + } + }); + } + + if (options.finalizeStatus) { + applyOtelCompatibilityAttributes(span, attributes); + applyOtelSpanStatus(span, attributes, spanJSON.status); + } + + if ( + inferred.description !== spanJSON.description && + (attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] !== 'custom' || (mayInferSource && !hasCustomSpanName)) + ) { + addNonEnumerableProperty(span as Span & { _name?: string }, '_name', inferred.description); + } +} + +function applyOtelSpanKind(span: Span, kind: SpanKind | undefined): void { + addNonEnumerableProperty(span as SentrySpanWithOtelKind, 'kind', kind ?? SpanKind.INTERNAL); +} + +function applyOtelSpanStatus(span: Span, attributes: SpanAttributes, status: string | undefined): void { + if (status === undefined) { + const inferredStatus = inferOtelSpanStatusFromAttributes(attributes); + span.setStatus(inferredStatus || { code: SPAN_STATUS_OK }); + return; + } + + if (!VALID_SPAN_STATUS_MESSAGES.has(status)) { + span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); + } +} + +function applyOtelCompatibilityAttributes(span: Span, attributes: SpanAttributes): void { + const legacyHttpStatusCode = attributes[LEGACY_HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE]; + + if (attributes[HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE] === undefined && legacyHttpStatusCode !== undefined) { + span.setAttribute(HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE, legacyHttpStatusCode); + attributes[HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE] = legacyHttpStatusCode; + } +} + +function inferOtelSpanStatusFromAttributes(attributes: SpanAttributes): SpanStatus | undefined { + const httpCodeAttribute = + attributes[HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE] ?? attributes[LEGACY_HTTP_RESPONSE_STATUS_CODE_ATTRIBUTE]; + const grpcCodeAttribute = attributes[RPC_GRPC_STATUS_CODE_ATTRIBUTE]; + + const numberHttpCode = + typeof httpCodeAttribute === 'number' + ? httpCodeAttribute + : typeof httpCodeAttribute === 'string' + ? parseInt(httpCodeAttribute, 10) + : undefined; + + if (typeof numberHttpCode === 'number') { + return getSpanStatusFromHttpCode(numberHttpCode); + } + + if (typeof grpcCodeAttribute === 'string') { + return { code: SPAN_STATUS_ERROR, message: GRPC_STATUS_CODE_MAP[grpcCodeAttribute] || 'unknown_error' }; + } + + return undefined; +} diff --git a/packages/opentelemetry/src/types.ts b/packages/opentelemetry/src/types.ts index 807e9b1d857f..4563f7b8c72f 100644 --- a/packages/opentelemetry/src/types.ts +++ b/packages/opentelemetry/src/types.ts @@ -1,10 +1,15 @@ -import type { Span as WriteableSpan, SpanKind, Tracer } from '@opentelemetry/api'; +import type { Span as WriteableSpan, SpanKind, Tracer, TracerProvider } from '@opentelemetry/api'; import type { BasicTracerProvider, ReadableSpan } from '@opentelemetry/sdk-trace-base'; import type { Scope, Span, StartSpanOptions } from '@sentry/core'; +export interface OpenTelemetryTraceProvider extends TracerProvider { + forceFlush(): Promise; + shutdown(): Promise; +} + export interface OpenTelemetryClient { tracer: Tracer; - traceProvider: BasicTracerProvider | undefined; + traceProvider: BasicTracerProvider | OpenTelemetryTraceProvider | undefined; } export interface OpenTelemetrySpanContext extends StartSpanOptions { diff --git a/packages/opentelemetry/src/utils/enhanceDscWithOpenTelemetryRootSpanName.ts b/packages/opentelemetry/src/utils/enhanceDscWithOpenTelemetryRootSpanName.ts index 7fb080119d3b..028dba699ab8 100644 --- a/packages/opentelemetry/src/utils/enhanceDscWithOpenTelemetryRootSpanName.ts +++ b/packages/opentelemetry/src/utils/enhanceDscWithOpenTelemetryRootSpanName.ts @@ -2,7 +2,6 @@ import type { Client } from '@sentry/core'; import { hasSpansEnabled, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, spanToJSON } from '@sentry/core'; import { getSamplingDecision } from './getSamplingDecision'; import { parseSpanDescription } from './parseSpanDescription'; -import { spanHasName } from './spanTypes'; /** * Setup a DSC handler on the passed client, @@ -24,9 +23,11 @@ export function enhanceDscWithOpenTelemetryRootSpanName(client: Client): void { const attributes = jsonSpan.data; const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]; - const { description } = spanHasName(rootSpan) ? parseSpanDescription(rootSpan) : { description: undefined }; - if (source !== 'url' && description) { - dsc.transaction = description; + if (jsonSpan.description) { + const { description } = parseSpanDescription(rootSpan); + if (source !== 'url' && description) { + dsc.transaction = description; + } } // Also ensure sampling decision is correctly inferred diff --git a/packages/opentelemetry/src/utils/parseSpanDescription.ts b/packages/opentelemetry/src/utils/parseSpanDescription.ts index ea06acb3a060..aa935ecfe983 100644 --- a/packages/opentelemetry/src/utils/parseSpanDescription.ts +++ b/packages/opentelemetry/src/utils/parseSpanDescription.ts @@ -14,7 +14,7 @@ import { RPC_SERVICE, URL_FULL, } from '@sentry/conventions/attributes'; -import type { SpanAttributes, TransactionSource } from '@sentry/core'; +import type { Span, SpanAttributes, TransactionSource } from '@sentry/core'; import { getSanitizedUrlString, parseUrl, @@ -22,6 +22,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + spanToJSON, stripUrlQueryAndFragment, } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION } from '../semanticAttributes'; @@ -104,10 +105,19 @@ export function inferSpanData(spanName: string, attributes: SpanAttributes, kind * Based on https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/7422ce2a06337f68a59b552b8c5a2ac125d6bae5/exporter/sentryexporter/sentry_exporter.go#L306 */ export function parseSpanDescription(span: AbstractSpan): SpanDescription { - const attributes = spanHasAttributes(span) ? span.attributes : {}; - const name = spanHasName(span) ? span.name : ''; - const kind = getSpanKind(span); + let attributes: Attributes; + let name: string; + + if (spanHasAttributes(span)) { + attributes = span.attributes; + name = spanHasName(span) ? span.name : ''; + } else { + const json = typeof (span as Span).spanContext === 'function' ? spanToJSON(span as Span) : undefined; + attributes = json?.data || {}; + name = spanHasName(span) ? span.name : json?.description || ''; + } + const kind = getSpanKind(span); return inferSpanData(name, attributes, kind); } diff --git a/packages/opentelemetry/src/utils/setupCheck.ts b/packages/opentelemetry/src/utils/setupCheck.ts index 66bc7b445f83..0cc8d9d310f7 100644 --- a/packages/opentelemetry/src/utils/setupCheck.ts +++ b/packages/opentelemetry/src/utils/setupCheck.ts @@ -1,4 +1,9 @@ -type OpenTelemetryElement = 'SentrySpanProcessor' | 'SentryContextManager' | 'SentryPropagator' | 'SentrySampler'; +type OpenTelemetryElement = + | 'SentrySpanProcessor' + | 'SentryContextManager' + | 'SentryPropagator' + | 'SentrySampler' + | 'SentryTraceProvider'; const setupElements = new Set(); diff --git a/packages/opentelemetry/test/sentryTraceProvider.test.ts b/packages/opentelemetry/test/sentryTraceProvider.test.ts new file mode 100644 index 000000000000..c665e0550563 --- /dev/null +++ b/packages/opentelemetry/test/sentryTraceProvider.test.ts @@ -0,0 +1,183 @@ +import { context, SpanKind, trace, TraceFlags } from '@opentelemetry/api'; +import { suppressTracing } from '@opentelemetry/core'; +import { + getActiveSpan, + getCapturedScopesOnSpan, + getRootSpan, + spanToJSON, + SPAN_STATUS_ERROR, + startSpanManual, + type Span, + withIsolationScope, +} from '@sentry/core'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { SentryAsyncLocalStorageContextManager } from '../src/asyncLocalStorageContextManager'; +import { setOpenTelemetryContextAsyncContextStrategy } from '../src/asyncContextStrategy'; +import { applyOtelSpanData, SentryTraceProvider } from '../src/sentryTraceProvider'; +import { cleanupOtel } from './helpers/mockSdkInit'; +import { init as initTestClient } from './helpers/TestClient'; + +describe('SentryTraceProvider', () => { + beforeEach(() => { + (global as { __SENTRY__?: unknown }).__SENTRY__ = {}; + setOpenTelemetryContextAsyncContextStrategy(); + initTestClient({ tracesSampleRate: 1 }); + context.setGlobalContextManager(new SentryAsyncLocalStorageContextManager()); + trace.setGlobalTracerProvider(new SentryTraceProvider()); + }); + + afterEach(async () => { + await cleanupOtel(); + }); + + it('creates Sentry spans from the global OpenTelemetry tracer', () => { + const span = trace.getTracer('test').startSpan('SELECT users', { + attributes: { + 'db.system.name': 'postgresql', + 'db.statement': 'SELECT * FROM users', + }, + }); + + expect(spanToJSON(span as Span)).toEqual({ + data: { + 'sentry.origin': 'manual', + 'sentry.op': 'db', + 'sentry.sample_rate': 1, + 'sentry.source': 'task', + 'db.system.name': 'postgresql', + 'db.statement': 'SELECT * FROM users', + }, + description: 'SELECT * FROM users', + op: 'db', + origin: 'manual', + parent_span_id: undefined, + span_id: span.spanContext().spanId, + start_timestamp: expect.any(Number), + status: undefined, + timestamp: undefined, + trace_id: span.spanContext().traceId, + profile_id: undefined, + exclusive_time: undefined, + measurements: undefined, + is_segment: undefined, + segment_id: undefined, + links: undefined, + }); + }); + + it('parents inactive spans to the active OpenTelemetry span', () => { + trace.getTracer('test').startActiveSpan('parent', parent => { + const child = trace.getTracer('test').startSpan('child'); + + expect(spanToJSON(child as Span).parent_span_id).toBe(parent.spanContext().spanId); + }); + }); + + it('links non-recording spans to a suppressed active parent', () => { + trace.getTracer('test').startActiveSpan('parent', parent => { + const suppressedContext = suppressTracing(context.active()); + const child = trace.getTracer('test').startSpan('child', {}, suppressedContext); + + expect(child.isRecording()).toBe(false); + expect(spanToJSON(child as Span).trace_id).toBe(parent.spanContext().traceId); + // Non-recording spans no longer carry a `parent_span_id` under the scope-based + // sampling model; the child is instead linked to the parent's span tree. + expect(getRootSpan(child as Span)).toBe(getRootSpan(parent as unknown as Span)); + + parent.end(); + }); + }); + + it('captures scopes on suppressed spans so startActiveSpan can fork the isolation scope', () => { + withIsolationScope(isolationScope => { + const suppressedContext = suppressTracing(context.active()); + const span = trace.getTracer('test').startSpan('child', {}, suppressedContext); + + // Without captured scopes, startActiveSpan cannot fork the isolation scope onto the context. + expect(getCapturedScopesOnSpan(span as unknown as Span).isolationScope).toBe(isolationScope); + }); + }); + + it('sets active OpenTelemetry spans on the Sentry scope', () => { + trace.getTracer('test').startActiveSpan('parent', parent => { + expect(getActiveSpan()).toBe(parent); + }); + }); + + it('syncs manual OpenTelemetry context switches onto the Sentry scope', () => { + const tracer = trace.getTracer('test'); + + tracer.startActiveSpan('parent', parent => { + const child = tracer.startSpan('child'); + const childContext = trace.setSpan(context.active(), child); + + context.with(childContext, () => { + expect(getActiveSpan()).toBe(child); + }); + + expect(getActiveSpan()).toBe(parent); + + child.end(); + parent.end(); + }); + }); + + it('parents core spans to the active OpenTelemetry span', () => { + trace.getTracer('test').startActiveSpan('parent', parent => { + startSpanManual({ name: 'child' }, child => { + expect(spanToJSON(child).parent_span_id).toBe(parent.spanContext().spanId); + child.end(); + }); + }); + }); + + it('continues remote OpenTelemetry span contexts as root Sentry spans', () => { + const remoteContext = trace.setSpanContext(context.active(), { + traceId: '12312012123120121231201212312012', + spanId: '1121201211212012', + isRemote: true, + traceFlags: TraceFlags.SAMPLED, + }); + + const span = trace.getTracer('test').startSpan('server', { kind: SpanKind.SERVER }, remoteContext); + const json = spanToJSON(span as Span); + + expect(json.trace_id).toBe('12312012123120121231201212312012'); + expect(json.parent_span_id).toBe('1121201211212012'); + expect(json.data?.['otel.kind']).toBe('SERVER'); + }); + + it('finalizes span statuses like the OpenTelemetry exporter', () => { + const okSpan = trace.getTracer('test').startSpan('ok'); + applyOtelSpanData(okSpan as Span, { finalizeStatus: true }); + expect(spanToJSON(okSpan as Span).status).toBe('ok'); + + const httpErrorSpan = trace.getTracer('test').startSpan('http-error'); + httpErrorSpan.setAttribute('http.response.status_code', 500); + applyOtelSpanData(httpErrorSpan as Span, { finalizeStatus: true }); + expect(spanToJSON(httpErrorSpan as Span).status).toBe('internal_error'); + + const legacyHttpErrorSpan = trace.getTracer('test').startSpan('legacy-http-error'); + legacyHttpErrorSpan.setAttribute('http.status_code', 500); + applyOtelSpanData(legacyHttpErrorSpan as Span, { finalizeStatus: true }); + expect(spanToJSON(legacyHttpErrorSpan as Span).status).toBe('internal_error'); + expect(spanToJSON(legacyHttpErrorSpan as Span).data).toMatchObject({ + 'http.response.status_code': 500, + 'http.status_code': 500, + }); + + const customErrorSpan = trace.getTracer('test').startSpan('custom-error'); + customErrorSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'This is a custom error' }); + applyOtelSpanData(customErrorSpan as Span, { finalizeStatus: true }); + expect(spanToJSON(customErrorSpan as Span).status).toBe('internal_error'); + }); + + it('keeps default custom source on provider-created spans', () => { + const span = trace.getTracer('test').startSpan('custom-source'); + span.setAttribute('sentry.source', 'custom'); + + applyOtelSpanData(span as Span, { finalizeStatus: true }); + + expect(spanToJSON(span as Span).data?.['sentry.source']).toBe('custom'); + }); +}); diff --git a/packages/opentelemetry/test/utils/setupCheck.test.ts b/packages/opentelemetry/test/utils/setupCheck.test.ts index 526945108ba7..498fa0c8a767 100644 --- a/packages/opentelemetry/test/utils/setupCheck.test.ts +++ b/packages/opentelemetry/test/utils/setupCheck.test.ts @@ -2,7 +2,8 @@ import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { SentrySampler } from '../../src/sampler'; import { SentrySpanProcessor } from '../../src/spanProcessor'; -import { openTelemetrySetupCheck } from '../../src/utils/setupCheck'; +import { SentryTraceProvider } from '../../src/sentryTraceProvider'; +import { openTelemetrySetupCheck, setIsSetup } from '../../src/utils/setupCheck'; import { setupOtel } from '../helpers/initOtel'; import { cleanupOtel } from '../helpers/mockSdkInit'; import { getDefaultTestClientOptions, TestClient } from '../helpers/TestClient'; @@ -41,4 +42,20 @@ describe('openTelemetrySetupCheck', () => { const setup = openTelemetrySetupCheck(); expect(setup).toEqual(['SentrySampler', 'SentrySpanProcessor']); }); + + it('does not mark SentryTraceProvider as set up on construction', () => { + // Construction must not mark setup — that only happens once the provider is + // successfully registered as the global tracer provider. Otherwise setup + // validation would skip required checks even when registration failed. + new SentryTraceProvider(); + + expect(openTelemetrySetupCheck()).toEqual([]); + }); + + it('returns SentryTraceProvider setup once it is marked as set up', () => { + setIsSetup('SentryTraceProvider'); + + const setup = openTelemetrySetupCheck(); + expect(setup).toEqual(['SentryTraceProvider']); + }); }); diff --git a/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts b/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts index 19c8e178c160..9cda157d0e34 100644 --- a/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts +++ b/packages/opentelemetry/test/utils/setupEventContextTrace.test.ts @@ -1,6 +1,7 @@ import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; import { captureException, setCurrentClient } from '@sentry/core'; import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { setOpenTelemetryContextAsyncContextStrategy } from '../../src/asyncContextStrategy'; import { setupEventContextTrace } from '../../src/setupEventContextTrace'; import { setupOtel } from '../helpers/initOtel'; import { cleanupOtel } from '../helpers/mockSdkInit'; @@ -29,6 +30,7 @@ describe('setupEventContextTrace', () => { client.init(); setupEventContextTrace(client); + setOpenTelemetryContextAsyncContextStrategy(); [provider] = setupOtel(client); });