Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a0415aa

Browse files
authored
ref(browser): Create standalone INP spans via startInactiveSpan (#11788)
Refactors how we create INP spans. Previously we'd directly initialize a `SentrySpan` instance with the necessary properties and manually sample the span. Ironically, we heavily discourage directly initializing a `Span` class. With this change we leverage the `standalone: true` flag introduced in #11696. This way, we can also use the built-in sampling functionality and ensure that we only have one logic for creating standalone span envelopes. Also bundle size should decrease slightly 🤞 Adjusted the integration tests to more thoroughly test the INP span envelopes
1 parent 4b6cb4a commit a0415aa

File tree

2 files changed

+71
-55
lines changed
  • dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp
  • packages/browser-utils/src/metrics

2 files changed

+71
-55
lines changed

‎dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp/test.ts‎

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { expect } from '@playwright/test';
2-
import type { Event as SentryEvent, SpanJSON } from '@sentry/types';
2+
import type { Event as SentryEvent, SpanEnvelope,SpanJSON } from '@sentry/types';
33

44
import { sentryTest } from '../../../../utils/fixtures';
55
import {
66
getFirstSentryEnvelopeRequest,
77
getMultipleSentryEnvelopeRequests,
8+
properFullEnvelopeRequestParser,
89
shouldSkipTracingTest,
910
} from '../../../../utils/helpers';
1011

@@ -28,9 +29,12 @@ sentryTest('should capture an INP click event span.', async ({ browserName, getL
2829
await page.goto(url);
2930
await getFirstSentryEnvelopeRequest<SentryEvent>(page); // wait for page load
3031

31-
const spanEnvelopesPromise = getMultipleSentryEnvelopeRequests<SpanJSON>(page, 1, {
32-
envelopeType: 'span',
33-
});
32+
const spanEnvelopePromise = getMultipleSentryEnvelopeRequests<SpanEnvelope>(
33+
page,
34+
1,
35+
{ envelopeType: 'span' },
36+
properFullEnvelopeRequestParser,
37+
);
3438

3539
await page.locator('[data-test-id=normal-button]').click();
3640
await page.locator('.clicked[data-test-id=normal-button]').isVisible();
@@ -43,14 +47,53 @@ sentryTest('should capture an INP click event span.', async ({ browserName, getL
4347
});
4448

4549
// Get the INP span envelope
46-
const spanEnvelopes = await spanEnvelopesPromise;
47-
48-
expect(spanEnvelopes).toHaveLength(1);
49-
expect(spanEnvelopes[0].op).toBe('ui.interaction.click');
50-
expect(spanEnvelopes[0].description).toBe('body > NormalButton');
51-
expect(spanEnvelopes[0].exclusive_time).toBeGreaterThan(0);
52-
expect(spanEnvelopes[0].measurements?.inp.value).toBeGreaterThan(0);
53-
expect(spanEnvelopes[0].measurements?.inp.unit).toBe('millisecond');
50+
const spanEnvelope = (await spanEnvelopePromise)[0];
51+
52+
const spanEnvelopeHeaders = spanEnvelope[0];
53+
const spanEnvelopeItem = spanEnvelope[1][0][1];
54+
55+
const traceId = spanEnvelopeHeaders.trace!.trace_id;
56+
expect(traceId).toMatch(/[a-f0-9]{32}/);
57+
58+
expect(spanEnvelopeHeaders).toEqual({
59+
sent_at: expect.any(String),
60+
trace: {
61+
environment: 'production',
62+
public_key: 'public',
63+
sample_rate: '1',
64+
sampled: 'true',
65+
trace_id: traceId,
66+
},
67+
});
68+
69+
const inpValue = spanEnvelopeItem.measurements?.inp.value;
70+
expect(inpValue).toBeGreaterThan(0);
71+
72+
expect(spanEnvelopeItem).toEqual({
73+
data: {
74+
'sentry.exclusive_time': inpValue,
75+
'sentry.op': 'ui.interaction.click',
76+
'sentry.origin': 'manual',
77+
'sentry.sample_rate': 1,
78+
'sentry.source': 'custom',
79+
},
80+
measurements: {
81+
inp: {
82+
unit: 'millisecond',
83+
value: inpValue,
84+
},
85+
},
86+
description: 'body > NormalButton',
87+
exclusive_time: inpValue,
88+
op: 'ui.interaction.click',
89+
origin: 'manual',
90+
is_segment: true,
91+
segment_id: spanEnvelopeItem.span_id,
92+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
93+
start_timestamp: expect.any(Number),
94+
timestamp: expect.any(Number),
95+
trace_id: traceId,
96+
});
5497
});
5598

5699
sentryTest(
@@ -85,7 +128,7 @@ sentryTest(
85128

86129
await page.waitForTimeout(500);
87130

88-
const spanEnvelopesPromise = getMultipleSentryEnvelopeRequests<SpanJSON>(page, 1, {
131+
const spanPromise = getMultipleSentryEnvelopeRequests<SpanJSON>(page, 1, {
89132
envelopeType: 'span',
90133
});
91134

@@ -95,13 +138,12 @@ sentryTest(
95138
});
96139

97140
// Get the INP span envelope
98-
const spanEnvelopes = await spanEnvelopesPromise;
99-
100-
expect(spanEnvelopes).toHaveLength(1);
101-
expect(spanEnvelopes[0].op).toBe('ui.interaction.click');
102-
expect(spanEnvelopes[0].description).toBe('body > SlowButton');
103-
expect(spanEnvelopes[0].exclusive_time).toBeGreaterThan(400);
104-
expect(spanEnvelopes[0].measurements?.inp.value).toBeGreaterThan(400);
105-
expect(spanEnvelopes[0].measurements?.inp.unit).toBe('millisecond');
141+
const span = (await spanPromise)[0];
142+
143+
expect(span.op).toBe('ui.interaction.click');
144+
expect(span.description).toBe('body > SlowButton');
145+
expect(span.exclusive_time).toBeGreaterThan(400);
146+
expect(span.measurements?.inp.value).toBeGreaterThan(400);
147+
expect(span.measurements?.inp.unit).toBe('millisecond');
106148
},
107149
);

‎packages/browser-utils/src/metrics/inp.ts‎

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,15 @@ import {
22
SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,
33
SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,
44
SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,
5-
SentrySpan,
6-
createSpanEnvelope,
75
getActiveSpan,
86
getClient,
97
getCurrentScope,
108
getRootSpan,
11-
sampleSpan,
12-
spanIsSampled,
139
spanToJSON,
10+
startInactiveSpan,
1411
} from '@sentry/core';
1512
import type { Integration, SpanAttributes } from '@sentry/types';
16-
import { browserPerformanceTimeOrigin, dropUndefinedKeys, htmlTreeAsString, logger } from '@sentry/utils';
17-
import { DEBUG_BUILD } from '../debug-build';
13+
import { browserPerformanceTimeOrigin, dropUndefinedKeys, htmlTreeAsString } from '@sentry/utils';
1814
import { addInpInstrumentationHandler } from './instrument';
1915
import { getBrowserPerformanceAPI, msToSec } from './utils';
2016

@@ -100,7 +96,6 @@ function _trackINP(): () => void {
10096
const profileId = scope.getScopeData().contexts?.profile?.profile_id as string | undefined;
10197

10298
const name = htmlTreeAsString(entry.target);
103-
const parentSampled = activeSpan ? spanIsSampled(activeSpan) : undefined;
10499
const attributes: SpanAttributes = dropUndefinedKeys({
105100
release: options.release,
106101
environment: options.environment,
@@ -111,42 +106,21 @@ function _trackINP(): () => void {
111106
replay_id: replayId || undefined,
112107
});
113108

114-
/** Check to see if the span should be sampled */
115-
const [sampled] = sampleSpan(options, {
109+
const span = startInactiveSpan({
116110
name,
117-
parentSampled,
118-
attributes,
119-
transactionContext: {
120-
name,
121-
parentSampled,
122-
},
123-
});
124-
125-
// Nothing to do
126-
if (!sampled) {
127-
return;
128-
}
129-
130-
const span = new SentrySpan({
131-
startTimestamp: startTime,
132-
endTimestamp: startTime + duration,
133111
op: `ui.interaction.${interactionType}`,
134-
name,
135112
attributes,
113+
startTime: startTime,
114+
experimental: {
115+
standalone: true,
116+
},
136117
});
137118

138119
span.addEvent('inp', {
139120
[SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond',
140121
[SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: metric.value,
141122
});
142123

143-
const envelope = createSpanEnvelope([span]);
144-
const transport = client && client.getTransport();
145-
if (transport) {
146-
transport.send(envelope).then(null, reason => {
147-
DEBUG_BUILD && logger.error('Error while sending interaction:', reason);
148-
});
149-
}
150-
return;
124+
span.end(startTime + duration);
151125
});
152126
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /