8000 feat(nuxt): Filter out Nuxt build assets (#13148) · benjick/sentry-javascript@29f070f · GitHub
[go: up one dir, main page]

Skip to content

Commit 29f070f

Browse files
authored
feat(nuxt): Filter out Nuxt build assets (getsentry#13148)
Filtering out events of the `_nuxt` [buildAssetDir](https://nuxt.com/docs/api/nuxt-config#buildassetsdir). Next step would be to change the regex based on the folder name (as this could be changed in the nuxt config during build time - but probably doesn't happen too often). Also added some unit tests for the server-side of the SDK. Before: <img width="698" alt="image" src="https://github.com/user-attachments/assets/2ec5ccfb-b8fb-449b-97ba-24fbecabd998"> After: <img width="686" alt="image" src="https://github.com/user-attachments/assets/adf43031-7521-44f5-b155-ea57259001f5">
1 parent d17f1be commit 29f070f

File tree

5 files changed

+125
-4
lines changed

5 files changed

+125
-4
lines changed

dev-packages/e2e-tests/test-applications/nuxt-3/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"build": "nuxt build",
77
"dev": "nuxt dev",
88
"generate": "nuxt generate",
9-
"preview": "nuxt preview",
9+
"preview": "NODE_OPTIONS='--import ./public/instrument.server.mjs' nuxt preview",
1010
"clean": "npx nuxi cleanup",
1111
"test": "playwright test",
1212
"test:build": "pnpm install && npx playwright install && pnpm build",
Lines changed: 8 additions & 0 deletions
Original file line numberDif 10000 f line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as Sentry from '@sentry/nuxt';
2+
3+
Sentry.init({
4+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
5+
environment: 'qa', // dynamic sampling bias to keep transactions
6+
tracesSampleRate: 1.0, // Capture 100% of the transactions
7+
tunnel: 'http://localhost:3031/', // proxy server
8+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForTransaction } from '@sentry-internal/test-utils';
3+
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
4+
5+
test('sends a server action transaction on pageload', async ({ page }) => {
6+
const transactionPromise = waitForTransaction('nuxt-3', transactionEvent => {
7+
return transactionEvent.transaction.includes('GET /test-param/');
8+
});
9+
10+
await page.goto('/test-param/1234');
11+
12+
const transaction = await transactionPromise;
13+
14+
expect(transaction.contexts.trace).toEqual(
15+
expect.objectContaining({
16+
data: expect.objectContaining({
17+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
18+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.http',
19+
}),
20+
}),
21+
);
22+
});
23+
24+
test('does not send transactions for build asset folder "_nuxt"', async ({ page }) => {
25+
let buildAssetFolderOccurred = false;
26+
27+
waitForTransaction('nuxt-3', transactionEvent => {
28+
if (transactionEvent.transaction?.match(/^GET \/_nuxt\//)) {
29+
buildAssetFolderOccurred = true;
30+
}
31+
return false; // expects to return a boolean (but not relevant here)
32+
});
33+
34+
const transactionEventPromise = waitForTransaction('nuxt-3', transactionEvent => {
35+
return transactionEvent.transaction.includes('GET /test-param/');
36+
});
37+
38+
await page.goto('/test-param/1234');
39+
40+
const transactionEvent = await transactionEventPromise;
41+
42+
expect(buildAssetFolderOccurred).toBe(false);
43+
44+
// todo: url not yet parametrized
45+
expect(transactionEvent.transaction).toBe('GET /test-param/1234');
46+
});

packages/nuxt/src/server/sdk.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { applySdkMetadata } from '@sentry/core';
1+
import { applySdkMetadata, getGlobalScope } from '@sentry/core';
22
import { init as initNode } from '@sentry/node';
3-
import type { Client } from '@sentry/types';
3+
import type { Client, EventProcessor } from '@sentry/types';
44
import type { SentryNuxtOptions } from '../common/types';
55

66
/**
@@ -15,5 +15,30 @@ export function init(options: SentryNuxtOptions): Client | undefined {
1515

1616
applySdkMetadata(sentryOptions, 'nuxt', ['nuxt', 'node']);
1717

18-
return initNode(sentryOptions);
18+
const client = initNode(sentryOptions);
19+
20+
getGlobalScope().addEventProcessor(
21+
Object.assign(
22+
(event => {
23+
if (event.type === 'transaction') {
24+
// Filter out transactions for Nuxt build assets
25+
// This regex matches the default path to the nuxt-generated build assets (`_nuxt`).
26+
// todo: the buildAssetDir could be changed in the nuxt config - change this to a more generic solution
27+
if (event.transaction?.match(/^GET \/_nuxt\//)) {
28+
options.debug &&
29+
// eslint-disable-next-line no-console
30+
console.log('[Sentry] NuxtLowQualityTransactionsFilter filtered transaction: ', event.transaction);
31+
return null;
32+
}
33+
34+
return event;
35+
} else {
36+
return event;
37+
}
38+
}) satisfies EventProcessor,
39+
{ id: 'NuxtLowQualityTransactionsFilter' },
40+
),
41+
);
42+
43+
return client;
1944
}

packages/nuxt/test/server/sdk.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as SentryNode from '@sentry/node';
2+
import { SDK_VERSION } from '@sentry/node';
3+
import { beforeEach, describe, expect, it, vi } from 'vitest';
4+
import { init } from '../../src/server';
5+
6+
const nodeInit = vi.spyOn(SentryNode, 'init');
7+
8+
describe('Nuxt Server SDK', () => {
9+
describe('init', () => {
10+
beforeEach(() => {
11+
vi.clearAllMocks();
12+
});
13+
14+
it('Adds Nuxt metadata to the SDK options', () => {
15+
expect(nodeInit).not.toHaveBeenCalled();
16+
17+
init({
18+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
19+
});
20+
21+
const expectedMetadata = {
22+
_metadata: {
23+
sdk: {
24+
name: 'sentry.javascript.nuxt',
25+
version: SDK_VERSION,
26+
packages: [
27+
{ name: 'npm:@sentry/nuxt', version: SDK_VERSION },
28+
{ name: 'npm:@sentry/node', version: SDK_VERSION },
29+
],
30+
},
31+
},
32+
};
33+
34+
expect(nodeInit).toHaveBeenCalledTimes(1);
35+
expect(nodeInit).toHaveBeenLastCalledWith(expect.objectContaining(expectedMetadata));
36+
});
37+
38+
it('returns client from init', () => {
39+
expect(init({})).not.toBeUndefined();
40+
});
41+
});
42+
});

0 commit comments

Comments
 (0)
0