Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(browser): Move navigation span descriptions into op #13527

Merged
merged 9 commits into from
Sep 23, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ sentryTest('should add browser-related spans to pageload transaction', async ({
const url = await getLocalTestPath({ testDir: __dirname });

const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
const browserSpans = eventData.spans?.filter(({ op }) => op === 'browser');
const browserSpans = eventData.spans?.filter(({ op }) => op?.startsWith('browser'));

// Spans `domContentLoadedEvent`, `connect`, `cache` and `DNS` are not
// always inside `pageload` transaction.
Expand All @@ -21,7 +21,8 @@ sentryTest('should add browser-related spans to pageload transaction', async ({
['loadEvent', 'request', 'response'].forEach(eventDesc =>
expect(browserSpans).toContainEqual(
expect.objectContaining({
description: eventDesc,
op: `browser.${eventDesc}`,
description: page.url(),
parent_span_id: eventData.contexts?.trace?.span_id,
}),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ sentryTest('should add browser-related spans to pageload transaction', async ({
const url = await getLocalTestPath({ testDir: __dirname });

const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
const browserSpans = eventData.spans?.filter(({ op }) => op === 'browser');
const browserSpans = eventData.spans?.filter(({ op }) => op?.startsWith('browser'));

// Spans `domContentLoadedEvent`, `connect`, `cache` and `DNS` are not
// always inside `pageload` transaction.
expect(browserSpans?.length).toBeGreaterThanOrEqual(4);

const requestSpan = browserSpans!.find(({ description }) => description === 'request');
const requestSpan = browserSpans!.find(({ op }) => op === 'browser.request');
expect(requestSpan).toBeDefined();
expect(requestSpan?.description).toBe(page.url());

const measureSpan = eventData.spans?.find(({ op }) => op === 'measure');
expect(measureSpan).toBeDefined();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ test('Captures a pageload transaction', async ({ page }) => {
expect(transactionEvent.spans).toContainEqual({
data: {
'sentry.origin': 'auto.ui.browser.metrics',
'sentry.op': 'browser',
'sentry.op': 'browser.domContentLoadedEvent',
},
description: 'domContentLoadedEvent',
op: 'browser',
description: page.url(),
op: 'browser.domContentLoadedEvent',
parent_span_id: expect.any(String),
span_id: expect.any(String),
start_timestamp: expect.any(Number),
Expand All @@ -56,10 +56,10 @@ test('Captures a pageload transaction', async ({ page }) => {
expect(transactionEvent.spans).toContainEqual({
data: {
'sentry.origin': 'auto.ui.browser.metrics',
'sentry.op': 'browser',
'sentry.op': 'browser.connect',
},
description: 'connect',
op: 'browser',
description: page.url(),
op: 'browser.connect',
parent_span_id: expect.any(String),
span_id: expect.any(String),
start_timestamp: expect.any(Number),
Expand All @@ -70,10 +70,10 @@ test('Captures a pageload transaction', async ({ page }) => {
expect(transactionEvent.spans).toContainEqual({
data: {
'sentry.origin': 'auto.ui.browser.metrics',
'sentry.op': 'browser',
'sentry.op': 'browser.request',
},
description: 'request',
op: 'browser',
description: page.url(),
op: 'browser.request',
parent_span_id: expect.any(String),
span_id: expect.any(String),
start_timestamp: expect.any(Number),
Expand All @@ -84,10 +84,10 @@ test('Captures a pageload transaction', async ({ page }) => {
expect(transactionEvent.spans).toContainEqual({
data: {
'sentry.origin': 'auto.ui.browser.metrics',
'sentry.op': 'browser',
'sentry.op': 'browser.response',
},
description: 'response',
op: 'browser',
description: page.url(),
op: 'browser.response',
parent_span_id: expect.any(String),
span_id: expect.any(String),
start_timestamp: expect.any(Number),
Expand Down
12 changes: 6 additions & 6 deletions packages/browser-utils/src/metrics/browserMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,8 @@ function _addPerformanceNavigationTiming(
return;
}
startAndEndSpan(span, timeOrigin + msToSec(start), timeOrigin + msToSec(end), {
op: 'browser',
name: name || event,
op: `browser.${name || event}`,
name: entry.name,
Copy link
Member

@Lms24 Lms24 Aug 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: assigning the URL here makes the span name become high-cardinality. Are we aware of this? Does it have impact on Relay/grouping/etc? These are unparameterized, raw URLs. I assume they not only contain path parameters but also potentially query and hash params. We generally tried to stay as far away as possible from this because historically, it always led to problems (e.g. dynamic sampling consistency, transaction name grouping)
The raw urls can also contain all kinds of tokens and ids.
I'm not 100% against changing this, I just want to make sure we're aware of the implications.

I guess an alternative would be to just describe a bit what this span is doing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Lukas, a very valid point but it's something we are aware of! There's currently no grouping in Relay for browser spans, so the cardinality will not be an issue. However, we already have the functionality available to scrub/parameterize URLs, which we use for resource and HTTP spans, for example. My next step is to update Relay to scrub these browser spans so they can be grouped safely.

Putting something different and low cardinality in the description would not be as useful, since we'd be losing a lot of details when looking at the span summary.

attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',
},
Expand All @@ -497,16 +497,16 @@ function _addRequest(span: Span, entry: Record<string, any>, timeOrigin: number)
// In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect
// these spans when the responseEnd value is available. The backend (Relay) would drop the entire span if it contained faulty spans.
startAndEndSpan(span, requestStartTimestamp, responseEndTimestamp, {
op: 'browser',
name: 'request',
op: 'browser.request',
name: entry.name,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',
},
});

startAndEndSpan(span, responseStartTimestamp, responseEndTimestamp, {
op: 'browser',
name: 'response',
op: 'browser.response',
name: entry.name,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',
},
Expand Down
Loading