Skip to content

feat(node): Drop 401-404 and 3xx status code spans by default #16972

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 15, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,3 @@ test('Should send a transaction and an error event for a faulty generateViewport

expect(errorEvent.transaction).toBe('Page.generateViewport (/generation-functions)');
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this test because the redirect is no longer sent.

test('Should send a transaction event with correct status for a generateMetadata() function invocation with redirect()', async ({
page,
}) => {
const testTitle = 'redirect-foobar';

const transactionPromise = waitForTransaction('nextjs-14', async transactionEvent => {
return (
transactionEvent.contexts?.trace?.data?.['http.target'] ===
`/generation-functions/with-redirect?metadataTitle=${testTitle}`
);
});

await page.goto(`/generation-functions/with-redirect?metadataTitle=${testTitle}`);

expect((await transactionPromise).contexts?.trace?.status).toBe('ok');
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export async function GET() {
}

export async function POST() {
return NextResponse.json({ name: 'John Doe' }, { status: 403 });
return NextResponse.json({ name: 'John Doe' }, { status: 400 });
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ test('Should create a transaction for route handlers and correctly set span stat

const routehandlerTransaction = await routehandlerTransactionPromise;

expect(routehandlerTransaction.contexts?.trace?.status).toBe('permission_denied');
expect(routehandlerTransaction.contexts?.trace?.status).toBe('invalid_argument');
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ export const appRouter = t.router({
.mutation(() => {
throw new Error('I crashed in a trpc handler');
}),
unauthorized: procedure.mutation(() => {
throw new TRPCError({ code: 'UNAUTHORIZED', cause: new Error('Unauthorized') });
badRequest: procedure.mutation(() => {
throw new TRPCError({ code: 'BAD_REQUEST', cause: new Error('Bad Request') });
}),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ test('Should record transaction and error for a trpc handler that returns a stat
const transactionEventPromise = waitForTransaction('node-express', transactionEvent => {
return (
transactionEvent.transaction === 'POST /trpc' &&
!!transactionEvent.spans?.find(span => span.description === 'trpc/unauthorized')
!!transactionEvent.spans?.find(span => span.description === 'trpc/badRequest')
);
});

const errorEventPromise = waitForError('node-express', errorEvent => {
return !!errorEvent?.exception?.values?.some(exception => exception.value?.includes('Unauthorized'));
return !!errorEvent?.exception?.values?.some(exception => exception.value?.includes('Bad Request'));
});

const trpcClient = createTRPCProxyClient<AppRouter>({
Expand All @@ -125,7 +125,7 @@ test('Should record transaction and error for a trpc handler that returns a stat
],
});

await expect(trpcClient.unauthorized.mutate()).rejects.toBeDefined();
await expect(trpcClient.badRequest.mutate()).rejects.toBeDefined();

await expect(transactionEventPromise).resolves.toBeDefined();
await expect(errorEventPromise).resolves.toBeDefined();
Expand Down
7 changes: 5 additions & 2 deletions packages/node-core/src/integrations/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ interface HttpOptions {
* By default, spans with 404 status code are ignored.
* Expects an array of status codes or a range of status codes, e.g. [[300,399], 404] would ignore 3xx and 404 status codes.
*
* @default `[404]`
* @default `[[401, 404], [300, 399]]`
*/
dropSpansForIncomingRequestStatusCodes?: (number | [number, number])[];

Expand Down Expand Up @@ -105,7 +105,10 @@ const instrumentSentryHttp = generateInstrumentOnce<SentryHttpInstrumentationOpt
* It creates breadcrumbs for outgoing HTTP requests which will be attached to the currently active span.
*/
export const httpIntegration = defineIntegration((options: HttpOptions = {}) => {
const dropSpansForIncomingRequestStatusCodes = options.dropSpansForIncomingRequestStatusCodes ?? [404];
const dropSpansForIncomingRequestStatusCodes = options.dropSpansForIncomingRequestStatusCodes ?? [
[401, 404],
[300, 399],
];

return {
name: INTEGRATION_NAME,
Expand Down
7 changes: 5 additions & 2 deletions packages/node/src/integrations/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ interface HttpOptions {
* By default, spans with 404 status code are ignored.
* Expects an array of status codes or a range of status codes, e.g. [[300,399], 404] would ignore 3xx and 404 status codes.
*
* @default `[404]`
* @default `[[401, 404], [300, 399]]`
*/
dropSpansForIncomingRequestStatusCodes?: (number | [number, number])[];

Expand Down Expand Up @@ -184,7 +184,10 @@ export function _shouldInstrumentSpans(options: HttpOptions, clientOptions: Part
* It creates breadcrumbs and spans for outgoing HTTP requests which will be attached to the currently active span.
*/
export const httpIntegration = defineIntegration((options: HttpOptions = {}) => {
const dropSpansForIncomingRequestStatusCodes = options.dropSpansForIncomingRequestStatusCodes ?? [404];
const dropSpansForIncomingRequestStatusCodes = options.dropSpansForIncomingRequestStatusCodes ?? [
[401, 404],
[300, 399],
];

return {
name: INTEGRATION_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,28 +152,15 @@ describe('Remix API Actions', () => {

const envelopes = await env.getMultipleEnvelopeRequest({
url,
count: 3,
count: 2,
method: 'post',
envelopeType: ['transaction', 'event'],
});

const [transaction_1, transaction_2] = envelopes.filter(envelope => envelope[1].type === 'transaction');
const [transaction] = envelopes.filter(envelope => envelope[1].type === 'transaction');
const [event] = envelopes.filter(envelope => envelope[1].type === 'event');

assertSentryTransaction(transaction_1[2], {
contexts: {
trace: {
op: 'http.server',
status: 'ok',
data: {
'http.response.status_code': 302,
},
},
},
transaction: `POST action-json-response/:id`,
});

assertSentryTransaction(transaction_2[2], {
assertSentryTransaction(transaction[2], {
contexts: {
trace: {
op: 'http.server',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,27 +123,14 @@ describe('Remix API Loaders', () => {

const envelopes = await env.getMultipleEnvelopeRequest({
url,
count: 3,
count: 2,
envelopeType: ['transaction', 'event'],
});

const [transaction_1, transaction_2] = envelopes.filter(envelope => envelope[1].type === 'transaction');
const [transaction] = envelopes.filter(envelope => envelope[1].type === 'transaction');
const [event] = envelopes.filter(envelope => envelope[1].type === 'event');

assertSentryTransaction(transaction_1[2], {
contexts: {
trace: {
op: 'http.server',
status: 'ok',
data: {
'http.response.status_code': 302,
},
},
},
transaction: `GET loader-json-response/:id`,
});

assertSentryTransaction(transaction_2[2], {
assertSentryTransaction(transaction[2], {
contexts: {
trace: {
op: 'http.server',
Expand Down