Skip to content

Commit

Permalink
fix(nuxt): Avoid sending server resource request transactions (#14497)
Browse files Browse the repository at this point in the history
Refactor the low quality transaction filter in the Nuxt SDK to
filter out all resource requests. Our SDKs
should generally not send dedicated transactions for resource requests
as they would deplete transaction quota fairly quickly, compared to only
tracking page requests.
  • Loading branch information
Lms24 authored Nov 28, 2024
1 parent 8a4098a commit f93ccbe
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 38 deletions.
16 changes: 10 additions & 6 deletions packages/nuxt/src/server/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as path from 'node:path';
import { applySdkMetadata, flush, getGlobalScope } from '@sentry/core';
import { logger, vercelWaitUntil } from '@sentry/core';
import {
Expand Down Expand Up @@ -33,23 +34,26 @@ export function init(options: SentryNuxtServerOptions): Client | undefined {
}

/**
* Filter out transactions for Nuxt build assets
* This regex matches the default path to the nuxt-generated build assets (`_nuxt`).
* Filter out transactions for resource requests which we don't want to send to Sentry
* for quota reasons.
*
* Only exported for testing
*/
export function lowQualityTransactionsFilter(options: SentryNuxtServerOptions): EventProcessor {
return Object.assign(
(event => {
if (event.type === 'transaction' && event.transaction?.match(/^GET \/_nuxt\//)) {
// todo: the buildAssetDir could be changed in the nuxt config - change this to a more generic solution
if (event.type !== 'transaction' || !event.transaction) {
return event;
}
// We don't want to send transaction for file requests, so everything ending with a *.someExtension should be filtered out
// path.extname will return an empty string for normal page requests
if (path.extname(event.transaction)) {
options.debug &&
DEBUG_BUILD &&
logger.log('NuxtLowQualityTransactionsFilter filtered transaction: ', event.transaction);
return null;
} else {
return event;
}
return event;
}) satisfies EventProcessor,
{ id: 'NuxtLowQualityTransactionsFilter' },
);
Expand Down
58 changes: 26 additions & 32 deletions packages/nuxt/test/server/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,45 +45,39 @@ describe('Nuxt Server SDK', () => {
expect(init({})).not.toBeUndefined();
});

it('filters out low quality transactions', async () => {
describe('low quality transactions filter (%s)', () => {
const beforeSendEvent = vi.fn(event => event);
const client = init({
dsn: 'https://[email protected]/1337',
}) as NodeClient;
client.on('beforeSendEvent', beforeSendEvent);

client.captureEvent({ type: 'transaction', transaction: 'GET /' });
client.captureEvent({ type: 'transaction', transaction: 'GET /_nuxt/some_asset.js' });
// Although this has the name of the build asset directory (_nuxt), it should not be filtered out as it would not match the regex
client.captureEvent({ type: 'transaction', transaction: 'GET _nuxt/some_asset.js' });
client.captureEvent({ type: 'transaction', transaction: 'POST /_server' });

await client!.flush();
it.each([
[
'GET /_nuxt/some_asset.js',
'GET _nuxt/some_asset.js',
'GET /icons/favicon.ico',
'GET /assets/logo.png',
'GET /icons/zones/forest.svg',
],
])('filters out low quality transactions', async transaction => {
client.captureEvent({ type: 'transaction', transaction });
await client!.flush();
expect(beforeSendEvent).not.toHaveBeenCalled();
});

expect(beforeSendEvent).toHaveBeenCalledTimes(3);
expect(beforeSendEvent).toHaveBeenCalledWith(
expect.objectContaining({
transaction: 'GET /',
}),
expect.any(Object),
);
expect(beforeSendEvent).toHaveBeenCalledWith(
expect.objectContaining({
transaction: 'GET _nuxt/some_asset.js',
}),
expect.any(Object),
);
expect(beforeSendEvent).not.toHaveBeenCalledWith(
expect.objectContaining({
transaction: 'GET /_nuxt/some_asset.js',
}),
expect.any(Object),
);
expect(beforeSendEvent).toHaveBeenCalledWith(
expect.objectContaining({
transaction: 'POST /_server',
}),
expect.any(Object),
it.each(['GET /', 'POST /_server'])(
'does not filter out high quality or route transactions (%s)',
async transaction => {
client.captureEvent({ type: 'transaction', transaction });
await client!.flush();
expect(beforeSendEvent).toHaveBeenCalledWith(
expect.objectContaining({
transaction,
}),
expect.any(Object),
);
},
);
});

Expand Down

0 comments on commit f93ccbe

Please sign in to comment.