From c78906d505197a0ba7a6469f2a0cea6a582e25d1 Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Fri, 23 Oct 2026 10:07:24 +0200 Subject: [PATCH 1/3] fix(deps): Allow `@opentelemetry/api` 1.9 again Co-Authored-By: Claude Opus 5.5 --- packages/cloudflare/package.json | 2 +- packages/deno/package.json | 2 +- packages/hono/package.json | 2 +- packages/nextjs/package.json | 2 +- packages/node/package.json | 2 +- packages/opentelemetry/package.json | 2 +- packages/react-router/package.json | 2 +- packages/server-utils/package.json | 2 +- packages/sveltekit/package.json | 2 +- packages/tanstackstart-react/package.json | 2 +- packages/vercel-edge/package.json | 2 +- pnpm-lock.yaml | 22 +++++++++++----------- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index 23534c205b03..f6ee446a3e36 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -52,7 +52,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.8.0", "@sentry/opentelemetry": "11.8.0", diff --git a/packages/deno/package.json b/packages/deno/package.json index 871eb5cffe9a..c500d297f8a7 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -27,7 +27,7 @@ "/build" ], "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.8.0", "@sentry/server-runtime-injection": "11.8.0", diff --git a/packages/hono/package.json b/packages/hono/package.json index bfe3c2f150dd..f04b15b5c5f8 100644 --- a/packages/hono/package.json +++ b/packages/hono/package.json @@ -72,7 +72,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/core": "11.8.0", "@sentry/conventions": "^0.27.0", "@sentry/server-utils": "11.8.0" diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index a28187f94076..8f322cd9290b 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -82,7 +82,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@rollup/plugin-commonjs": "28.0.1", "@sentry/browser-utils": "11.8.0", "@sentry/bundler-plugins": "11.8.0", diff --git a/packages/node/package.json b/packages/node/package.json index 66820c04a670..854c6667a2e0 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -77,7 +77,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.8.0", "@sentry/opentelemetry": "11.8.0", diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json index b9c0e6e4e2cc..b2995fe8173e 100644 --- a/packages/opentelemetry/package.json +++ b/packages/opentelemetry/package.json @@ -34,7 +34,7 @@ "@opentelemetry/api": "^1.9.0" }, "devDependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry-internal/rollup-utils": "11.8.0" }, "scripts": { diff --git a/packages/react-router/package.json b/packages/react-router/package.json index f1d0304eea03..e4169d0fc812 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -55,7 +55,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/browser": "11.8.0", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.8.0", diff --git a/packages/server-utils/package.json b/packages/server-utils/package.json index 1ab0c2b80b41..3466cba33b39 100644 --- a/packages/server-utils/package.json +++ b/packages/server-utils/package.json @@ -96,7 +96,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.8.0" }, diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index 4cd737e752bd..70ae37d65d36 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -70,7 +70,7 @@ } }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/cloudflare": "11.8.0", "@sentry/core": "11.8.0", "@sentry/conventions": "^0.27.0", diff --git a/packages/tanstackstart-react/package.json b/packages/tanstackstart-react/package.json index 67facf555cc5..1543b2cc293a 100644 --- a/packages/tanstackstart-react/package.json +++ b/packages/tanstackstart-react/package.json @@ -51,7 +51,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/browser-utils": "11.8.0", "@sentry/conventions": "^0.27.0", "@sentry/core": "11.8.0", diff --git a/packages/vercel-edge/package.json b/packages/vercel-edge/package.json index 01bac2e99907..26c91099670f 100644 --- a/packages/vercel-edge/package.json +++ b/packages/vercel-edge/package.json @@ -32,7 +32,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.10.0", + "@opentelemetry/api": "^1.9.1", "@sentry/core": "11.8.0", "@sentry/server-utils": "11.8.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff5278597ebd..73f114221f2d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1221,7 +1221,7 @@ importers: packages/cloudflare: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/conventions': specifier: ^0.27.0 @@ -1274,7 +1274,7 @@ importers: packages/deno: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/conventions': specifier: ^0.27.0 @@ -1538,7 +1538,7 @@ importers: packages/hono: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/conventions': specifier: ^0.27.0 @@ -1622,7 +1622,7 @@ importers: packages/nextjs: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@rollup/plugin-commonjs': specifier: 28.0.1 @@ -1723,7 +1723,7 @@ importers: packages/node: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/bundler-plugins': specifier: 11.8.0 @@ -1853,7 +1853,7 @@ importers: version: link:../core devDependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry-internal/rollup-utils': specifier: 11.8.0 @@ -1951,7 +1951,7 @@ importers: packages/react-router: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/browser': specifier: 11.8.0 @@ -2188,7 +2188,7 @@ importers: packages/server-utils: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/conventions': specifier: ^0.27.0 @@ -2363,7 +2363,7 @@ importers: packages/sveltekit: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/bundler-plugins': specifier: 11.8.0 @@ -2427,7 +2427,7 @@ importers: packages/tanstackstart-react: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/browser-utils': specifier: 11.8.0 @@ -2469,7 +2469,7 @@ importers: packages/vercel-edge: dependencies: '@opentelemetry/api': - specifier: ^1.10.0 + specifier: ^1.9.1 version: 1.10.0 '@sentry/core': specifier: 11.8.0 From ee02627f51f3a3b6019b901ad3aa41720bb680df Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Fri, 23 Oct 2026 10:22:06 +0200 Subject: [PATCH 2/3] Pin @opentelemetry/api to 1.9.1 in node-otel-sdk-node E2E app --- .../e2e-tests/test-applications/node-otel-sdk-node/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json index 48bee311d805..ce771de4edba 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json @@ -9,7 +9,7 @@ "test:assert": "playwright test" }, "dependencies": { - "@opentelemetry/api": "^1.9.1", + "@opentelemetry/api": "1.9.1", "@opentelemetry/exporter-trace-otlp-http": "^0.220.0", "@opentelemetry/instrumentation": "^0.220.0", "@opentelemetry/instrumentation-http": "^0.220.0", From 6b4b0e68047eed75069f5bb5a45035f2fc985c6c Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Fri, 23 Oct 2026 13:01:35 +0200 Subject: [PATCH 3/3] test(e2e): Run OTel SDK E2E apps on SDK v3 with an SDK v2 variant Co-Authored-By: Claude Opus 5.5 --- .../nextjs-otlp/otel-tracer-provider.ts | 22 ++++++ .../otel-v2/otel-tracer-provider.ts | 11 +++ .../nextjs-otlp/otel.server.config.ts | 14 +--- .../nextjs-otlp/package.json | 17 +++-- .../nextjs-otlp/tsconfig.json | 2 +- .../otel-v2/tracer-provider.ts | 9 +++ .../node-express-otlp/package.json | 19 ++++- .../node-express-otlp/src/app.ts | 22 ++---- .../node-express-otlp/src/tracer-provider.ts | 20 +++++ .../node-otel-sdk-node-v3/package.json | 28 ------- .../playwright.config.mjs | 34 --------- .../node-otel-sdk-node-v3/pnpm-workspace.yaml | 3 - .../node-otel-sdk-node-v3/src/app.mjs | 47 ------------ .../start-event-proxy.mjs | 6 -- .../start-otel-proxy.mjs | 6 -- .../tests/errors.test.ts | 31 -------- .../tests/opentelemetry.test.ts | 73 ------------------- .../node-otel-sdk-node/package.json | 27 +++++-- .../src/instrument-otel-v2.mjs} | 7 +- .../node-otel-sdk-node/src/instrument.mjs | 7 +- .../otel-v2/otel-tracer-provider.ts | 11 +++ .../sveltekit-2-otlp/package.json | 21 ++++-- .../src/instrumentation.server.ts | 14 +--- .../src/otel-tracer-provider.ts | 22 ++++++ 24 files changed, 180 insertions(+), 293 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-tracer-provider.ts create mode 100644 dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-v2/otel-tracer-provider.ts create mode 100644 dev-packages/e2e-tests/test-applications/node-express-otlp/otel-v2/tracer-provider.ts create mode 100644 dev-packages/e2e-tests/test-applications/node-express-otlp/src/tracer-provider.ts delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/package.json delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/playwright.config.mjs delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/pnpm-workspace.yaml delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/src/app.mjs delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-event-proxy.mjs delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-otel-proxy.mjs delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/errors.test.ts delete mode 100644 dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/opentelemetry.test.ts rename dev-packages/e2e-tests/test-applications/{node-otel-sdk-node-v3/src/instrument.mjs => node-otel-sdk-node/src/instrument-otel-v2.mjs} (86%) create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/otel-v2/otel-tracer-provider.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/otel-tracer-provider.ts diff --git a/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-tracer-provider.ts b/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-tracer-provider.ts new file mode 100644 index 000000000000..dd56ed7a742a --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-tracer-provider.ts @@ -0,0 +1,22 @@ +import { context, propagation, trace } from '@opentelemetry/api'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; +import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core'; +import type { Resource } from '@opentelemetry/resources'; +import type { SpanExporter } from '@opentelemetry/sdk-trace'; +import { BatchSpanProcessor, TracerProvider } from '@opentelemetry/sdk-trace'; + +// OpenTelemetry SDK v3 has no `NodeTracerProvider.register()`, so the app registers the tracer +// provider, context manager and propagator itself. The OTel SDK v2 variant replaces this file with +// `otel-v2/otel-tracer-provider.ts`. +export function registerTracerProvider(exporter: SpanExporter, resource: Resource): void { + trace.setGlobalTracerProvider( + new TracerProvider({ + resource, + spanProcessors: [new BatchSpanProcessor({ exporter, scheduledDelayMillis: 100 })], + }), + ); + context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable()); + propagation.setGlobalPropagator( + new CompositePropagator({ propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()] }), + ); +} diff --git a/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-v2/otel-tracer-provider.ts b/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-v2/otel-tracer-provider.ts new file mode 100644 index 000000000000..3af449a59158 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel-v2/otel-tracer-provider.ts @@ -0,0 +1,11 @@ +import type { Resource } from '@opentelemetry/resources'; +import type { SpanExporter } from '@opentelemetry/sdk-trace-base'; +import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; + +export function registerTracerProvider(exporter: SpanExporter, resource: Resource): void { + new NodeTracerProvider({ + resource, + spanProcessors: [new BatchSpanProcessor(exporter, { scheduledDelayMillis: 100 })], + }).register(); +} diff --git a/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel.server.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel.server.config.ts index 0ee1bc170f31..33d2bef4f832 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-otlp/otel.server.config.ts @@ -1,9 +1,8 @@ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { resourceFromAttributes } from '@opentelemetry/resources'; -import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; -import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import { getOtlpTracesEndpoint } from '@sentry/nextjs'; import { OTLP_RECEIVER_PORT, startOtlpReceiver } from './otel-receiver'; +import { registerTracerProvider } from './otel-tracer-provider'; // Next.js can run `register()` more than once in dev, which would leave a second receiver fighting // for the port and a second set of providers losing the race to register globally. @@ -27,13 +26,8 @@ if (!globalWithOtelFlag.__otelRegistered) { // The app owns tracing: this registers the global tracer provider, context manager and // propagator. Sentry is initialized afterwards with `enableOpenTelemetrySetup: false` so it does // not contend for any of them. - new NodeTracerProvider({ + registerTracerProvider( + new OTLPTraceExporter({ url: `${otlpBaseUrl}/v1/traces`, headers: otlpTracesEndpoint.headers }), resource, - spanProcessors: [ - new BatchSpanProcessor( - new OTLPTraceExporter({ url: `${otlpBaseUrl}/v1/traces`, headers: otlpTracesEndpoint.headers }), - { scheduledDelayMillis: 100 }, - ), - ], - }).register(); + ); } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-otlp/package.json b/dev-packages/e2e-tests/test-applications/nextjs-otlp/package.json index 4bc498a3e49d..838283e06f41 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-otlp/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-otlp/package.json @@ -14,16 +14,18 @@ "test:dev": "TEST_ENV=development playwright test", "test:dev-webpack": "TEST_ENV=development-webpack playwright test", "test:build": "pnpm install && pnpm build", + "test:build:otel-v2": "pnpm remove @opentelemetry/context-async-hooks @opentelemetry/core @opentelemetry/sdk-trace && pnpm add @opentelemetry/api@1.9.1 @opentelemetry/exporter-trace-otlp-http@^0.220.0 @opentelemetry/resources@^2.9.0 @opentelemetry/sdk-trace-base@^2.9.0 @opentelemetry/sdk-trace-node@^2.9.0 && pnpm dedupe && cp otel-v2/otel-tracer-provider.ts otel-tracer-provider.ts && pnpm build", "test:build-webpack": "pnpm install && pnpm build-webpack", "test:assert": "pnpm test:prod && pnpm test:dev", "test:assert-webpack": "pnpm test:prod && pnpm test:dev-webpack" }, "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/exporter-trace-otlp-http": "^0.220.0", - "@opentelemetry/resources": "^2.9.0", - "@opentelemetry/sdk-trace-base": "^2.9.0", - "@opentelemetry/sdk-trace-node": "^2.9.0", + "@opentelemetry/api": "^1.10.0", + "@opentelemetry/context-async-hooks": "^3.0.0", + "@opentelemetry/core": "^3.0.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.300.0", + "@opentelemetry/resources": "^3.0.0", + "@opentelemetry/sdk-trace": "^3.0.0", "@sentry/core": "file:../../packed/sentry-core-packed.tgz", "@sentry/nextjs": "file:../../packed/sentry-nextjs-packed.tgz", "import-in-the-middle": "^2", @@ -51,6 +53,11 @@ "build-command": "pnpm test:build-webpack", "label": "nextjs-otlp (webpack)", "assert-command": "pnpm test:assert-webpack" + }, + { + "build-command": "pnpm test:build:otel-v2", + "assert-command": "pnpm test:assert", + "label": "nextjs-otlp (OTel SDK v2)" } ] } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-otlp/tsconfig.json b/dev-packages/e2e-tests/test-applications/nextjs-otlp/tsconfig.json index cc9ed39b5aa2..f1fb9c3599e1 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-otlp/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-otlp/tsconfig.json @@ -23,5 +23,5 @@ } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts", "**/*.mts"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "otel-v2"] } diff --git a/dev-packages/e2e-tests/test-applications/node-express-otlp/otel-v2/tracer-provider.ts b/dev-packages/e2e-tests/test-applications/node-express-otlp/otel-v2/tracer-provider.ts new file mode 100644 index 000000000000..d87aab506191 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/node-express-otlp/otel-v2/tracer-provider.ts @@ -0,0 +1,9 @@ +import type { SpanExporter } from '@opentelemetry/sdk-trace-base'; +import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; + +export function registerTracerProvider(exporter: SpanExporter): void { + new NodeTracerProvider({ + spanProcessors: [new BatchSpanProcessor(exporter, { scheduledDelayMillis: 100 })], + }).register(); +} diff --git a/dev-packages/e2e-tests/test-applications/node-express-otlp/package.json b/dev-packages/e2e-tests/test-applications/node-express-otlp/package.json index a63e7392a49d..2cfe8952ed6d 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-otlp/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-otlp/package.json @@ -8,13 +8,15 @@ "test": "playwright test", "clean": "npx rimraf node_modules pnpm-lock.yaml", "test:build": "pnpm install && pnpm build", + "test:build:otel-v2": "pnpm remove @opentelemetry/context-async-hooks @opentelemetry/core @opentelemetry/sdk-trace && pnpm add @opentelemetry/api@1.9.1 @opentelemetry/exporter-trace-otlp-http@^0.220.0 @opentelemetry/sdk-trace-base@^2.9.0 @opentelemetry/sdk-trace-node@^2.9.0 && pnpm dedupe && cp otel-v2/tracer-provider.ts src/tracer-provider.ts && pnpm build", "test:assert": "pnpm test" }, "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/exporter-trace-otlp-http": "^0.220.0", - "@opentelemetry/sdk-trace-base": "^2.9.0", - "@opentelemetry/sdk-trace-node": "^2.9.0", + "@opentelemetry/api": "^1.10.0", + "@opentelemetry/context-async-hooks": "^3.0.0", + "@opentelemetry/core": "^3.0.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.300.0", + "@opentelemetry/sdk-trace": "^3.0.0", "@sentry/node": "file:../../packed/sentry-node-packed.tgz", "@types/express": "^4.17.21", "@types/node": "^18.19.1", @@ -27,5 +29,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "pnpm test:build:otel-v2", + "assert-command": "pnpm test:assert", + "label": "node-express-otlp (OTel SDK v2)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-express-otlp/src/app.ts b/dev-packages/e2e-tests/test-applications/node-express-otlp/src/app.ts index c6246a18f3a9..e6cb40ad2639 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-otlp/src/app.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-otlp/src/app.ts @@ -1,9 +1,8 @@ import { trace } from '@opentelemetry/api'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; -import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; -import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import * as Sentry from '@sentry/node'; import express from 'express'; +import { registerTracerProvider } from './tracer-provider'; const dsn = process.env.E2E_TEST_DSN as string; const appPort = 3030; @@ -17,19 +16,12 @@ if (!otlpTracesEndpoint) { // The user brings their own OpenTelemetry setup. In production `url` would be // `otlpTracesEndpoint.url`; here it points at the local receiver below so the test can assert what // was actually exported. The auth headers are the real DSN-derived ones either way. -const provider = new NodeTracerProvider({ - spanProcessors: [ - new BatchSpanProcessor( - new OTLPTraceExporter({ - url: `http://localhost:${otlpReceiverPort}/v1/traces`, - headers: otlpTracesEndpoint.headers, - }), - { scheduledDelayMillis: 100 }, - ), - ], -}); - -provider.register(); +registerTracerProvider( + new OTLPTraceExporter({ + url: `http://localhost:${otlpReceiverPort}/v1/traces`, + headers: otlpTracesEndpoint.headers, + }), +); Sentry.init({ dsn, diff --git a/dev-packages/e2e-tests/test-applications/node-express-otlp/src/tracer-provider.ts b/dev-packages/e2e-tests/test-applications/node-express-otlp/src/tracer-provider.ts new file mode 100644 index 000000000000..ec591e7e4c14 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/node-express-otlp/src/tracer-provider.ts @@ -0,0 +1,20 @@ +import { context, propagation, trace } from '@opentelemetry/api'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; +import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core'; +import type { SpanExporter } from '@opentelemetry/sdk-trace'; +import { BatchSpanProcessor, TracerProvider } from '@opentelemetry/sdk-trace'; + +// OpenTelemetry SDK v3 has no `NodeTracerProvider.register()`, so the app registers the tracer +// provider, context manager and propagator itself. The OTel SDK v2 variant replaces this file with +// `otel-v2/tracer-provider.ts`. +export function registerTracerProvider(exporter: SpanExporter): void { + trace.setGlobalTracerProvider( + new TracerProvider({ + spanProcessors: [new BatchSpanProcessor({ exporter, scheduledDelayMillis: 100 })], + }), + ); + context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable()); + propagation.setGlobalPropagator( + new CompositePropagator({ propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()] }), + ); +} diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/package.json b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/package.json deleted file mode 100644 index 264efe90d301..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "node-otel-sdk-node-v3", - "version": "1.0.0", - "private": true, - "scripts": { - "start": "node --import ./src/instrument.mjs src/app.mjs", - "clean": "npx rimraf node_modules pnpm-lock.yaml", - "test:build": "pnpm install", - "test:assert": "playwright test" - }, - "dependencies": { - "@opentelemetry/api": "^1.10.0", - "@opentelemetry/exporter-trace-otlp-http": "^0.300.0", - "@opentelemetry/instrumentation": "^0.300.0", - "@opentelemetry/instrumentation-http": "^0.300.0", - "@opentelemetry/sdk-node": "^0.300.0", - "@opentelemetry/sdk-trace": "^3.0.0", - "@sentry/node": "file:../../packed/sentry-node-packed.tgz", - "express": "^4.21.2" - }, - "devDependencies": { - "@playwright/test": "1.64.1", - "@sentry-internal/test-utils": "file:../../packed/sentry-internal-test-utils-packed.tgz" - }, - "volta": { - "extends": "../../package.json" - } -} diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/playwright.config.mjs b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/playwright.config.mjs deleted file mode 100644 index 888e61cfb2dc..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/playwright.config.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import { getPlaywrightConfig } from '@sentry-internal/test-utils'; - -const config = getPlaywrightConfig( - { - startCommand: `pnpm start`, - }, - { - webServer: [ - { - command: `node ./start-event-proxy.mjs`, - port: 3031, - stdout: 'pipe', - stderr: 'pipe', - }, - { - command: `node ./start-otel-proxy.mjs`, - port: 3032, - stdout: 'pipe', - stderr: 'pipe', - }, - { - command: 'pnpm start', - port: 3030, - stdout: 'pipe', - stderr: 'pipe', - env: { - PORT: 3030, - }, - }, - ], - }, -); - -export default config; diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/pnpm-workspace.yaml b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/pnpm-workspace.yaml deleted file mode 100644 index 428f42f5ee7b..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/pnpm-workspace.yaml +++ /dev/null @@ -1,3 +0,0 @@ -allowBuilds: - protobufjs: false -minimumReleaseAge: 0 diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/src/app.mjs b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/src/app.mjs deleted file mode 100644 index ee441975d47c..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/src/app.mjs +++ /dev/null @@ -1,47 +0,0 @@ -import { trace } from '@opentelemetry/api'; -import * as Sentry from '@sentry/node'; -import express from 'express'; -import http from 'node:http'; - -const app = express(); -const port = 3030; -const tracer = trace.getTracer('node-otel-sdk-node-v3'); - -app.get('/test-telemetry/:id', function (req, res) { - tracer.startActiveSpan('telemetry-handler', span => { - const { traceId, spanId } = span.spanContext(); - - Sentry.captureException(new Error(`This is an exception with id ${req.params.id}`)); - - span.end(); - - res.json({ traceId, spanId }); - }); -}); - -app.get('/test-exception/:id', function (req, _res) { - throw new Error(`This is an exception with id ${req.params.id}`); -}); - -app.get('/test-outgoing', function (_req, res) { - http.get(`http://localhost:${port}/echo-headers`, response => { - let body = ''; - response.on('data', chunk => (body += chunk)); - response.on('end', () => res.type('json').send(body)); - }); -}); - -app.get('/echo-headers', function (req, res) { - res.send(req.headers); -}); - -// Answers with the OpenTelemetry span the request ran under, so the test can check what the error -// captured by Sentry was linked to. -app.use(function onError(_err, _req, res, _next) { - const spanContext = trace.getActiveSpan()?.spanContext(); - res.status(500).json({ traceId: spanContext?.traceId, spanId: spanContext?.spanId }); -}); - -app.listen(port, () => { - console.log(`Example app listening on port ${port}`); -}); diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-event-proxy.mjs b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-event-proxy.mjs deleted file mode 100644 index 52bbf5464e17..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-event-proxy.mjs +++ /dev/null @@ -1,6 +0,0 @@ -import { startEventProxyServer } from '@sentry-internal/test-utils'; - -startEventProxyServer({ - port: 3031, - proxyServerName: 'node-otel-sdk-node-v3', -}); diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-otel-proxy.mjs b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-otel-proxy.mjs deleted file mode 100644 index 0a3a31f582b2..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/start-otel-proxy.mjs +++ /dev/null @@ -1,6 +0,0 @@ -import { startProxyServer } from '@sentry-internal/test-utils'; - -startProxyServer({ - port: 3032, - proxyServerName: 'node-otel-sdk-node-v3-otel', -}); diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/errors.test.ts deleted file mode 100644 index 603e9c053aaa..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/errors.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { expect, test } from '@playwright/test'; -import { waitForError } from '@sentry-internal/test-utils'; - -test('links errors to the active OpenTelemetry span', async ({ baseURL }) => { - const errorEventPromise = waitForError('node-otel-sdk-node-v3', errorEvent => { - return errorEvent.exception?.values?.[0]?.value === 'This is an exception with id 123'; - }); - - const response = await fetch(`${baseURL}/test-telemetry/123`); - const { traceId, spanId } = (await response.json()) as { traceId: string; spanId: string }; - - const errorEvent = await errorEventPromise; - - expect(errorEvent.contexts?.trace).toEqual({ trace_id: traceId, span_id: spanId }); -}); - -test('links errors from the Sentry instrumentation to the active OpenTelemetry span', async ({ baseURL }) => { - const errorEventPromise = waitForError('node-otel-sdk-node-v3', errorEvent => { - return errorEvent.exception?.values?.[0]?.value === 'This is an exception with id 456'; - }); - - const response = await fetch(`${baseURL}/test-exception/456`); - const { traceId, spanId } = (await response.json()) as { traceId: string; spanId: string }; - - const errorEvent = await errorEventPromise; - - // With tracing off, Sentry's channel instrumentation still runs and reports the errors express - // never handles. - expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({ type: 'auto.http.express', handled: false }); - expect(errorEvent.contexts?.trace).toEqual({ trace_id: traceId, span_id: spanId }); -}); diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/opentelemetry.test.ts b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/opentelemetry.test.ts deleted file mode 100644 index cbeffac8b286..000000000000 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/tests/opentelemetry.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { expect, test } from '@playwright/test'; -import { waitForError, waitForPlainRequest, waitForTransaction } from '@sentry-internal/test-utils'; - -interface OtlpSpan { - name: string; - traceId: string; -} - -/** - * The proxy hands back the payloads it received as newline separated JSON, so a single read can - * hold more than one OTLP export. - */ -function getExportedSpans(data: string): OtlpSpan[] { - return data - .split('\n') - .filter(Boolean) - .flatMap( - line => (JSON.parse(line) as { resourceSpans?: { scopeSpans?: { spans?: OtlpSpan[] }[] }[] }).resourceSpans ?? [], - ) - .flatMap(resourceSpan => resourceSpan.scopeSpans ?? []) - .flatMap(scopeSpan => scopeSpan.spans ?? []); -} - -test('exports the spans of the user OpenTelemetry setup to their own collector', async ({ baseURL }) => { - let traceId: string | undefined; - - // Every test in this app exports into the same proxy, and the http span only ends once the - // response is out, so wait for this request's own trace to be complete. Waiting on the span names - // alone matches a batch that another test filled, whose spans are on a different trace. - const otelExportPromise = waitForPlainRequest('node-otel-sdk-node-v3-otel', data => { - const names = getExportedSpans(data) - .filter(span => span.traceId === traceId) - .map(span => span.name); - return names.includes('telemetry-handler') && names.includes('GET'); - }); - - const response = await fetch(`${baseURL}/test-telemetry/234`); - ({ traceId } = (await response.json()) as { traceId: string }); - - const exportedSpans = getExportedSpans(await otelExportPromise).filter(span => span.traceId === traceId); - - // The user's own http instrumentation keeps working and stays on the same trace as their spans. - expect(exportedSpans.map(span => span.name)).toEqual(expect.arrayContaining(['telemetry-handler', 'GET'])); -}); - -test('sends no spans to Sentry', async ({ baseURL }) => { - const transactionPromise = waitForTransaction('node-otel-sdk-node-v3', () => true); - const errorPromise = waitForError('node-otel-sdk-node-v3', errorEvent => { - return errorEvent.exception?.values?.[0]?.value === 'This is an exception with id 345'; - }); - - await fetch(`${baseURL}/test-telemetry/345`); - // Proves the request's telemetry reached the proxy, so the absence check below is not vacuous. - await errorPromise; - - // Absence can only be time bounded. This guards against Sentry's own instrumentation emitting - // spans again, which would produce a transaction for every request, well inside this window. - const transaction = await Promise.race([ - transactionPromise, - new Promise(resolve => setTimeout(() => resolve(undefined), 3000)), - ]); - - expect(transaction).toBeUndefined(); -}); - -test('leaves outgoing trace propagation to the user propagator', async ({ baseURL }) => { - const response = await fetch(`${baseURL}/test-outgoing`); - const headers = (await response.json()) as Record; - - expect(headers['traceparent']).toMatch(/^00-[a-f0-9]{32}-[a-f0-9]{16}-\d{2}$/); - expect(headers['sentry-trace']).toBeUndefined(); - expect(headers['baggage']).toBeUndefined(); -}); diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json index ce771de4edba..aaf516193155 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json @@ -3,18 +3,20 @@ "version": "1.0.0", "private": true, "scripts": { - "start": "node --import ./src/instrument.mjs src/app.mjs", + "start": "node --import ./src/${INSTRUMENT_FILE:-instrument.mjs} src/app.mjs", "clean": "npx rimraf node_modules pnpm-lock.yaml", "test:build": "pnpm install", - "test:assert": "playwright test" + "test:build:otel-v2": "pnpm install && pnpm add @opentelemetry/api@1.9.1 @opentelemetry/exporter-trace-otlp-http@^0.220.0 @opentelemetry/instrumentation@^0.220.0 @opentelemetry/instrumentation-http@^0.220.0 @opentelemetry/sdk-node@^0.220.0 @opentelemetry/sdk-trace-base@^2.9.0 && pnpm dedupe", + "test:assert": "playwright test", + "test:assert:otel-v2": "INSTRUMENT_FILE=instrument-otel-v2.mjs playwright test" }, "dependencies": { - "@opentelemetry/api": "1.9.1", - "@opentelemetry/exporter-trace-otlp-http": "^0.220.0", - "@opentelemetry/instrumentation": "^0.220.0", - "@opentelemetry/instrumentation-http": "^0.220.0", - "@opentelemetry/sdk-node": "^0.220.0", - "@opentelemetry/sdk-trace-base": "^2.9.0", + "@opentelemetry/api": "^1.10.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.300.0", + "@opentelemetry/instrumentation": "^0.300.0", + "@opentelemetry/instrumentation-http": "^0.300.0", + "@opentelemetry/sdk-node": "^0.300.0", + "@opentelemetry/sdk-trace": "^3.0.0", "@sentry/node": "file:../../packed/sentry-node-packed.tgz", "express": "^4.21.2" }, @@ -24,5 +26,14 @@ }, "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "pnpm test:build:otel-v2", + "assert-command": "pnpm test:assert:otel-v2", + "label": "node-otel-sdk-node (OTel SDK v2)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/src/instrument.mjs b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/src/instrument-otel-v2.mjs similarity index 86% rename from dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/src/instrument.mjs rename to dev-packages/e2e-tests/test-applications/node-otel-sdk-node/src/instrument-otel-v2.mjs index c9b910fd3122..25749a79ff21 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node-v3/src/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/src/instrument-otel-v2.mjs @@ -1,7 +1,7 @@ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; import { NodeSDK } from '@opentelemetry/sdk-node'; -import { BatchSpanProcessor } from '@opentelemetry/sdk-trace'; +import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; import * as Sentry from '@sentry/node'; import { register } from 'node:module'; @@ -16,10 +16,7 @@ register('@opentelemetry/instrumentation/hook.mjs', import.meta.url); const sdk = new NodeSDK({ instrumentations: [new HttpInstrumentation()], spanProcessors: [ - new BatchSpanProcessor({ - exporter: new OTLPTraceExporter({ url: 'http://localhost:3032/' }), - scheduledDelayMillis: 100, - }), + new BatchSpanProcessor(new OTLPTraceExporter({ url: 'http://localhost:3032/' }), { scheduledDelayMillis: 100 }), ], }); diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/src/instrument.mjs b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/src/instrument.mjs index 25749a79ff21..c9b910fd3122 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/src/instrument.mjs +++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/src/instrument.mjs @@ -1,7 +1,7 @@ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; import { NodeSDK } from '@opentelemetry/sdk-node'; -import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { BatchSpanProcessor } from '@opentelemetry/sdk-trace'; import * as Sentry from '@sentry/node'; import { register } from 'node:module'; @@ -16,7 +16,10 @@ register('@opentelemetry/instrumentation/hook.mjs', import.meta.url); const sdk = new NodeSDK({ instrumentations: [new HttpInstrumentation()], spanProcessors: [ - new BatchSpanProcessor(new OTLPTraceExporter({ url: 'http://localhost:3032/' }), { scheduledDelayMillis: 100 }), + new BatchSpanProcessor({ + exporter: new OTLPTraceExporter({ url: 'http://localhost:3032/' }), + scheduledDelayMillis: 100, + }), ], }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/otel-v2/otel-tracer-provider.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/otel-v2/otel-tracer-provider.ts new file mode 100644 index 000000000000..3af449a59158 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/otel-v2/otel-tracer-provider.ts @@ -0,0 +1,11 @@ +import type { Resource } from '@opentelemetry/resources'; +import type { SpanExporter } from '@opentelemetry/sdk-trace-base'; +import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; + +export function registerTracerProvider(exporter: SpanExporter, resource: Resource): void { + new NodeTracerProvider({ + resource, + spanProcessors: [new BatchSpanProcessor(exporter, { scheduledDelayMillis: 100 })], + }).register(); +} diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/package.json b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/package.json index d82441f2e072..53df141cc648 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/package.json @@ -12,14 +12,16 @@ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "test:prod": "TEST_ENV=production playwright test", "test:build": "pnpm install && pnpm build", + "test:build:otel-v2": "pnpm remove @opentelemetry/context-async-hooks @opentelemetry/core @opentelemetry/sdk-trace && pnpm add @opentelemetry/api@1.9.1 @opentelemetry/exporter-trace-otlp-http@^0.220.0 @opentelemetry/resources@^2.9.0 @opentelemetry/sdk-trace-base@^2.9.0 @opentelemetry/sdk-trace-node@^2.9.0 && pnpm dedupe && cp otel-v2/otel-tracer-provider.ts src/otel-tracer-provider.ts && pnpm build", "test:assert": "pnpm test:prod" }, "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/exporter-trace-otlp-http": "^0.220.0", - "@opentelemetry/resources": "^2.9.0", - "@opentelemetry/sdk-trace-base": "^2.9.0", - "@opentelemetry/sdk-trace-node": "^2.9.0", + "@opentelemetry/api": "^1.10.0", + "@opentelemetry/context-async-hooks": "^3.0.0", + "@opentelemetry/core": "^3.0.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.300.0", + "@opentelemetry/resources": "^3.0.0", + "@opentelemetry/sdk-trace": "^3.0.0", "@sentry/core": "file:../../packed/sentry-core-packed.tgz", "@sentry/sveltekit": "file:../../packed/sentry-sveltekit-packed.tgz" }, @@ -38,5 +40,14 @@ "type": "module", "volta": { "extends": "../../package.json" + }, + "sentryTest": { + "variants": [ + { + "build-command": "pnpm test:build:otel-v2", + "assert-command": "pnpm test:assert", + "label": "sveltekit-2-otlp (OTel SDK v2)" + } + ] } } diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/instrumentation.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/instrumentation.server.ts index 91406fc9ba24..4e81313c7714 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/instrumentation.server.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/instrumentation.server.ts @@ -1,10 +1,9 @@ import { E2E_TEST_DSN } from '$env/static/private'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { resourceFromAttributes } from '@opentelemetry/resources'; -import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'; -import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import * as Sentry from '@sentry/sveltekit'; import { OTLP_RECEIVER_PORT, startOtlpReceiver } from './otel-receiver'; +import { registerTracerProvider } from './otel-tracer-provider'; startOtlpReceiver(); @@ -21,15 +20,10 @@ if (!otlpTracesEndpoint) { // The app owns tracing: this registers the global tracer provider, context manager and // propagator. Sentry is initialized afterwards with `enableOpenTelemetrySetup: false` so it does // not contend for any of them. -new NodeTracerProvider({ +registerTracerProvider( + new OTLPTraceExporter({ url: `${otlpBaseUrl}/v1/traces`, headers: otlpTracesEndpoint.headers }), resource, - spanProcessors: [ - new BatchSpanProcessor( - new OTLPTraceExporter({ url: `${otlpBaseUrl}/v1/traces`, headers: otlpTracesEndpoint.headers }), - { scheduledDelayMillis: 100 }, - ), - ], -}).register(); +); Sentry.init({ environment: 'qa', diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/otel-tracer-provider.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/otel-tracer-provider.ts new file mode 100644 index 000000000000..dd56ed7a742a --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-otlp/src/otel-tracer-provider.ts @@ -0,0 +1,22 @@ +import { context, propagation, trace } from '@opentelemetry/api'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; +import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core'; +import type { Resource } from '@opentelemetry/resources'; +import type { SpanExporter } from '@opentelemetry/sdk-trace'; +import { BatchSpanProcessor, TracerProvider } from '@opentelemetry/sdk-trace'; + +// OpenTelemetry SDK v3 has no `NodeTracerProvider.register()`, so the app registers the tracer +// provider, context manager and propagator itself. The OTel SDK v2 variant replaces this file with +// `otel-v2/otel-tracer-provider.ts`. +export function registerTracerProvider(exporter: SpanExporter, resource: Resource): void { + trace.setGlobalTracerProvider( + new TracerProvider({ + resource, + spanProcessors: [new BatchSpanProcessor({ exporter, scheduledDelayMillis: 100 })], + }), + ); + context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable()); + propagation.setGlobalPropagator( + new CompositePropagator({ propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()] }), + ); +}