From 4a94eb21494d46c105e01907421c3c2d0caa4585 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Tue, 26 Oct 2021 21:06:13 -0700 Subject: [PATCH 1/4] add filter for 404 transactions --- packages/nextjs/src/index.client.ts | 1 + packages/nextjs/src/index.server.ts | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/packages/nextjs/src/index.client.ts b/packages/nextjs/src/index.client.ts index e23464cf07d1..970cadb00a06 100644 --- a/packages/nextjs/src/index.client.ts +++ b/packages/nextjs/src/index.client.ts @@ -30,6 +30,7 @@ export function init(options: NextjsOptions): void { }); configureScope(scope => { scope.setTag('runtime', 'browser'); + scope.addEventProcessor(event => (event.type === 'transaction' && event.transaction === '/404' ? null : event)); }); } diff --git a/packages/nextjs/src/index.server.ts b/packages/nextjs/src/index.server.ts index 0c7e19690877..6fd4e1fce468 100644 --- a/packages/nextjs/src/index.server.ts +++ b/packages/nextjs/src/index.server.ts @@ -1,6 +1,7 @@ import { Carrier, getHubFromCarrier, getMainCarrier } from '@sentry/hub'; import { RewriteFrames } from '@sentry/integrations'; import { configureScope, getCurrentHub, init as nodeInit, Integrations } from '@sentry/node'; +import { Event } from '@sentry/types'; import { escapeStringForRegex, logger } from '@sentry/utils'; import * as domainModule from 'domain'; import * as path from 'path'; @@ -56,6 +57,8 @@ export function init(options: NextjsOptions): void { if (process.env.VERCEL) { scope.setTag('vercel', true); } + + scope.addEventProcessor(filterTransactions); }); if (activeDomain) { @@ -65,6 +68,8 @@ export function init(options: NextjsOptions): void { // apply the changes made by `nodeInit` to the domain's hub also domainHub.bindClient(globalHub.getClient()); domainHub.getScope()?.update(globalHub.getScope()); + // `scope.update()` doesn’t copy over event processors, so we have to add it manually + domainHub.getScope()?.addEventProcessor(filterTransactions); // restore the domain hub as the current one domain.active = activeDomain; @@ -107,6 +112,10 @@ function addServerIntegrations(options: NextjsOptions): void { } } +function filterTransactions(event: Event): Event | null { + return event.type === 'transaction' && event.transaction === '/404' ? null : event; +} + export { withSentryConfig } from './config'; export { withSentry } from './utils/withSentry'; From a7b492d1ef4e3cffd4b0ef29bcb4ca5af112d807 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Tue, 26 Oct 2021 21:06:50 -0700 Subject: [PATCH 2/4] add server test --- packages/nextjs/test/index.server.test.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/nextjs/test/index.server.test.ts b/packages/nextjs/test/index.server.test.ts index 337e70345c52..39e5a244a31b 100644 --- a/packages/nextjs/test/index.server.test.ts +++ b/packages/nextjs/test/index.server.test.ts @@ -2,7 +2,7 @@ import { RewriteFrames } from '@sentry/integrations'; import * as SentryNode from '@sentry/node'; import { getCurrentHub, NodeClient } from '@sentry/node'; import { Integration } from '@sentry/types'; -import { getGlobalObject } from '@sentry/utils'; +import { getGlobalObject, logger, SentryError } from '@sentry/utils'; import * as domain from 'domain'; import { init } from '../src/index.server'; @@ -16,6 +16,7 @@ const global = getGlobalObject(); (global as typeof global & { __rewriteFramesDistDir__: string }).__rewriteFramesDistDir__ = '.next'; const nodeInit = jest.spyOn(SentryNode, 'init'); +const logError = jest.spyOn(logger, 'error'); describe('Server init()', () => { afterEach(() => { @@ -87,6 +88,18 @@ describe('Server init()', () => { expect(currentScope._tags.vercel).toBeUndefined(); }); + it('adds 404 transaction filter', () => { + init({ + dsn: 'https://dogsarebadatkeepingsecrets@squirrelchasers.ingest.sentry.io/12312012', + tracesSampleRate: 1.0, + }); + + const transaction = getCurrentHub().startTransaction({ name: '/404' }); + transaction.finish(); + + expect(logError).toHaveBeenCalledWith(new SentryError('An event processor returned null, will not send event.')); + }); + it("initializes both global hub and domain hub when there's an active domain", () => { const globalHub = getCurrentHub(); const local = domain.create(); From fd704f846a3c50e8885c7b07956d0acd64f07d10 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Tue, 26 Oct 2021 21:14:17 -0700 Subject: [PATCH 3/4] add client test --- packages/nextjs/test/index.client.test.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/nextjs/test/index.client.test.ts b/packages/nextjs/test/index.client.test.ts index 0f906df79b2d..749ee474bd71 100644 --- a/packages/nextjs/test/index.client.test.ts +++ b/packages/nextjs/test/index.client.test.ts @@ -2,7 +2,7 @@ import { getCurrentHub } from '@sentry/hub'; import * as SentryReact from '@sentry/react'; import { Integrations as TracingIntegrations } from '@sentry/tracing'; import { Integration } from '@sentry/types'; -import { getGlobalObject } from '@sentry/utils'; +import { getGlobalObject, logger, SentryError } from '@sentry/utils'; import { init, Integrations, nextRouterInstrumentation } from '../src/index.client'; import { NextjsOptions } from '../src/utils/nextjsOptions'; @@ -12,6 +12,7 @@ const { BrowserTracing } = TracingIntegrations; const global = getGlobalObject(); const reactInit = jest.spyOn(SentryReact, 'init'); +const logError = jest.spyOn(logger, 'error'); describe('Client init()', () => { afterEach(() => { @@ -50,6 +51,18 @@ describe('Client init()', () => { expect(currentScope._tags).toEqual({ runtime: 'browser' }); }); + it('adds 404 transaction filter', () => { + init({ + dsn: 'https://dogsarebadatkeepingsecrets@squirrelchasers.ingest.sentry.io/12312012', + tracesSampleRate: 1.0, + }); + + const transaction = getCurrentHub().startTransaction({ name: '/404' }); + transaction.finish(); + + expect(logError).toHaveBeenCalledWith(new SentryError('An event processor returned null, will not send event.')); + }); + describe('integrations', () => { it('does not add BrowserTracing integration by default if tracesSampleRate is not set', () => { init({}); From b2872a8f2577591f02db2abfb9be27d789d1f41f Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Wed, 27 Oct 2021 13:21:13 -0700 Subject: [PATCH 4/4] assert on more things in tests --- packages/nextjs/test/index.client.test.ts | 10 ++++++++-- packages/nextjs/test/index.server.test.ts | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/nextjs/test/index.client.test.ts b/packages/nextjs/test/index.client.test.ts index 749ee474bd71..19171bc4346c 100644 --- a/packages/nextjs/test/index.client.test.ts +++ b/packages/nextjs/test/index.client.test.ts @@ -1,3 +1,4 @@ +import { BaseClient } from '@sentry/core'; import { getCurrentHub } from '@sentry/hub'; import * as SentryReact from '@sentry/react'; import { Integrations as TracingIntegrations } from '@sentry/tracing'; @@ -12,11 +13,12 @@ const { BrowserTracing } = TracingIntegrations; const global = getGlobalObject(); const reactInit = jest.spyOn(SentryReact, 'init'); +const captureEvent = jest.spyOn(BaseClient.prototype, 'captureEvent'); const logError = jest.spyOn(logger, 'error'); describe('Client init()', () => { afterEach(() => { - reactInit.mockClear(); + jest.clearAllMocks(); global.__SENTRY__.hub = undefined; }); @@ -56,10 +58,14 @@ describe('Client init()', () => { dsn: 'https://dogsarebadatkeepingsecrets@squirrelchasers.ingest.sentry.io/12312012', tracesSampleRate: 1.0, }); + const hub = getCurrentHub(); + const sendEvent = jest.spyOn(hub.getClient()!.getTransport!(), 'sendEvent'); - const transaction = getCurrentHub().startTransaction({ name: '/404' }); + const transaction = hub.startTransaction({ name: '/404' }); transaction.finish(); + expect(sendEvent).not.toHaveBeenCalled(); + expect(captureEvent.mock.results[0].value).toBeUndefined(); expect(logError).toHaveBeenCalledWith(new SentryError('An event processor returned null, will not send event.')); }); diff --git a/packages/nextjs/test/index.server.test.ts b/packages/nextjs/test/index.server.test.ts index 39e5a244a31b..d3fc53a194ed 100644 --- a/packages/nextjs/test/index.server.test.ts +++ b/packages/nextjs/test/index.server.test.ts @@ -1,3 +1,4 @@ +import { BaseClient } from '@sentry/core'; import { RewriteFrames } from '@sentry/integrations'; import * as SentryNode from '@sentry/node'; import { getCurrentHub, NodeClient } from '@sentry/node'; @@ -16,11 +17,12 @@ const global = getGlobalObject(); (global as typeof global & { __rewriteFramesDistDir__: string }).__rewriteFramesDistDir__ = '.next'; const nodeInit = jest.spyOn(SentryNode, 'init'); +const captureEvent = jest.spyOn(BaseClient.prototype, 'captureEvent'); const logError = jest.spyOn(logger, 'error'); describe('Server init()', () => { afterEach(() => { - nodeInit.mockClear(); + jest.clearAllMocks(); global.__SENTRY__.hub = undefined; }); @@ -93,10 +95,14 @@ describe('Server init()', () => { dsn: 'https://dogsarebadatkeepingsecrets@squirrelchasers.ingest.sentry.io/12312012', tracesSampleRate: 1.0, }); + const hub = getCurrentHub(); + const sendEvent = jest.spyOn(hub.getClient()!.getTransport!(), 'sendEvent'); - const transaction = getCurrentHub().startTransaction({ name: '/404' }); + const transaction = hub.startTransaction({ name: '/404' }); transaction.finish(); + expect(sendEvent).not.toHaveBeenCalled(); + expect(captureEvent.mock.results[0].value).toBeUndefined(); expect(logError).toHaveBeenCalledWith(new SentryError('An event processor returned null, will not send event.')); });