Skip to content

Commit 87316c9

Browse files
committed
ref: Set normalizedRequest instead of request various places
The request data integration prefers this over `request`, we want to get rid of `request` in v9. Part of #14298
1 parent 1828af8 commit 87316c9

File tree

16 files changed

+91
-72
lines changed

16 files changed

+91
-72
lines changed

dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/server-components.test.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,12 @@ test('Sends a transaction for a request to app router', async ({ page }) => {
3333
trace_id: expect.any(String),
3434
});
3535

36-
expect(transactionEvent).toEqual(
37-
expect.objectContaining({
38-
request: {
39-
cookies: {},
40-
headers: expect.any(Object),
41-
url: expect.any(String),
42-
},
36+
expect(transactionEvent.request).toEqual({
37+
cookies: {},
38+
headers: expect.objectContaining({
39+
'user-agent': expect.any(String),
4340
}),
44-
);
45-
46-
expect(Object.keys(transactionEvent.request?.headers!).length).toBeGreaterThan(0);
41+
});
4742

4843
// The transaction should not contain any spans with the same name as the transaction
4944
// e.g. "GET /server-component/parameter/[...parameters]"

packages/astro/src/server/middleware.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import {
1212
startSpan,
1313
withIsolationScope,
1414
} from '@sentry/node';
15-
import type { Scope, SpanAttributes } from '@sentry/types';
15+
import type { Request, Scope, SpanAttributes } from '@sentry/types';
1616
import {
1717
addNonEnumerableProperty,
18+
extractQueryParamsFromUrl,
1819
logger,
1920
objectify,
2021
stripUrlQueryAndFragment,
@@ -111,7 +112,13 @@ async function instrumentRequest(
111112
getCurrentScope().setSDKProcessingMetadata({
112113
// We store the request on the current scope, not isolation scope,
113114
// because we may have multiple requests nested inside each other
114-
request: isDynamicPageRequest ? winterCGRequestToRequestData(request) : { method, url: request.url },
115+
normalizedRequest: (isDynamicPageRequest
116+
? winterCGRequestToRequestData(request)
117+
: {
118+
method,
119+
url: request.url,
120+
query_string: extractQueryParamsFromUrl(request.url),
121+
}) satisfies Request,
115122
});
116123

117124
if (options.trackClientIp && isDynamicPageRequest) {

packages/astro/test/server/middleware.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ describe('sentryMiddleware', () => {
221221
await middleware(ctx, next);
222222

223223
expect(setSDKProcessingMetadataMock).toHaveBeenCalledWith({
224-
request: {
224+
normalizedRequest: {
225225
method: 'GET',
226226
url: '/users',
227227
headers: {
@@ -254,7 +254,7 @@ describe('sentryMiddleware', () => {
254254
await middleware(ctx, next);
255255

256256
expect(setSDKProcessingMetadataMock).toHaveBeenCalledWith({
257-
request: {
257+
normalizedRequest: {
258258
method: 'GET',
259259
url: '/users',
260260
},

packages/bun/src/integrations/bunserver.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {
99
startSpan,
1010
withIsolationScope,
1111
} from '@sentry/core';
12-
import type { IntegrationFn, SpanAttributes } from '@sentry/types';
13-
import { getSanitizedUrlString, parseUrl } from '@sentry/utils';
12+
import type { IntegrationFn, Request, SpanAttributes } from '@sentry/types';
13+
import { extractQueryParamsFromUrl, getSanitizedUrlString, parseUrl } from '@sentry/utils';
1414

1515
const INTEGRATION_NAME = 'BunServer';
1616

@@ -76,11 +76,12 @@ function instrumentBunServeOptions(serveOptions: Parameters<typeof Bun.serve>[0]
7676
const url = getSanitizedUrlString(parsedUrl);
7777

7878
isolationScope.setSDKProcessingMetadata({
79-
request: {
79+
normalizedRequest: {
8080
url,
8181
method: request.method,
8282
headers: request.headers.toJSON(),
83-
},
83+
query_string: extractQueryParamsFromUrl(url),
84+
} satisfies Request,
8485
});
8586

8687
return continueTrace(

packages/cloudflare/src/scope-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ export function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties)
2525
* Set request data on scope
2626
*/
2727
export function addRequest(scope: Scope, request: Request): void {
28-
scope.setSDKProcessingMetadata({ request: winterCGRequestToRequestData(request) });
28+
scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });
2929
}

packages/cloudflare/test/request.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe('withSentry', () => {
109109
},
110110
);
111111

112-
expect(sentryEvent.sdkProcessingMetadata?.request).toEqual({
112+
expect(sentryEvent.sdkProcessingMetadata?.normalizedRequest).toEqual({
113113
headers: {},
114114
url: 'https://example.com/',
115115
method: 'GET',

packages/nextjs/src/common/captureRequestError.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { captureException, withScope } from '@sentry/core';
2+
import type { Request } from '@sentry/types';
3+
import { headersToDict } from '@sentry/utils';
24

35
type RequestInfo = {
46
path: string;
@@ -18,10 +20,10 @@ type ErrorContext = {
1820
export function captureRequestError(error: unknown, request: RequestInfo, errorContext: ErrorContext): void {
1921
withScope(scope => {
2022
scope.setSDKProcessingMetadata({
21-
request: {
22-
headers: request.headers,
23+
normalizedRequest: {
24+
headers: headersToDict(request.headers),
2325
method: request.method,
24-
},
26+
} satisfies Request,
2527
});
2628

2729
scope.setContext('nextjs', {

packages/nextjs/src/common/withServerActionInstrumentation.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
startSpan,
1010
withIsolationScope,
1111
} from '@sentry/core';
12+
import type { Request } from '@sentry/types';
1213
import { logger, vercelWaitUntil } from '@sentry/utils';
1314

1415
import { DEBUG_BUILD } from './debug-build';
@@ -89,9 +90,9 @@ async function withServerActionInstrumentationImplementation<A extends (...args:
8990

9091
isolationScope.setTransactionName(`serverAction/${serverActionName}`);
9192
isolationScope.setSDKProcessingMetadata({
92-
request: {
93+
normalizedRequest: {
9394
headers: fullHeadersObject,
94-
},
95+
} satisfies Request,
9596
});
9697

9798
return continueTrace(

packages/nextjs/src/common/wrapGenerationFunctionWithSentry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
withIsolationScope,
1515
withScope,
1616
} from '@sentry/core';
17-
import type { WebFetchHeaders } from '@sentry/types';
17+
import type { Request, WebFetchHeaders } from '@sentry/types';
1818
import { propagationContextFromHeaders, uuid4, winterCGHeadersToDict } from '@sentry/utils';
1919

2020
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
@@ -68,9 +68,9 @@ export function wrapGenerationFunctionWithSentry<F extends (...args: any[]) => a
6868
scope.setTransactionName(`${componentType}.${generationFunctionIdentifier} (${componentRoute})`);
6969

7070
isolationScope.setSDKProcessingMetadata({
71-
request: {
71+
normalizedRequest: {
7272
headers: headersDict,
73-
},
73+
} satisfies Request,
7474
});
7575

7676
const activeSpan = getActiveSpan();

packages/nextjs/src/common/wrapMiddlewareWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function wrapMiddlewareWithSentry<H extends EdgeRouteHandler>(
3636

3737
if (req instanceof Request) {
3838
isolationScope.setSDKProcessingMetadata({
39-
request: winterCGRequestToRequestData(req),
39+
normalizedRequest: winterCGRequestToRequestData(req),
4040
});
4141
spanName = `middleware ${req.method} ${new URL(req.url).pathname}`;
4242
spanSource = 'url';

packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
withIsolationScope,
1414
withScope,
1515
} from '@sentry/core';
16-
16+
import type { Request as SentryRequest } from '@sentry/types';
1717
import type { RouteHandlerContext } from './types';
1818

1919
import { propagationContextFromHeaders, winterCGHeadersToDict } from '@sentry/utils';
@@ -64,10 +64,10 @@ export function wrapRouteHandlerWithSentry<F extends (...args: any[]) => any>(
6464
);
6565
scope.setPropagationContext(incomingPropagationContext);
6666
scope.setSDKProcessingMetadata({
67-
request: {
67+
normalizedRequest: {
6868
method,
6969
headers: completeHeadersDict,
70-
},
70+
} satisfies SentryRequest,
7171
});
7272
}
7373

packages/nextjs/src/common/wrapServerComponentWithSentry.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
withIsolationScope,
1414
withScope,
1515
} from '@sentry/core';
16+
import type { Request as SentryRequest } from '@sentry/types';
1617
import { propagationContextFromHeaders, uuid4, vercelWaitUntil, winterCGHeadersToDict } from '@sentry/utils';
1718

1819
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
@@ -49,9 +50,9 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
4950
const headersDict = context.headers ? winterCGHeadersToDict(context.headers) : undefined;
5051

5152
isolationScope.setSDKProcessingMetadata({
52-
request: {
53+
normalizedRequest: {
5354
headers: headersDict,
54-
},
55+
} satisfies SentryRequest,
5556
});
5657

5758
return withIsolationScope(isolationScope, () => {

packages/nextjs/src/edge/wrapApiHandlerWithSentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function wrapApiHandlerWithSentry<H extends EdgeRouteHandler>(
3232

3333
if (req instanceof Request) {
3434
isolationScope.setSDKProcessingMetadata({
35-
request: winterCGRequestToRequestData(req),
35+
normalizedRequest: winterCGRequestToRequestData(req),
3636
});
3737
currentScope.setTransactionName(`${req.method} ${parameterizedRoute}`);
3838
} else {

packages/node/src/integrations/http/SentryHttpInstrumentation.ts

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import { getRequestInfo } from '@opentelemetry/instrumentation-http';
88
import { addBreadcrumb, getClient, getIsolationScope, withIsolationScope } from '@sentry/core';
99
import type { PolymorphicRequest, Request, SanitizedRequestData } from '@sentry/types';
1010
import {
11+
extractQueryParamsFromUrl,
1112
getBreadcrumbLogLevelFromHttpStatusCode,
1213
getSanitizedUrlString,
14+
headersToDict,
1315
logger,
1416
parseUrl,
1517
stripUrlQueryAndFragment,
@@ -145,7 +147,7 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
145147
const normalizedRequest: Request = {
146148
url: absoluteUrl,
147149
method: request.method,
148-
query_string: extractQueryParams(request),
150+
query_string: extractQueryParamsFromUrl(request.url || ''),
149151
headers: headersToDict(request.headers),
150152
cookies,
151153
};
@@ -439,36 +441,3 @@ function patchRequestToCaptureBody(req: IncomingMessage, normalizedRequest: Requ
439441
// ignore errors if we can't patch stuff
440442
}
441443
}
442-
443-
function extractQueryParams(req: IncomingMessage): string | undefined {
444-
// req.url is path and query string
445-
if (!req.url) {
446-
return;
447-
}
448-
449-
try {
450-
// The `URL` constructor can't handle internal URLs of the form `/some/path/here`, so stick a dummy protocol and
451-
// hostname as the base. Since the point here is just to grab the query string, it doesn't matter what we use.
452-
const queryParams = new URL(req.url, 'http://dogs.are.great').search.slice(1);
453-
return queryParams.length ? queryParams : undefined;
454-
} catch {
455-
return undefined;
456-
}
457-
}
458-
459-
function headersToDict(reqHeaders: Record<string, string | string[] | undefined>): Record<string, string> {
460-
const headers: Record<string, string> = Object.create(null);
461-
462-
try {
463-
Object.entries(reqHeaders).forEach(([key, value]) => {
464-
if (typeof value === 'string') {
465-
headers[key] = value;
466-
}
467-
});
468-
} catch (e) {
469-
DEBUG_BUILD &&
470-
logger.warn('Sentry failed extracting headers from a request object. If you see this, please file an issue.');
471-
}
472-
473-
return headers;
474-
}

packages/sveltekit/src/server/handle.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle {
131131
return withIsolationScope(isolationScope => {
132132
// We only call continueTrace in the initial top level request to avoid
133133
// creating a new root span for the sub request.
134-
isolationScope.setSDKProcessingMetadata({ request: winterCGRequestToRequestData(input.event.request.clone()) });
134+
isolationScope.setSDKProcessingMetadata({
135+
normalizedRequest: winterCGRequestToRequestData(input.event.request.clone()),
136+
});
135137
return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options));
136138
});
137139
};
@@ -167,7 +169,9 @@ async function instrumentHandle(
167169
name: routeName,
168170
},
169171
async (span?: Span) => {
170-
getCurrentScope().setSDKProcessingMetadata({ request: winterCGRequestToRequestData(event.request.clone()) });
172+
getCurrentScope().setSDKProcessingMetadata({
173+
normalizedRequest: winterCGRequestToRequestData(event.request.clone()),
174+
});
171175
const res = await resolve(event, {
172176
transformPageChunk: addSentryCodeToPage(options),
173177
});

packages/utils/src/requestdata.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,18 +434,57 @@ export function winterCGHeadersToDict(winterCGHeaders: WebFetchHeaders): Record<
434434
return headers;
435435
}
436436

437+
/**
438+
* Convert common request headers to a simple dictionary.
439+
*/
440+
export function headersToDict(reqHeaders: Record<string, string | string[] | undefined>): Record<string, string> {
441+
const headers: Record<string, string> = Object.create(null);
442+
443+
try {
444+
Object.entries(reqHeaders).forEach(([key, value]) => {
445+
if (typeof value === 'string') {
446+
headers[key] = value;
447+
}
448+
});
449+
} catch (e) {
450+
DEBUG_BUILD &&
451+
logger.warn('Sentry failed extracting headers from a request object. If you see this, please file an issue.');
452+
}
453+
454+
return headers;
455+
}
456+
437457
/**
438458
* Converts a `Request` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into the format that the `RequestData` integration understands.
439459
*/
440-
export function winterCGRequestToRequestData(req: WebFetchRequest): PolymorphicRequest {
460+
export function winterCGRequestToRequestData(req: WebFetchRequest): Request {
441461
const headers = winterCGHeadersToDict(req.headers);
442462
return {
443463
method: req.method,
444464
url: req.url,
465+
query_string: extractQueryParamsFromUrl(req.url),
445466
headers,
467+
// TODO: Can we extract body data from the request?
446468
};
447469
}
448470

471+
/** Extract the query params from an URL. */
472+
export function extractQueryParamsFromUrl(url: string): string | undefined {
473+
// url is path and query string
474+
if (!url) {
475+
return;
476+
}
477+
478+
try {
479+
// The `URL` constructor can't handle internal URLs of the form `/some/path/here`, so stick a dummy protocol and
480+
// hostname as the base. Since the point here is just to grab the query string, it doesn't matter what we use.
481+
const queryParams = new URL(url, 'http://dogs.are.great').search.slice(1);
482+
return queryParams.length ? queryParams : undefined;
483+
} catch {
484+
return undefined;
485+
}
486+
}
487+
449488
function extractNormalizedRequestData(normalizedRequest: Request, { include }: { include: string[] }): Request {
450489
const includeKeys = include ? (Array.isArray(include) ? include : DEFAULT_REQUEST_INCLUDES) : [];
451490

0 commit comments

Comments
 (0)