diff --git a/packages/solidstart/src/server/sdk.ts b/packages/solidstart/src/server/sdk.ts index 7329100d9de9..883d2a0ef63f 100644 --- a/packages/solidstart/src/server/sdk.ts +++ b/packages/solidstart/src/server/sdk.ts @@ -1,6 +1,7 @@ import { applySdkMetadata } from '@sentry/core'; import type { NodeClient, NodeOptions } from '@sentry/node'; import { init as initNodeSdk } from '@sentry/node'; +import { filterLowQualityTransactions } from './utils'; /** * Initializes the server side of the Solid Start SDK @@ -11,6 +12,7 @@ export function init(options: NodeOptions): NodeClient | undefined { }; applySdkMetadata(opts, 'solidstart', ['solidstart', 'node']); + filterLowQualityTransactions(opts); return initNodeSdk(opts); } diff --git a/packages/solidstart/src/server/utils.ts b/packages/solidstart/src/server/utils.ts index f3d26e5d3a26..f570ae355424 100644 --- a/packages/solidstart/src/server/utils.ts +++ b/packages/solidstart/src/server/utils.ts @@ -1,4 +1,5 @@ -import { flush } from '@sentry/node'; +import { flush, getGlobalScope } from '@sentry/node'; +import type { EventProcessor, Options } from '@sentry/types'; import { logger } from '@sentry/utils'; import { DEBUG_BUILD } from '../common/debug-build'; @@ -31,3 +32,26 @@ export function isRedirect(error: unknown): boolean { const hasValidStatus = error.status >= 300 && error.status <= 308; return hasValidLocation && hasValidStatus; } + +/** + * Adds an event processor to filter out low quality transactions, + * e.g. to filter out transactions for build assets + */ +export function filterLowQualityTransactions(options: Options): void { + getGlobalScope().addEventProcessor( + Object.assign( + (event => { + if (event.type !== 'transaction') { + return event; + } + // Filter out transactions for build assets + if (event.transaction?.match(/^GET \/_build\//)) { + options.debug && logger.log('SolidStartLowQualityTransactionsFilter filtered transaction', event.transaction); + return null; + } + return event; + }) satisfies EventProcessor, + { id: 'SolidStartLowQualityTransactionsFilter' }, + ), + ); +} diff --git a/packages/solidstart/test/server/sdk.test.ts b/packages/solidstart/test/server/sdk.test.ts index e658876c0a12..b700b43a067a 100644 --- a/packages/solidstart/test/server/sdk.test.ts +++ b/packages/solidstart/test/server/sdk.test.ts @@ -1,7 +1,7 @@ +import type { NodeClient } from '@sentry/node'; import { SDK_VERSION } from '@sentry/node'; import * as SentryNode from '@sentry/node'; - -import { vi } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { init as solidStartInit } from '../../src/server'; const browserInit = vi.spyOn(SentryNode, 'init'); @@ -33,4 +33,38 @@ describe('Initialize Solid Start SDK', () => { expect(browserInit).toHaveBeenCalledTimes(1); expect(browserInit).toHaveBeenLastCalledWith(expect.objectContaining(expectedMetadata)); }); + + it('filters out low quality transactions', async () => { + const beforeSendEvent = vi.fn(event => event); + const client = solidStartInit({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + }) as NodeClient; + client.on('beforeSendEvent', beforeSendEvent); + + client.captureEvent({ type: 'transaction', transaction: 'GET /' }); + client.captureEvent({ type: 'transaction', transaction: 'GET /_build/some_asset.js' }); + client.captureEvent({ type: 'transaction', transaction: 'POST /_server' }); + + await client!.flush(); + + expect(beforeSendEvent).toHaveBeenCalledTimes(2); + expect(beforeSendEvent).toHaveBeenCalledWith( + expect.objectContaining({ + transaction: 'GET /', + }), + expect.any(Object), + ); + expect(beforeSendEvent).not.toHaveBeenCalledWith( + expect.objectContaining({ + transaction: 'GET /_build/some_asset.js', + }), + expect.any(Object), + ); + expect(beforeSendEvent).toHaveBeenCalledWith( + expect.objectContaining({ + transaction: 'POST /_server', + }), + expect.any(Object), + ); + }); }); diff --git a/packages/types/src/eventprocessor.ts b/packages/types/src/eventprocessor.ts index 60a983fa0fdc..54177388cdde 100644 --- a/packages/types/src/eventprocessor.ts +++ b/packages/types/src/eventprocessor.ts @@ -1,7 +1,7 @@ import type { Event, EventHint } from './event'; /** - * Event processors are used to change the event before it will be send. + * Event processors are used to change the event before it will be sent. * We strongly advise to make this function sync. * Returning a PromiseLike will work just fine, but better be sure that you know what you are doing. * Event processing will be deferred until your Promise is resolved.