Skip to content

Commit 93058fc

Browse files
Lms24onurtemizkan
authored andcommitted
fix(core): Set sentry.source attribute to custom when calling span.updateName on SentrySpan (#14251)
Fix a "regression" introduced in v8 where we no longer updated the source of the span when calling `span.updateName`. We had this behaviour in our v7 `Transaction` class (IIRC via `transaction.setName(name, source)` but most likely forgot to port it to the `Span` class as the `event.transaction_info.source` field is only relevant for transactions (i.e. root spans in today's SDK lingo).
1 parent d7e6a87 commit 93058fc

File tree

10 files changed

+114
-15
lines changed

10 files changed

+114
-15
lines changed

.size-limit.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ module.exports = [
139139
path: 'packages/vue/build/esm/index.js',
140140
import: createImport('init', 'browserTracingIntegration'),
141141
gzip: true,
142-
limit: '38 KB',
142+
limit: '38.5 KB',
143143
},
144144
// Svelte SDK (ESM)
145145
{

dev-packages/browser-integration-tests/suites/public-api/startSpan/basic/test.ts

+29-12
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,41 @@
11
import { expect } from '@playwright/test';
22

3+
import {
4+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
5+
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
6+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
7+
} from '@sentry/browser';
38
import { sentryTest } from '../../../../utils/fixtures';
49
import {
510
envelopeRequestParser,
611
shouldSkipTracingTest,
712
waitForTransactionRequestOnUrl,
813
} from '../../../../utils/helpers';
914

10-
sentryTest('should send a transaction in an envelope', async ({ getLocalTestPath, page }) => {
11-
if (shouldSkipTracingTest()) {
12-
sentryTest.skip();
13-
}
14-
15-
const url = await getLocalTestPath({ testDir: __dirname });
16-
const req = await waitForTransactionRequestOnUrl(page, url);
17-
const transaction = envelopeRequestParser(req);
18-
19-
expect(transaction.transaction).toBe('parent_span');
20-
expect(transaction.spans).toBeDefined();
21-
});
15+
sentryTest(
16+
'sends a transaction in an envelope with manual origin and custom source',
17+
async ({ getLocalTestPath, page }) => {
18+
if (shouldSkipTracingTest()) {
19+
sentryTest.skip();
20+
}
21+
22+
const url = await getLocalTestPath({ testDir: __dirname });
23+
const req = await waitForTransactionRequestOnUrl(page, url);
24+
const transaction = envelopeRequestParser(req);
25+
26+
const attributes = transaction.contexts?.trace?.data;
27+
expect(attributes).toEqual({
28+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'manual',
29+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
30+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'custom',
31+
});
32+
33+
expect(transaction.transaction_info?.source).toBe('custom');
34+
35+
expect(transaction.transaction).toBe('parent_span');
36+
expect(transaction.spans).toBeDefined();
37+
},
38+
);
2239

2340
sentryTest('should report finished spans as children of the root transaction', async ({ getLocalTestPath, page }) => {
2441
if (shouldSkipTracingTest()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window._testBaseTimestamp = performance.timeOrigin / 1000;
5+
6+
Sentry.init({
7+
dsn: 'https://[email protected]/1337',
8+
integrations: [Sentry.browserTracingIntegration()],
9+
tracesSampleRate: 1,
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const activeSpan = Sentry.getActiveSpan();
2+
const rootSpan = activeSpan && Sentry.getRootSpan(activeSpan);
3+
rootSpan?.updateName('new name');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/types';
3+
4+
import {
5+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
6+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
7+
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
8+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
9+
} from '@sentry/browser';
10+
import { sentryTest } from '../../../../utils/fixtures';
11+
import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers';
12+
13+
sentryTest('sets the source to custom when updating the transaction name', async ({ getLocalTestPath, page }) => {
14+
if (shouldSkipTracingTest()) {
15+
sentryTest.skip();
16+
}
17+
18+
const url = await getLocalTestPath({ testDir: __dirname });
19+
20+
const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
21+
22+
const traceContextData = eventData.contexts?.trace?.data;
23+
24+
expect(traceContextData).toMatchObject({
25+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',
26+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
27+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'custom',
28+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
29+
});
30+
31+
expect(eventData.transaction).toBe('new name');
32+
33+
expect(eventData.contexts?.trace?.op).toBe('pageload');
34+
expect(eventData.spans?.length).toBeGreaterThan(0);
35+
expect(eventData.transaction_info?.source).toEqual('custom');
36+
});

dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/pageload/test.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import { expect } from '@playwright/test';
22
import type { Event } from '@sentry/types';
33

4+
import {
5+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
6+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
7+
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
8+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
9+
} from '@sentry/browser';
410
import { sentryTest } from '../../../../utils/fixtures';
511
import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers';
612

7-
sentryTest('should create a pageload transaction', async ({ getLocalTestPath, page }) => {
13+
sentryTest('creates a pageload transaction with url as source', async ({ getLocalTestPath, page }) => {
814
if (shouldSkipTracingTest()) {
915
sentryTest.skip();
1016
}
@@ -16,8 +22,17 @@ sentryTest('should create a pageload transaction', async ({ getLocalTestPath, pa
1622

1723
const { start_timestamp: startTimestamp } = eventData;
1824

25+
const traceContextData = eventData.contexts?.trace?.data;
26+
1927
expect(startTimestamp).toBeCloseTo(timeOrigin, 1);
2028

29+
expect(traceContextData).toMatchObject({
30+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser',
31+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1,
32+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
33+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
34+
});
35+
2136
expect(eventData.contexts?.trace?.op).toBe('pageload');
2237
expect(eventData.spans?.length).toBeGreaterThan(0);
2338
expect(eventData.transaction_info?.source).toEqual('url');

packages/core/src/tracing/sentrySpan.ts

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ export class SentrySpan implements Span {
193193
*/
194194
public updateName(name: string): this {
195195
this._name = name;
196+
this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'custom');
196197
return this;
197198
}
198199

packages/core/test/lib/tracing/sentrySpan.test.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { timestampInSeconds } from '@sentry/utils';
2-
import { setCurrentClient } from '../../../src';
2+
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, setCurrentClient } from '../../../src';
33
import { SentrySpan } from '../../../src/tracing/sentrySpan';
44
import { SPAN_STATUS_ERROR } from '../../../src/tracing/spanstatus';
55
import { TRACE_FLAG_NONE, TRACE_FLAG_SAMPLED, spanToJSON } from '../../../src/utils/spanUtils';
@@ -20,6 +20,19 @@ describe('SentrySpan', () => {
2020

2121
expect(spanToJSON(span).description).toEqual('new name');
2222
});
23+
24+
it('sets the source to custom when calling updateName', () => {
25+
const span = new SentrySpan({
26+
name: 'original name',
27+
attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url' },
28+
});
29+
30+
span.updateName('new name');
31+
32+
const spanJson = spanToJSON(span);
33+
expect(spanJson.description).toEqual('new name');
34+
expect(spanJson.data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]).toEqual('custom');
35+
});
2336
});
2437

2538
describe('setters', () => {

packages/nextjs/src/client/routing/appRouterRoutingInstrumentation.ts

+3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export function appRouterInstrumentNavigation(client: Client): void {
6161
WINDOW.addEventListener('popstate', () => {
6262
if (currentNavigationSpan && currentNavigationSpan.isRecording()) {
6363
currentNavigationSpan.updateName(WINDOW.location.pathname);
64+
currentNavigationSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url');
6465
} else {
6566
currentNavigationSpan = startBrowserTracingNavigationSpan(client, {
6667
name: WINDOW.location.pathname,
@@ -105,9 +106,11 @@ export function appRouterInstrumentNavigation(client: Client): void {
105106

106107
if (routerFunctionName === 'push') {
107108
span?.updateName(transactionNameifyRouterArgument(argArray[0]));
109+
span?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url');
108110
span?.setAttribute('navigation.type', 'router.push');
109111
} else if (routerFunctionName === 'replace') {
110112
span?.updateName(transactionNameifyRouterArgument(argArray[0]));
113+
span?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url');
111114
span?.setAttribute('navigation.type', 'router.replace');
112115
} else if (routerFunctionName === 'back') {
113116
span?.setAttribute('navigation.type', 'router.back');

packages/solid/src/solidrouter.ts

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ function withSentryRouterRoot(Root: Component<RouteSectionProps>): Component<Rou
8989
// everything else was already instrumented correctly in `useBeforeLeave`
9090
if (op === 'navigation' && description === '-1') {
9191
rootSpan.updateName(name);
92+
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url');
9293
}
9394
}
9495
});

0 commit comments

Comments
 (0)