Skip to content

Commit 54b1cf5

Browse files
authored
feat(core): Fix span scope handling & transaction setting (#10886)
This does the following things: 1. Instead of setting `transaction` tag, we ensure to set the `transaction` on the event itself. 2. This also allows us to remove code that lead to other bugs, which is that we needed to fork the scope for `startInactiveSpan` just to get the correct transaction tag. 3. Add tests to ensure that the scope is correctly applied when using `startInactiveSpan` ## Background I initially implemented `startInactiveSpan` to fork the current scope & set the span on that to satisfy two things: 1. We do not want to set this span as active on the actual current scope 2. We needed a way to set the transaction tag on the span (if it was a transaction) in an event processor For 2., in order for `getActiveSpan()` to work in there I had to make the span active in the forked scope. This kind of worked, BUT I now noticed that this has the massive problem: ```js const scope = getCurrentScope(); const span = startInactiveSpan(...); scope.setTag(...); // <-- this will not be applied to the span! ``` So I went in and fixed this - and since we talked about not needing to set the `transaction` tag anyhow (instead, just set the `transaction` itself!), I figured I can fix these in one go.
1 parent 9c213eb commit 54b1cf5

File tree

20 files changed

+122
-126
lines changed

20 files changed

+122
-126
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Route } from '@playwright/test';
22
import { expect } from '@playwright/test';
3-
import type { Event, Span, SpanContext, Transaction } from '@sentry/types';
3+
import type { Event, SpanContext, SpanJSON } from '@sentry/types';
44

55
import { sentryTest } from '../../../../utils/fixtures';
66
import {
@@ -9,8 +9,8 @@ import {
99
shouldSkipTracingTest,
1010
} from '../../../../utils/helpers';
1111

12-
type TransactionJSON = ReturnType<Transaction['toJSON']> & {
13-
spans: ReturnType<Span['toJSON']>[];
12+
type TransactionJSON = SpanJSON & {
13+
spans: SpanJSON[];
1414
contexts: SpanContext;
1515
platform: string;
1616
type: string;

dev-packages/e2e-tests/test-applications/angular-17/tests/errors.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { waitForError } from '../event-proxy-server';
33

44
test('sends an error', async ({ page }) => {
55
const errorPromise = waitForError('angular-17', async errorEvent => {
6-
return !errorEvent?.transaction;
6+
return !errorEvent.type;
77
});
88

99
await page.goto(`/`);

dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/route-handlers.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ test('Should record exceptions and transactions for faulty route handlers', asyn
5252
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
5353

5454
expect(routehandlerError.exception?.values?.[0].value).toBe('route-handler-error');
55-
expect(routehandlerError.tags?.transaction).toBe('PUT /route-handlers/[param]/error');
55+
expect(routehandlerError.transaction).toBe('PUT /route-handlers/[param]/error');
5656
});
5757

5858
test.describe('Edge runtime', () => {

dev-packages/e2e-tests/test-applications/sveltekit-2/test/errors.server.test.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ test.describe('server-side errors', () => {
6060
}),
6161
);
6262

63-
expect(errorEvent.tags).toMatchObject({
64-
runtime: 'node',
65-
transaction: 'GET /server-route-error',
66-
});
63+
expect(errorEvent.transaction).toEqual('GET /server-route-error');
6764
});
6865
});

dev-packages/e2e-tests/test-applications/sveltekit/test/errors.server.test.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,6 @@ test.describe('server-side errors', () => {
6363
}),
6464
);
6565

66-
expect(errorEvent.tags).toMatchObject({
67-
runtime: 'node',
68-
transaction: 'GET /server-route-error',
69-
});
66+
expect(errorEvent.transaction).toEqual('GET /server-route-error');
7067
});
7168
});

dev-packages/e2e-tests/test-applications/vue-3/tests/errors.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { waitForError } from '../event-proxy-server';
33

44
test('sends an error', async ({ page }) => {
55
const errorPromise = waitForError('vue-3', async errorEvent => {
6-
return !errorEvent?.transaction;
6+
return !errorEvent.type;
77
});
88

99
await page.goto(`/`);

packages/core/src/tracing/trace.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ export function startSpan<T>(context: StartSpanOptions, callback: (span: Span |
4242
scope,
4343
});
4444

45+
if (activeSpan) {
46+
// eslint-disable-next-line deprecation/deprecation
47+
scope.setSpan(activeSpan);
48+
}
49+
4550
return handleCallbackErrors(
4651
() => callback(activeSpan),
4752
() => {
@@ -91,6 +96,11 @@ export function startSpanManual<T>(
9196
scope,
9297
});
9398

99+
if (activeSpan) {
100+
// eslint-disable-next-line deprecation/deprecation
101+
scope.setSpan(activeSpan);
102+
}
103+
94104
function finishAndSetSpan(): void {
95105
activeSpan && activeSpan.end();
96106
}
@@ -141,16 +151,11 @@ export function startInactiveSpan(context: StartSpanOptions): Span | undefined {
141151

142152
const scope = context.scope || getCurrentScope();
143153

144-
// Even though we don't actually want to make this span active on the current scope,
145-
// we need to make it active on a temporary scope that we use for event processing
146-
// as otherwise, it won't pick the correct span for the event when processing it
147-
const temporaryScope = scope.clone();
148-
149154
return createChildSpanOrTransaction(hub, {
150155
parentSpan,
151156
spanContext,
152157
forceTransaction: context.forceTransaction,
153-
scope: temporaryScope,
158+
scope,
154159
});
155160
}
156161

@@ -319,12 +324,6 @@ function createChildSpanOrTransaction(
319324
});
320325
}
321326

322-
// We always set this as active span on the scope
323-
// In the case of this being an inactive span, we ensure to pass a detached scope in here in the first place
324-
// But by having this here, we can ensure that the lookup through `getCapturedScopesOnSpan` results in the correct scope & span combo
325-
// eslint-disable-next-line deprecation/deprecation
326-
scope.setSpan(span);
327-
328327
setCapturedScopesOnSpan(span, scope, isolationScope);
329328

330329
return span;

packages/core/src/utils/applyScopeDataToEvent.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,10 @@ function applySpanToEvent(event: Event, span: Span): void {
178178
dynamicSamplingContext: getDynamicSamplingContextFromSpan(span),
179179
...event.sdkProcessingMetadata,
180180
};
181+
181182
const transactionName = spanToJSON(rootSpan).description;
182-
if (transactionName) {
183-
event.tags = { transaction: transactionName, ...event.tags };
183+
if (transactionName && !event.transaction) {
184+
event.transaction = transactionName;
184185
}
185186
}
186187
}

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

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,7 @@ describe('startSpan', () => {
360360
},
361361
});
362362
expect(outerTransaction?.spans).toEqual([{ name: 'inner span', id: expect.any(String) }]);
363-
expect(outerTransaction?.tags).toEqual({
364-
transaction: 'outer transaction',
365-
});
363+
expect(outerTransaction?.transaction).toEqual('outer transaction');
366364
expect(outerTransaction?.sdkProcessingMetadata).toEqual({
367365
dynamicSamplingContext: {
368366
environment: 'production',
@@ -386,9 +384,7 @@ describe('startSpan', () => {
386384
},
387385
});
388386
expect(innerTransaction?.spans).toEqual([{ name: 'inner span 2', id: expect.any(String) }]);
389-
expect(innerTransaction?.tags).toEqual({
390-
transaction: 'inner transaction',
391-
});
387+
expect(innerTransaction?.transaction).toEqual('inner transaction');
392388
expect(innerTransaction?.sdkProcessingMetadata).toEqual({
393389
dynamicSamplingContext: {
394390
environment: 'production',
@@ -643,9 +639,7 @@ describe('startSpanManual', () => {
643639
},
644640
});
645641
expect(outerTransaction?.spans).toEqual([{ name: 'inner span', id: expect.any(String) }]);
646-
expect(outerTransaction?.tags).toEqual({
647-
transaction: 'outer transaction',
648-
});
642+
expect(outerTransaction?.transaction).toEqual('outer transaction');
649643
expect(outerTransaction?.sdkProcessingMetadata).toEqual({
650644
dynamicSamplingContext: {
651645
environment: 'production',
@@ -669,9 +663,7 @@ describe('startSpanManual', () => {
669663
},
670664
});
671665
expect(innerTransaction?.spans).toEqual([{ name: 'inner span 2', id: expect.any(String) }]);
672-
expect(innerTransaction?.tags).toEqual({
673-
transaction: 'inner transaction',
674-
});
666+
expect(innerTransaction?.transaction).toEqual('inner transaction');
675667
expect(innerTransaction?.sdkProcessingMetadata).toEqual({
676668
dynamicSamplingContext: {
677669
environment: 'production',
@@ -854,9 +846,7 @@ describe('startInactiveSpan', () => {
854846
},
855847
});
856848
expect(outerTransaction?.spans).toEqual([{ name: 'inner span', id: expect.any(String) }]);
857-
expect(outerTransaction?.tags).toEqual({
858-
transaction: 'outer transaction',
859-
});
849+
expect(outerTransaction?.transaction).toEqual('outer transaction');
860850
expect(outerTransaction?.sdkProcessingMetadata).toEqual({
861851
dynamicSamplingContext: {
862852
environment: 'production',
@@ -880,9 +870,7 @@ describe('startInactiveSpan', () => {
880870
},
881871
});
882872
expect(innerTransaction?.spans).toEqual([]);
883-
expect(innerTransaction?.tags).toEqual({
884-
transaction: 'inner transaction',
885-
});
873+
expect(innerTransaction?.transaction).toEqual('inner transaction');
886874
expect(innerTransaction?.sdkProcessingMetadata).toEqual({
887875
dynamicSamplingContext: {
888876
environment: 'production',
@@ -948,9 +936,13 @@ describe('startInactiveSpan', () => {
948936

949937
let span: Span | undefined;
950938

939+
const scope = getCurrentScope();
940+
scope.setTag('outer', 'foo');
941+
951942
withScope(scope => {
952943
scope.setTag('scope', 1);
953944
span = startInactiveSpan({ name: 'my-span' });
945+
scope.setTag('scope_after_span', 2);
954946
});
955947

956948
withScope(scope => {
@@ -964,7 +956,9 @@ describe('startInactiveSpan', () => {
964956
expect(beforeSendTransaction).toHaveBeenCalledWith(
965957
expect.objectContaining({
966958
tags: expect.objectContaining({
959+
outer: 'foo',
967960
scope: 1,
961+
scope_after_span: 2,
968962
}),
969963
}),
970964
expect.anything(),

packages/node-experimental/test/integration/scope.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ describe('Integration | Scope', () => {
8282
tag2: 'val2',
8383
tag3: 'val3',
8484
tag4: 'val4',
85-
...(enableTracing ? { transaction: 'outer' } : {}),
8685
},
86+
...(enableTracing ? { transaction: 'outer' } : {}),
8787
}),
8888
{
8989
event_id: expect.any(String),
@@ -118,7 +118,6 @@ describe('Integration | Scope', () => {
118118
tag2: 'val2',
119119
tag3: 'val3',
120120
tag4: 'val4',
121-
transaction: 'outer',
122121
},
123122
timestamp: expect.any(Number),
124123
transaction: 'outer',
@@ -203,8 +202,8 @@ describe('Integration | Scope', () => {
203202
tag2: 'val2a',
204203
tag3: 'val3a',
205204
tag4: 'val4a',
206-
...(enableTracing ? { transaction: 'outer' } : {}),
207205
},
206+
...(enableTracing ? { transaction: 'outer' } : {}),
208207
}),
209208
{
210209
event_id: expect.any(String),
@@ -229,8 +228,8 @@ describe('Integration | Scope', () => {
229228
tag2: 'val2b',
230229
tag3: 'val3b',
231230
tag4: 'val4b',
232-
...(enableTracing ? { transaction: 'outer' } : {}),
233231
},
232+
...(enableTracing ? { transaction: 'outer' } : {}),
234233
}),
235234
{
236235
event_id: expect.any(String),

0 commit comments

Comments
 (0)