From a88544aea4b5b5c28fd50d7a556a3ea717009182 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 27 Mar 2024 15:15:16 +0000 Subject: [PATCH] feat(nextjs): Fork isolation scopes when incoming HTTP spans are created --- packages/nextjs/package.json | 2 ++ .../requestIsolationScopeIntegration.ts | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 packages/nextjs/src/server/requestIsolationScopeIntegration.ts diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index d72295f973a8..b52972de762b 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -35,12 +35,14 @@ "access": "public" }, "dependencies": { + "@opentelemetry/api": "1.7.0", "@rollup/plugin-commonjs": "24.0.0", "@sentry/core": "8.0.0-alpha.5", "@sentry/node": "8.0.0-alpha.5", "@sentry/react": "8.0.0-alpha.5", "@sentry/types": "8.0.0-alpha.5", "@sentry/utils": "8.0.0-alpha.5", + "@sentry/opentelemetry": "8.0.0-alpha.5", "@sentry/vercel-edge": "8.0.0-alpha.5", "@sentry/webpack-plugin": "2.16.0", "chalk": "3.0.0", diff --git a/packages/nextjs/src/server/requestIsolationScopeIntegration.ts b/packages/nextjs/src/server/requestIsolationScopeIntegration.ts new file mode 100644 index 000000000000..44a118419025 --- /dev/null +++ b/packages/nextjs/src/server/requestIsolationScopeIntegration.ts @@ -0,0 +1,29 @@ +import { SpanKind } from '@opentelemetry/api'; +import { defineIntegration, spanToJSON } from '@sentry/core'; +import { getSpanKind, getSpanScopes } from '@sentry/opentelemetry'; + +/** + * This integration is responsible for creating isolation scopes for incoming Http requests. + * We do so by waiting for http spans to be created and then forking the isolation scope. + * + * Normally the isolation scopes would be created by our Http instrumentation, however Next.js brings it's own Http + * instrumentation so we had to disable ours. + */ +export const requestIsolationScopeIntegration = defineIntegration(() => { + return { + name: 'RequestIsolationScope', + setup(client) { + client.on('spanStart', span => { + const spanJson = spanToJSON(span); + + // The following check is a heuristic to determine whether the started span is a span that tracks an incoming HTTP request + if (getSpanKind(span) === SpanKind.SERVER && spanJson.data && 'http.method' in spanJson.data) { + const scopes = getSpanScopes(span); + if (scopes) { + scopes.isolationScope = scopes.isolationScope.clone(); + } + } + }); + }, + }; +});