Skip to content

Commit 708c73e

Browse files
authored
Merge pull request #16931 from getsentry/prepare-release/9.38.0
meta(changelog): Update changelog for 9.38.0
2 parents 8697908 + ccf61b2 commit 708c73e

File tree

65 files changed

+602
-375
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+602
-375
lines changed

.craft.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ targets:
4646
- name: npm
4747
id: '@sentry/profiling-node'
4848
includeNames: /^sentry-profiling-node-\d.*\.tgz$/
49+
- name: npm
50+
id: '@sentry/node-native'
51+
includeNames: /^sentry-node-native-\d.*\.tgz$/
4952

5053
## 3 Browser-based Packages
5154
- name: npm

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7+
## 9.38.0
8+
9+
### Important Changes
10+
11+
- **chore: Add craft entry for @sentry/node-native ([#16907](https://github.com/getsentry/sentry-javascript/pull/16907))**
12+
13+
This release publishes the `@sentry/node-native` SDK.
14+
15+
### Other Changes
16+
17+
- feat(core): Introduce `debug` to replace `logger` ([#16906](https://github.com/getsentry/sentry-javascript/pull/16906))
18+
- fix(browser): Guard `nextHopProtocol` when adding resource spans ([#16900](https://github.com/getsentry/sentry-javascript/pull/16900))
19+
720
## 9.37.0
821

922
### Important Changes

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/linked-traces/consistent-sampling/meta-precedence/test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ sentryTest.describe('When `consistentTraceSampling` is `true` and page contains
2525
sentryTest.skip();
2626
}
2727

28-
29-
30-
3128
const url = await getLocalTestUrl({ testDir: __dirname });
3229

3330
const clientReportPromise = waitForClientReportRequest(page);

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-cls-standalone-spans/test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ sentryTest('captures a "GOOD" CLS vital with its source as a standalone span', a
6565
'sentry.exclusive_time': 0,
6666
'sentry.op': 'ui.webvital.cls',
6767
'sentry.origin': 'auto.http.browser.cls',
68+
'sentry.report_event': 'pagehide',
6869
transaction: expect.stringContaining('index.html'),
6970
'user_agent.original': expect.stringContaining('Chrome'),
7071
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
@@ -134,6 +135,7 @@ sentryTest('captures a "MEH" CLS vital with its source as a standalone span', as
134135
'sentry.exclusive_time': 0,
135136
'sentry.op': 'ui.webvital.cls',
136137
'sentry.origin': 'auto.http.browser.cls',
138+
'sentry.report_event': 'pagehide',
137139
transaction: expect.stringContaining('index.html'),
138140
'user_agent.original': expect.stringContaining('Chrome'),
139141
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
@@ -201,6 +203,7 @@ sentryTest('captures a "POOR" CLS vital with its source as a standalone span.',
201203
'sentry.exclusive_time': 0,
202204
'sentry.op': 'ui.webvital.cls',
203205
'sentry.origin': 'auto.http.browser.cls',
206+
'sentry.report_event': 'pagehide',
204207
transaction: expect.stringContaining('index.html'),
205208
'user_agent.original': expect.stringContaining('Chrome'),
206209
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
@@ -269,6 +272,7 @@ sentryTest(
269272
'sentry.exclusive_time': 0,
270273
'sentry.op': 'ui.webvital.cls',
271274
'sentry.origin': 'auto.http.browser.cls',
275+
'sentry.report_event': 'pagehide',
272276
transaction: expect.stringContaining('index.html'),
273277
'user_agent.original': expect.stringContaining('Chrome'),
274278
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
@@ -342,6 +346,8 @@ sentryTest(
342346
// Ensure the CLS span is connected to the pageload span and trace
343347
expect(spanEnvelopeItem.data?.['sentry.pageload.span_id']).toBe(pageloadSpanId);
344348
expect(spanEnvelopeItem.trace_id).toEqual(pageloadTraceId);
349+
350+
expect(spanEnvelopeItem.data?.['sentry.report_event']).toBe('pagehide');
345351
},
346352
);
347353

@@ -374,6 +380,8 @@ sentryTest('sends CLS of the initial page when soft-navigating to a new page', a
374380
expect(spanEnvelopeItem.measurements?.cls?.value).toBeLessThan(0.15);
375381
expect(spanEnvelopeItem.data?.['sentry.pageload.span_id']).toBe(pageloadEventData.contexts?.trace?.span_id);
376382
expect(spanEnvelopeItem.trace_id).toEqual(pageloadTraceId);
383+
384+
expect(spanEnvelopeItem.data?.['sentry.report_event']).toBe('navigation');
377385
});
378386

379387
sentryTest("doesn't send further CLS after the first navigation", async ({ getLocalTestUrl, page }) => {
@@ -398,6 +406,7 @@ sentryTest("doesn't send further CLS after the first navigation", async ({ getLo
398406
const spanEnvelope = (await spanEnvelopePromise)[0];
399407
const spanEnvelopeItem = spanEnvelope[1][0][1];
400408
expect(spanEnvelopeItem.measurements?.cls?.value).toBeGreaterThan(0);
409+
expect(spanEnvelopeItem.data?.['sentry.report_event']).toBe('navigation');
401410

402411
getMultipleSentryEnvelopeRequests<SpanEnvelope>(page, 1, { envelopeType: 'span' }, () => {
403412
throw new Error('Unexpected span - This should not happen!');
@@ -442,6 +451,7 @@ sentryTest("doesn't send further CLS after the first page hide", async ({ getLoc
442451
const spanEnvelope = (await spanEnvelopePromise)[0];
443452
const spanEnvelopeItem = spanEnvelope[1][0][1];
444453
expect(spanEnvelopeItem.measurements?.cls?.value).toBeGreaterThan(0);
454+
expect(spanEnvelopeItem.data?.['sentry.report_event']).toBe('pagehide');
445455

446456
getMultipleSentryEnvelopeRequests<SpanEnvelope>(page, 1, { envelopeType: 'span' }, () => {
447457
throw new Error('Unexpected span - This should not happen!');

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-lcp-standalone-spans/test.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ sentryTest('captures LCP vital as a standalone span', async ({ getLocalTestUrl,
6464
'sentry.exclusive_time': 0,
6565
'sentry.op': 'ui.webvital.lcp',
6666
'sentry.origin': 'auto.http.browser.lcp',
67+
'sentry.report_event': 'pagehide',
6768
transaction: expect.stringContaining('index.html'),
6869
'user_agent.original': expect.stringContaining('Chrome'),
6970
'sentry.pageload.span_id': expect.stringMatching(/[a-f0-9]{16}/),
@@ -181,6 +182,7 @@ sentryTest('sends LCP of the initial page when soft-navigating to a new page', a
181182

182183
expect(spanEnvelopeItem.measurements?.lcp?.value).toBeGreaterThan(0);
183184
expect(spanEnvelopeItem.data?.['sentry.pageload.span_id']).toBe(pageloadEventData.contexts?.trace?.span_id);
185+
expect(spanEnvelopeItem.data?.['sentry.report_event']).toBe('navigation');
184186
expect(spanEnvelopeItem.trace_id).toBe(pageloadEventData.contexts?.trace?.trace_id);
185187
});
186188

@@ -194,10 +196,10 @@ sentryTest("doesn't send further LCP after the first navigation", async ({ getLo
194196

195197
const url = await getLocalTestUrl({ testDir: __dirname });
196198

197-
const eventData = await getFirstSentryEnvelopeRequest<SentryEvent>(page, url);
199+
const pageloadEventData = await getFirstSentryEnvelopeRequest<SentryEvent>(page, url);
198200

199-
expect(eventData.type).toBe('transaction');
200-
expect(eventData.contexts?.trace?.op).toBe('pageload');
201+
expect(pageloadEventData.type).toBe('transaction');
202+
expect(pageloadEventData.contexts?.trace?.op).toBe('pageload');
201203

202204
const spanEnvelopePromise = getMultipleSentryEnvelopeRequests<SpanEnvelope>(
203205
page,
@@ -214,6 +216,8 @@ sentryTest("doesn't send further LCP after the first navigation", async ({ getLo
214216
const spanEnvelope = (await spanEnvelopePromise)[0];
215217
const spanEnvelopeItem = spanEnvelope[1][0][1];
216218
expect(spanEnvelopeItem.measurements?.lcp?.value).toBeGreaterThan(0);
219+
expect(spanEnvelopeItem.data?.['sentry.report_event']).toBe('navigation');
220+
expect(spanEnvelopeItem.trace_id).toBe(pageloadEventData.contexts?.trace?.trace_id);
217221

218222
getMultipleSentryEnvelopeRequests<SpanEnvelope>(page, 1, { envelopeType: 'span' }, () => {
219223
throw new Error('Unexpected span - This should not happen!');
@@ -246,10 +250,10 @@ sentryTest("doesn't send further LCP after the first page hide", async ({ getLoc
246250

247251
const url = await getLocalTestUrl({ testDir: __dirname });
248252

249-
const eventData = await getFirstSentryEnvelopeRequest<SentryEvent>(page, url);
253+
const pageloadEventData = await getFirstSentryEnvelopeRequest<SentryEvent>(page, url);
250254

251-
expect(eventData.type).toBe('transaction');
252-
expect(eventData.contexts?.trace?.op).toBe('pageload');
255+
expect(pageloadEventData.type).toBe('transaction');
256+
expect(pageloadEventData.contexts?.trace?.op).toBe('pageload');
253257

254258
const spanEnvelopePromise = getMultipleSentryEnvelopeRequests<SpanEnvelope>(
255259
page,
@@ -266,6 +270,8 @@ sentryTest("doesn't send further LCP after the first page hide", async ({ getLoc
266270
const spanEnvelope = (await spanEnvelopePromise)[0];
267271
const spanEnvelopeItem = spanEnvelope[1][0][1];
268272
expect(spanEnvelopeItem.measurements?.lcp?.value).toBeGreaterThan(0);
273+
expect(spanEnvelopeItem.data?.['sentry.report_event']).toBe('pagehide');
274+
expect(spanEnvelopeItem.trace_id).toBe(pageloadEventData.contexts?.trace?.trace_id);
269275

270276
getMultipleSentryEnvelopeRequests<SpanEnvelope>(page, 1, { envelopeType: 'span' }, () => {
271277
throw new Error('Unexpected span - This should not happen!');

packages/browser-utils/src/metrics/browserMetrics.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -715,9 +715,13 @@ export function _addResourceSpans(
715715

716716
attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);
717717

718-
const { name, version } = extractNetworkProtocol(entry.nextHopProtocol);
719-
attributes['network.protocol.name'] = name;
720-
attributes['network.protocol.version'] = version;
718+
// Checking for only `undefined` and `null` is intentional because it's
719+
// valid for `nextHopProtocol` to be an empty string.
720+
if (entry.nextHopProtocol != null) {
721+
const { name, version } = extractNetworkProtocol(entry.nextHopProtocol);
722+
attributes['network.protocol.name'] = name;
723+
attributes['network.protocol.version'] = version;
724+
}
721725

722726
const startTimestamp = timeOrigin + startTime;
723727
const endTimestamp = startTimestamp + duration;
Lines changed: 14 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
import type { SpanAttributes } from '@sentry/core';
22
import {
33
browserPerformanceTimeOrigin,
4-
getActiveSpan,
5-
getClient,
64
getCurrentScope,
7-
getRootSpan,
85
htmlTreeAsString,
96
logger,
107
SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME,
118
SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT,
129
SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,
1310
SEMANTIC_ATTRIBUTE_SENTRY_OP,
1411
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
15-
spanToJSON,
1612
} from '@sentry/core';
1713
import { DEBUG_BUILD } from '../debug-build';
1814
import { addClsInstrumentationHandler } from './instrument';
19-
import { msToSec, startStandaloneWebVitalSpan } from './utils';
20-
import { onHidden } from './web-vitals/lib/onHidden';
15+
import type { WebVitalReportEvent } from './utils';
16+
import { listenForWebVitalReportEvents, msToSec, startStandaloneWebVitalSpan, supportsWebVital } from './utils';
2117

2218
/**
2319
* Starts tracking the Cumulative Layout Shift on the current page and collects the value once
@@ -31,24 +27,11 @@ import { onHidden } from './web-vitals/lib/onHidden';
3127
export function trackClsAsStandaloneSpan(): void {
3228
let standaloneCLsValue = 0;
3329
let standaloneClsEntry: LayoutShift | undefined;
34-
let pageloadSpanId: string | undefined;
3530

36-
if (!supportsLayoutShift()) {
31+
if (!supportsWebVital('layout-shift')) {
3732
return;
3833
}
3934

40-
let sentSpan = false;
41-
function _collectClsOnce() {
42-
if (sentSpan) {
43-
return;
44-
}
45-
sentSpan = true;
46-
if (pageloadSpanId) {
47-
sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId);
48-
}
49-
cleanupClsHandler();
50-
}
51-
5235
const cleanupClsHandler = addClsInstrumentationHandler(({ metric }) => {
5336
const entry = metric.entries[metric.entries.length - 1] as LayoutShift | undefined;
5437
if (!entry) {
@@ -58,40 +41,18 @@ export function trackClsAsStandaloneSpan(): void {
5841
standaloneClsEntry = entry;
5942
}, true);
6043

61-
onHidden(() => {
62-
_collectClsOnce();
44+
listenForWebVitalReportEvents((reportEvent, pageloadSpanId) => {
45+
sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId, reportEvent);
46+
cleanupClsHandler();
6347
});
64-
65-
// Since the call chain of this function is synchronous and evaluates before the SDK client is created,
66-
// we need to wait with subscribing to a client hook until the client is created. Therefore, we defer
67-
// to the next tick after the SDK setup.
68-
setTimeout(() => {
69-
const client = getClient();
70-
71-
if (!client) {
72-
return;
73-
}
74-
75-
const unsubscribeStartNavigation = client.on('beforeStartNavigationSpan', (_, options) => {
76-
// we only want to collect LCP if we actually navigate. Redirects should be ignored.
77-
if (!options?.isRedirect) {
78-
_collectClsOnce();
79-
unsubscribeStartNavigation?.();
80-
}
81-
});
82-
83-
const activeSpan = getActiveSpan();
84-
if (activeSpan) {
85-
const rootSpan = getRootSpan(activeSpan);
86-
const spanJSON = spanToJSON(rootSpan);
87-
if (spanJSON.op === 'pageload') {
88-
pageloadSpanId = rootSpan.spanContext().spanId;
89-
}
90-
}
91-
}, 0);
9248
}
9349

94-
function sendStandaloneClsSpan(clsValue: number, entry: LayoutShift | undefined, pageloadSpanId: string) {
50+
function sendStandaloneClsSpan(
51+
clsValue: number,
52+
entry: LayoutShift | undefined,
53+
pageloadSpanId: string,
54+
reportEvent: WebVitalReportEvent,
55+
) {
9556
DEBUG_BUILD && logger.log(`Sending CLS span (${clsValue})`);
9657

9758
const startTime = msToSec((browserPerformanceTimeOrigin() || 0) + (entry?.startTime || 0));
@@ -105,6 +66,8 @@ function sendStandaloneClsSpan(clsValue: number, entry: LayoutShift | undefined,
10566
[SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration || 0,
10667
// attach the pageload span id to the CLS span so that we can link them in the UI
10768
'sentry.pageload.span_id': pageloadSpanId,
69+
// describes what triggered the web vital to be reported
70+
'sentry.report_event': reportEvent,
10871
};
10972

11073
// Add CLS sources as span attributes to help with debugging layout shifts
@@ -133,11 +96,3 @@ function sendStandaloneClsSpan(clsValue: number, entry: LayoutShift | undefined,
13396
span.end(startTime);
13497
}
13598
}
136-
137-
function supportsLayoutShift(): boolean {
138-
try {
139-
return PerformanceObserver.supportedEntryTypes.includes('layout-shift');
140-
} catch {
141-
return false;
142-
}
143-
}

0 commit comments

Comments
 (0)