From f42b94590a991b58a7a75e0ca8ca6c246e8174eb Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 26 May 2025 10:43:55 -0400 Subject: [PATCH 1/6] feat(browser): option to ignore certain resource types --- .../resource-spans-ignored/init.js | 13 +++++ .../resource-spans-ignored/test.ts | 21 ++++++++ .../src/metrics/browserMetrics.ts | 17 ++++++- .../test/browser/browserMetrics.test.ts | 48 +++++++++++++++++++ .../src/tracing/browserTracingIntegration.ts | 11 ++++- 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js new file mode 100644 index 000000000000..d8003898290b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js @@ -0,0 +1,13 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [ + Sentry.browserTracingIntegration({ + ignoreResourceSpans: ['resource.script'] + }), + ], + tracesSampleRate: 1, +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts new file mode 100644 index 000000000000..5e62ba7aeb27 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts @@ -0,0 +1,21 @@ +import type { Route } from '@playwright/test'; +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/core'; +import { sentryTest } from '../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; + +sentryTest( + 'should allow specific types of resource spans to be ignored.', + async ({ getLocalTestUrl, page }) => { + await page.route('**/path/to/script.js', (route: Route) => + route.fulfill({ path: `${__dirname}/assets/script.js` }), + ); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + const uiSpans = eventData.spans?.filter(({ op }) => op?.startsWith('resource.script')); + + expect(uiSpans?.length).toBe(0); + }, +); diff --git a/packages/browser-utils/src/metrics/browserMetrics.ts b/packages/browser-utils/src/metrics/browserMetrics.ts index 71470a0d8706..1d5e805fb02f 100644 --- a/packages/browser-utils/src/metrics/browserMetrics.ts +++ b/packages/browser-utils/src/metrics/browserMetrics.ts @@ -300,6 +300,13 @@ interface AddPerformanceEntriesOptions { * sent as a standalone span instead. */ recordClsOnPageloadSpan: boolean; + + /** + * Resource spans matching strings in the array will not be emitted. + * + * Default: [] + */ + ignoreResourceSpans: Array; } /** Add performance related spans to a transaction */ @@ -355,7 +362,7 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries break; } case 'resource': { - _addResourceSpans(span, entry as PerformanceResourceTiming, entry.name, startTime, duration, timeOrigin); + _addResourceSpans(span, entry as PerformanceResourceTiming, entry.name, startTime, duration, timeOrigin, options.ignoreResourceSpans); break; } // Ignore other entry types. @@ -568,6 +575,7 @@ export function _addResourceSpans( startTime: number, duration: number, timeOrigin: number, + ignoreResourceSpans?: Array ): void { // we already instrument based on fetch and xhr, so we don't need to // duplicate spans here. @@ -575,6 +583,11 @@ export function _addResourceSpans( return; } + const op = entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other'; + if (ignoreResourceSpans?.includes(op)) { + return; + } + const parsedUrl = parseUrl(resourceUrl); const attributes: SpanAttributes = { @@ -616,7 +629,7 @@ export function _addResourceSpans( startAndEndSpan(span, startTimestamp, endTimestamp, { name: resourceUrl.replace(WINDOW.location.origin, ''), - op: entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other', + op, attributes, }); } diff --git a/packages/browser-utils/test/browser/browserMetrics.test.ts b/packages/browser-utils/test/browser/browserMetrics.test.ts index 99cf451f824e..0f3cebd631f5 100644 --- a/packages/browser-utils/test/browser/browserMetrics.test.ts +++ b/packages/browser-utils/test/browser/browserMetrics.test.ts @@ -271,6 +271,54 @@ describe('_addResourceSpans', () => { } }); + it('allows resource spans to be ignored via ignoreResourceSpans', () => { + const spans: Span[] = []; + const ignoredResourceSpans = [ + 'resource.other', + 'resource.script' + ]; + + getClient()?.on('spanEnd', span => { + spans.push(span); + }); + + const table = [ + { + initiatorType: undefined, + op: 'resource.other', + }, + { + initiatorType: 'css', + op: 'resource.css', + }, + { + initiatorType: 'css', + op: 'resource.css', + }, + { + initiatorType: 'image', + op: 'resource.image', + }, + { + initiatorType: 'script', + op: 'resource.script', + }, + ]; + for (const row of table) { + const { initiatorType } = row; + const entry = mockPerformanceResourceTiming({ + initiatorType, + nextHopProtocol: 'http/1.1', + }); + _addResourceSpans(span, entry, 'https://example.com/assets/to/me', 123, 234, 465, ignoredResourceSpans); + } + expect(spans).toHaveLength(table.length - ignoredResourceSpans.length); + const spanOps = new Set(spans.map((s) => { + return spanToJSON(s).op; + })); + expect(spanOps).toEqual(new Set(['resource.css', 'resource.image'])); + }); + it('allows for enter size of 0', () => { const spans: Span[] = []; diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index d31fe41742f8..3fd8a1e05e67 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -144,6 +144,13 @@ export interface BrowserTracingOptions { */ enableHTTPTimings: boolean; + /** + * Resource spans matching strings in the array will not be emitted. + * + * Default: [] + */ + ignoreResourceSpans: Array; + /** * Link the currently started trace to a previous trace (e.g. a prior pageload, navigation or * manually started span). When enabled, this option will allow you to navigate between traces @@ -226,6 +233,7 @@ const DEFAULT_BROWSER_TRACING_OPTIONS: BrowserTracingOptions = { enableLongTask: true, enableLongAnimationFrame: true, enableInp: true, + ignoreResourceSpans: [], linkPreviousTrace: 'in-memory', consistentTraceSampling: false, _experiments: {}, @@ -268,6 +276,7 @@ export const browserTracingIntegration = ((_options: Partial Date: Mon, 26 May 2025 10:46:48 -0400 Subject: [PATCH 2/6] chore: fix linting --- .../resource-spans-ignored/init.js | 2 +- .../resource-spans-ignored/test.ts | 19 +++++++------------ .../src/metrics/browserMetrics.ts | 12 ++++++++++-- .../test/browser/browserMetrics.test.ts | 13 ++++++------- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js index d8003898290b..3a4c2cb1cdf4 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js @@ -6,7 +6,7 @@ Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', integrations: [ Sentry.browserTracingIntegration({ - ignoreResourceSpans: ['resource.script'] + ignoreResourceSpans: ['resource.script'], }), ], tracesSampleRate: 1, diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts index 5e62ba7aeb27..c0fad1adb34a 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts @@ -4,18 +4,13 @@ import type { Event } from '@sentry/core'; import { sentryTest } from '../../../../utils/fixtures'; import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; -sentryTest( - 'should allow specific types of resource spans to be ignored.', - async ({ getLocalTestUrl, page }) => { - await page.route('**/path/to/script.js', (route: Route) => - route.fulfill({ path: `${__dirname}/assets/script.js` }), - ); +sentryTest('should allow specific types of resource spans to be ignored.', async ({ getLocalTestUrl, page }) => { + await page.route('**/path/to/script.js', (route: Route) => route.fulfill({ path: `${__dirname}/assets/script.js` })); - const url = await getLocalTestUrl({ testDir: __dirname }); + const url = await getLocalTestUrl({ testDir: __dirname }); - const eventData = await getFirstSentryEnvelopeRequest(page, url); - const uiSpans = eventData.spans?.filter(({ op }) => op?.startsWith('resource.script')); + const eventData = await getFirstSentryEnvelopeRequest(page, url); + const uiSpans = eventData.spans?.filter(({ op }) => op?.startsWith('resource.script')); - expect(uiSpans?.length).toBe(0); - }, -); + expect(uiSpans?.length).toBe(0); +}); diff --git a/packages/browser-utils/src/metrics/browserMetrics.ts b/packages/browser-utils/src/metrics/browserMetrics.ts index 1d5e805fb02f..7f3f13eda0b6 100644 --- a/packages/browser-utils/src/metrics/browserMetrics.ts +++ b/packages/browser-utils/src/metrics/browserMetrics.ts @@ -362,7 +362,15 @@ export function addPerformanceEntries(span: Span, options: AddPerformanceEntries break; } case 'resource': { - _addResourceSpans(span, entry as PerformanceResourceTiming, entry.name, startTime, duration, timeOrigin, options.ignoreResourceSpans); + _addResourceSpans( + span, + entry as PerformanceResourceTiming, + entry.name, + startTime, + duration, + timeOrigin, + options.ignoreResourceSpans, + ); break; } // Ignore other entry types. @@ -575,7 +583,7 @@ export function _addResourceSpans( startTime: number, duration: number, timeOrigin: number, - ignoreResourceSpans?: Array + ignoreResourceSpans?: Array, ): void { // we already instrument based on fetch and xhr, so we don't need to // duplicate spans here. diff --git a/packages/browser-utils/test/browser/browserMetrics.test.ts b/packages/browser-utils/test/browser/browserMetrics.test.ts index 0f3cebd631f5..87646a690f0e 100644 --- a/packages/browser-utils/test/browser/browserMetrics.test.ts +++ b/packages/browser-utils/test/browser/browserMetrics.test.ts @@ -273,10 +273,7 @@ describe('_addResourceSpans', () => { it('allows resource spans to be ignored via ignoreResourceSpans', () => { const spans: Span[] = []; - const ignoredResourceSpans = [ - 'resource.other', - 'resource.script' - ]; + const ignoredResourceSpans = ['resource.other', 'resource.script']; getClient()?.on('spanEnd', span => { spans.push(span); @@ -313,9 +310,11 @@ describe('_addResourceSpans', () => { _addResourceSpans(span, entry, 'https://example.com/assets/to/me', 123, 234, 465, ignoredResourceSpans); } expect(spans).toHaveLength(table.length - ignoredResourceSpans.length); - const spanOps = new Set(spans.map((s) => { - return spanToJSON(s).op; - })); + const spanOps = new Set( + spans.map(s => { + return spanToJSON(s).op; + }), + ); expect(spanOps).toEqual(new Set(['resource.css', 'resource.image'])); }); From 57311d414a9c63c61d6ebf63f245245edef69bb0 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 26 May 2025 10:50:22 -0400 Subject: [PATCH 3/6] test: uiSpans are actually allSpans --- .../browserTracingIntegration/resource-spans-ignored/test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts index c0fad1adb34a..b15f89ed1d83 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts @@ -10,7 +10,7 @@ sentryTest('should allow specific types of resource spans to be ignored.', async const url = await getLocalTestUrl({ testDir: __dirname }); const eventData = await getFirstSentryEnvelopeRequest(page, url); - const uiSpans = eventData.spans?.filter(({ op }) => op?.startsWith('resource.script')); + const allSpans = eventData.spans?.filter(({ op }) => op?.startsWith('resource.script')); - expect(uiSpans?.length).toBe(0); + expect(allSpans?.length).toBe(0); }); From d2bbd018aa08cb51bc6bef01623c88855d23cff3 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 26 May 2025 11:47:06 -0400 Subject: [PATCH 4/6] test: address failing tst --- .../resource-spans-ignored/assets/script.js | 3 +++ .../resource-spans-ignored/init.js | 1 + .../resource-spans-ignored/test.ts | 6 +++++- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/assets/script.js diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/assets/script.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/assets/script.js new file mode 100644 index 000000000000..eab583b75a75 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/assets/script.js @@ -0,0 +1,3 @@ +(() => { + // I do nothing. +})(); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js index 3a4c2cb1cdf4..70c0b30a03a5 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/init.js @@ -7,6 +7,7 @@ Sentry.init({ integrations: [ Sentry.browserTracingIntegration({ ignoreResourceSpans: ['resource.script'], + idleTimeout: 9000, }), ], tracesSampleRate: 1, diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts index b15f89ed1d83..4bc9621f8395 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/resource-spans-ignored/test.ts @@ -2,9 +2,13 @@ import type { Route } from '@playwright/test'; import { expect } from '@playwright/test'; import type { Event } from '@sentry/core'; import { sentryTest } from '../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; +import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; sentryTest('should allow specific types of resource spans to be ignored.', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + await page.route('**/path/to/script.js', (route: Route) => route.fulfill({ path: `${__dirname}/assets/script.js` })); const url = await getLocalTestUrl({ testDir: __dirname }); From 644a3abd48c7fb5234eb997dfc393af2ddedcff9 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Mon, 26 May 2025 12:22:06 -0400 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Lukas Stracke --- packages/browser-utils/src/metrics/browserMetrics.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/browser-utils/src/metrics/browserMetrics.ts b/packages/browser-utils/src/metrics/browserMetrics.ts index 7f3f13eda0b6..764e4ddc8bc4 100644 --- a/packages/browser-utils/src/metrics/browserMetrics.ts +++ b/packages/browser-utils/src/metrics/browserMetrics.ts @@ -302,11 +302,11 @@ interface AddPerformanceEntriesOptions { recordClsOnPageloadSpan: boolean; /** - * Resource spans matching strings in the array will not be emitted. + * Resource spans with `op`s matching strings in the array will not be emitted. * * Default: [] */ - ignoreResourceSpans: Array; + ignoreResourceSpans: Array<'resouce.script' | 'resource.css' | 'resource.img' | 'resource.other' | string >; } /** Add performance related spans to a transaction */ From fbdbf6055d708774f713b8f508823f351160bd8f Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 26 May 2025 12:25:30 -0400 Subject: [PATCH 6/6] test: fix linting --- packages/browser-utils/src/metrics/browserMetrics.ts | 2 +- packages/browser/src/tracing/browserTracingIntegration.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/browser-utils/src/metrics/browserMetrics.ts b/packages/browser-utils/src/metrics/browserMetrics.ts index 764e4ddc8bc4..d5ca039c65f0 100644 --- a/packages/browser-utils/src/metrics/browserMetrics.ts +++ b/packages/browser-utils/src/metrics/browserMetrics.ts @@ -306,7 +306,7 @@ interface AddPerformanceEntriesOptions { * * Default: [] */ - ignoreResourceSpans: Array<'resouce.script' | 'resource.css' | 'resource.img' | 'resource.other' | string >; + ignoreResourceSpans: Array<'resouce.script' | 'resource.css' | 'resource.img' | 'resource.other' | string>; } /** Add performance related spans to a transaction */ diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index 3fd8a1e05e67..3f38bdb6a8be 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -145,7 +145,7 @@ export interface BrowserTracingOptions { enableHTTPTimings: boolean; /** - * Resource spans matching strings in the array will not be emitted. + * Resource spans with `op`s matching strings in the array will not be emitted. * * Default: [] */