From c4c179464dc48ee6eb234f5090cfa77d2ac12b48 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 28 May 2024 12:05:52 +0200 Subject: [PATCH 1/3] feat(sveltekit): Add request data to server-side events --- .../test/errors.server.test.ts | 29 +++++++++++++++++++ .../test/performance.server.test.ts | 10 +++++++ .../sveltekit/test/errors.server.test.ts | 29 +++++++++++++++++++ .../sveltekit/test/performance.server.test.ts | 10 +++++++ packages/sveltekit/src/server/handle.ts | 20 +++++++++++-- 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/errors.server.test.ts index f169b0bf6b68..bbd87a5366a6 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/errors.server.test.ts @@ -20,6 +20,16 @@ test.describe('server-side errors', () => { ); expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); + + expect(errorEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + 'user-agent': expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/universal-load-error', + }); }); test('captures server load error', async ({ page }) => { @@ -40,6 +50,16 @@ test.describe('server-side errors', () => { ); expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); + + expect(errorEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + 'user-agent': expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/server-load-error', + }); }); test('captures server route (GET) error', async ({ page }) => { @@ -61,5 +81,14 @@ test.describe('server-side errors', () => { ); expect(errorEvent.transaction).toEqual('GET /server-route-error'); + + expect(errorEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/server-route-error', + }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/performance.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/performance.server.test.ts index d43941f2a0c2..10d0690e70b8 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/performance.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/test/performance.server.test.ts @@ -32,4 +32,14 @@ test('server pageload request span has nested request span for sub request', asy expect.objectContaining({ op: 'http.server', description: 'GET /api/users' }), ]), ); + + expect(serverTxnEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + 'user-agent': expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/server-load-fetch', + }); }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit/test/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit/test/errors.server.test.ts index d2215cf8e763..5a3940a213b5 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit/test/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit/test/errors.server.test.ts @@ -21,6 +21,16 @@ test.describe('server-side errors', () => { ); expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); + + expect(errorEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + 'user-agent': expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/universal-load-error', + }); }); test('captures server load error', async ({ page }) => { @@ -42,6 +52,16 @@ test.describe('server-side errors', () => { ); expect(errorEvent.tags).toMatchObject({ runtime: 'node' }); + + expect(errorEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + 'user-agent': expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/server-load-error', + }); }); test('captures server route (GET) error', async ({ page }) => { @@ -64,5 +84,14 @@ test.describe('server-side errors', () => { ); expect(errorEvent.transaction).toEqual('GET /server-route-error'); + + expect(errorEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/server-route-error', + }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts index a363d28f291b..e462d08ddeeb 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts @@ -32,4 +32,14 @@ test('server pageload request span has nested request span for sub request', asy expect.objectContaining({ op: 'http.server', description: 'GET /api/users' }), ]), ); + + expect(serverTxnEvent.request).toEqual({ + cookies: {}, + headers: expect.objectContaining({ + accept: expect.any(String), + 'user-agent': expect.any(String), + }), + method: 'GET', + url: 'http://localhost:3030/server-load-fetch', + }); }); diff --git a/packages/sveltekit/src/server/handle.ts b/packages/sveltekit/src/server/handle.ts index ee55ed810e8e..8791ad406ff8 100644 --- a/packages/sveltekit/src/server/handle.ts +++ b/packages/sveltekit/src/server/handle.ts @@ -2,6 +2,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getActiveSpan, + getCurrentScope, getDefaultIsolationScope, getIsolationScope, getRootSpan, @@ -11,8 +12,13 @@ import { } from '@sentry/core'; import { startSpan } from '@sentry/core'; import { captureException, continueTrace } from '@sentry/node'; -import type { Span } from '@sentry/types'; -import { dynamicSamplingContextToSentryBaggageHeader, logger, objectify } from '@sentry/utils'; +import type { Scope, Span } from '@sentry/types'; +import { + dynamicSamplingContextToSentryBaggageHeader, + logger, + objectify, + winterCGRequestToRequestData, +} from '@sentry/utils'; import type { Handle, ResolveOptions } from '@sveltejs/kit'; import { getDynamicSamplingContextFromSpan } from '@sentry/opentelemetry'; @@ -168,9 +174,10 @@ export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle { return instrumentHandle(input, options); } - return withIsolationScope(() => { + return withIsolationScope(isolationScope => { // We only call continueTrace in the initial top level request to avoid // creating a new root span for the sub request. + setRequestOnScope(input.event.request.clone(), isolationScope); return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options)); }); }; @@ -206,6 +213,7 @@ async function instrumentHandle( name: routeName, }, async (span?: Span) => { + setRequestOnScope(event.request.clone(), getCurrentScope()); const res = await resolve(event, { transformPageChunk: addSentryCodeToPage(options), }); @@ -223,3 +231,9 @@ async function instrumentHandle( await flushIfServerless(); } } + +function setRequestOnScope(request: Request, scope: Scope): void { + scope.setSDKProcessingMetadata({ + request: winterCGRequestToRequestData(request), + }); +} From d99ad3ef8ab823a45c5dde60c553096e819b7dd6 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 28 May 2024 12:07:29 +0200 Subject: [PATCH 2/3] cleanup --- packages/sveltekit/src/server/handle.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/sveltekit/src/server/handle.ts b/packages/sveltekit/src/server/handle.ts index 8791ad406ff8..56ddc23e1885 100644 --- a/packages/sveltekit/src/server/handle.ts +++ b/packages/sveltekit/src/server/handle.ts @@ -12,7 +12,7 @@ import { } from '@sentry/core'; import { startSpan } from '@sentry/core'; import { captureException, continueTrace } from '@sentry/node'; -import type { Scope, Span } from '@sentry/types'; +import type { Span } from '@sentry/types'; import { dynamicSamplingContextToSentryBaggageHeader, logger, @@ -177,7 +177,7 @@ export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle { return withIsolationScope(isolationScope => { // We only call continueTrace in the initial top level request to avoid // creating a new root span for the sub request. - setRequestOnScope(input.event.request.clone(), isolationScope); + isolationScope.setSDKProcessingMetadata({ request: winterCGRequestToRequestData(input.event.request.clone()) }); return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options)); }); }; @@ -213,7 +213,7 @@ async function instrumentHandle( name: routeName, }, async (span?: Span) => { - setRequestOnScope(event.request.clone(), getCurrentScope()); + getCurrentScope().setSDKProcessingMetadata({ request: winterCGRequestToRequestData(event.request.clone()) }); const res = await resolve(event, { transformPageChunk: addSentryCodeToPage(options), }); @@ -231,9 +231,3 @@ async function instrumentHandle( await flushIfServerless(); } } - -function setRequestOnScope(request: Request, scope: Scope): void { - scope.setSDKProcessingMetadata({ - request: winterCGRequestToRequestData(request), - }); -} From 15cccdefa4e19721c31ccd73ccc06678e49dcdcf Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 28 May 2024 12:49:14 +0200 Subject: [PATCH 3/3] fix unit tests --- packages/sveltekit/test/server/handle.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/sveltekit/test/server/handle.test.ts b/packages/sveltekit/test/server/handle.test.ts index e029a118b411..e34f507af047 100644 --- a/packages/sveltekit/test/server/handle.test.ts +++ b/packages/sveltekit/test/server/handle.test.ts @@ -44,6 +44,8 @@ function mockEvent(override: Record = {}): Parameters[0 ...override, }; + event.request.clone = () => event.request; + return event; }