diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 0e5906f92908..c8f9e5c51faa 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -68,6 +68,7 @@ "access": "public" }, "dependencies": { + "@opentelemetry/api": "^1.9.0", "@opentelemetry/instrumentation-http": "0.53.0", "@opentelemetry/semantic-conventions": "^1.27.0", "@rollup/plugin-commonjs": "26.0.1", diff --git a/packages/nextjs/src/edge/index.ts b/packages/nextjs/src/edge/index.ts index adcee834e0d9..cf0e571e67cb 100644 --- a/packages/nextjs/src/edge/index.ts +++ b/packages/nextjs/src/edge/index.ts @@ -1,8 +1,19 @@ -import { applySdkMetadata, registerSpanErrorInstrumentation } from '@sentry/core'; +import { context } from '@opentelemetry/api'; +import { + applySdkMetadata, + getCapturedScopesOnSpan, + getCurrentScope, + getIsolationScope, + getRootSpan, + registerSpanErrorInstrumentation, + setCapturedScopesOnSpan, +} from '@sentry/core'; + import { GLOBAL_OBJ } from '@sentry/utils'; import type { VercelEdgeOptions } from '@sentry/vercel-edge'; import { getDefaultIntegrations, init as vercelEdgeInit } from '@sentry/vercel-edge'; +import { getScopesFromContext } from '@sentry/opentelemetry'; import { isBuild } from '../common/utils/isBuild'; import { distDirRewriteFramesIntegration } from './distDirRewriteFramesIntegration'; @@ -39,7 +50,24 @@ export function init(options: VercelEdgeOptions = {}): void { applySdkMetadata(opts, 'nextjs'); - vercelEdgeInit(opts); + const client = vercelEdgeInit(opts); + + // Create/fork an isolation whenever we create root spans. This is ok because in Next.js we only create root spans on the edge for incoming requests. + client?.on('spanStart', span => { + if (span === getRootSpan(span)) { + const scopes = getCapturedScopesOnSpan(span); + + const isolationScope = (scopes.isolationScope || getIsolationScope()).clone(); + const scope = scopes.scope || getCurrentScope(); + + const currentScopesPointer = getScopesFromContext(context.active()); + if (currentScopesPointer) { + currentScopesPointer.isolationScope = isolationScope; + } + + setCapturedScopesOnSpan(span, scope, isolationScope); + } + }); } /**