Skip to content

Commit 1cceeae

Browse files
authored
feat(core): Deprecate Span.origin in favor of sentry.origin attribute (#10260)
Deprecate the `Span.origin` field on the class and the interface. It will be replaced in v8 by the semantic `sentry.op` attribute.
1 parent d3fecc1 commit 1cceeae

File tree

20 files changed

+216
-49
lines changed

20 files changed

+216
-49
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ sentryTest('should report finished spans as children of the root transaction', a
2424
const url = await getLocalTestPath({ testDir: __dirname });
2525
const transaction = await getFirstSentryEnvelopeRequest<SerializedEvent>(page, url);
2626

27-
const rootSpanId = transaction?.contexts?.trace?.span_id;
28-
2927
expect(transaction.spans).toHaveLength(1);
3028

3129
const span_1 = transaction.spans?.[0];
3230
expect(span_1?.description).toBe('child_span');
33-
expect(span_1?.parent_span_id).toEqual(rootSpanId);
31+
expect(span_1?.parent_span_id).toEqual(transaction?.contexts?.trace?.span_id);
32+
expect(span_1?.origin).toEqual('manual');
33+
expect(span_1?.data?.['sentry.origin']).toEqual('manual');
3434
});

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ test('Should trace outgoing fetch requests inside middleware and create breadcru
6969
type: 'fetch',
7070
url: 'http://localhost:3030/',
7171
'sentry.op': 'http.client',
72+
'sentry.origin': 'auto.http.wintercg_fetch',
7273
},
7374
description: 'GET http://localhost:3030/',
7475
op: 'http.client',

dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => {
6464
'otel.kind': 'SERVER',
6565
'http.response.status_code': 200,
6666
'sentry.op': 'http.server',
67+
'sentry.origin': 'auto.http.otel.http',
6768
},
6869
op: 'http.server',
6970
span_id: expect.any(String),
@@ -87,6 +88,7 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => {
8788
'otel.kind': 'SERVER',
8889
'http.response.status_code': 200,
8990
'sentry.op': 'http.server',
91+
'sentry.origin': 'auto.http.otel.http',
9092
},
9193
op: 'http.server',
9294
parent_span_id: outgoingHttpSpanId,
@@ -159,6 +161,7 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => {
159161
'otel.kind': 'SERVER',
160162
'http.response.status_code': 200,
161163
'sentry.op': 'http.server',
164+
'sentry.origin': 'auto.http.otel.http',
162165
},
163166
op: 'http.server',
164167
span_id: expect.any(String),
@@ -182,6 +185,7 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => {
182185
'otel.kind': 'SERVER',
183186
'http.response.status_code': 200,
184187
'sentry.op': 'http.server',
188+
'sentry.origin': 'auto.http.otel.http',
185189
},
186190
op: 'http.server',
187191
parent_span_id: outgoingHttpSpanId,

dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ test('Sends an API route transaction', async ({ baseURL }) => {
2929
'otel.kind': 'SERVER',
3030
'http.response.status_code': 200,
3131
'sentry.op': 'http.server',
32+
'sentry.origin': 'auto.http.otel.http',
3233
},
3334
op: 'http.server',
3435
span_id: expect.any(String),
@@ -48,6 +49,7 @@ test('Sends an API route transaction', async ({ baseURL }) => {
4849
'fastify.type': 'request_handler',
4950
'http.route': '/test-transaction',
5051
'otel.kind': 'INTERNAL',
52+
'sentry.origin': 'auto.http.otel.fastify',
5153
},
5254
description: 'request handler - fastify -> app-auto-0',
5355
parent_span_id: expect.any(String),
@@ -61,6 +63,7 @@ test('Sends an API route transaction', async ({ baseURL }) => {
6163
{
6264
data: {
6365
'otel.kind': 'INTERNAL',
66+
'sentry.origin': 'manual',
6467
},
6568
description: 'test-span',
6669
parent_span_id: expect.any(String),
@@ -74,6 +77,7 @@ test('Sends an API route transaction', async ({ baseURL }) => {
7477
{
7578
data: {
7679
'otel.kind': 'INTERNAL',
80+
'sentry.origin': 'manual',
7781
},
7882
description: 'child-span',
7983
parent_span_id: expect.any(String),

packages/core/src/semanticAttributes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ export const SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = 'sentry.sample_rate';
1414
* Use this attribute to represent the operation of a span.
1515
*/
1616
export const SEMANTIC_ATTRIBUTE_SENTRY_OP = 'sentry.op';
17+
18+
/**
19+
* Use this attribute to represent the origin of a span.
20+
*/
21+
export const SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = 'sentry.origin';

packages/core/src/tracing/span.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type {
1616
import { dropUndefinedKeys, logger, timestampInSeconds, uuid4 } from '@sentry/utils';
1717

1818
import { DEBUG_BUILD } from '../debug-build';
19-
import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../semanticAttributes';
19+
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes';
2020
import { getRootSpan } from '../utils/getRootSpan';
2121
import {
2222
TRACE_FLAG_NONE,
@@ -100,11 +100,6 @@ export class Span implements SpanInterface {
100100
*/
101101
public instrumenter: Instrumenter;
102102

103-
/**
104-
* The origin of the span, giving context about what created the span.
105-
*/
106-
public origin?: SpanOrigin;
107-
108103
protected _traceId: string;
109104
protected _spanId: string;
110105
protected _parentSpanId?: string;
@@ -138,7 +133,9 @@ export class Span implements SpanInterface {
138133
this._attributes = spanContext.attributes ? { ...spanContext.attributes } : {};
139134
// eslint-disable-next-line deprecation/deprecation
140135
this.instrumenter = spanContext.instrumenter || 'sentry';
141-
this.origin = spanContext.origin || 'manual';
136+
137+
this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanContext.origin || 'manual');
138+
142139
// eslint-disable-next-line deprecation/deprecation
143140
this._name = spanContext.name || spanContext.description;
144141

@@ -346,6 +343,24 @@ export class Span implements SpanInterface {
346343
this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, op);
347344
}
348345

346+
/**
347+
* The origin of the span, giving context about what created the span.
348+
*
349+
* @deprecated Use `spanToJSON().origin` to read the origin instead.
350+
*/
351+
public get origin(): SpanOrigin | undefined {
352+
return this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined;
353+
}
354+
355+
/**
356+
* The origin of the span, giving context about what created the span.
357+
*
358+
* @deprecated Use `startSpan()` functions to set the origin instead.
359+
*/
360+
public set origin(origin: SpanOrigin | undefined) {
361+
this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, origin);
362+
}
363+
349364
/* eslint-enable @typescript-eslint/member-ordering */
350365

351366
/** @inheritdoc */
@@ -611,7 +626,7 @@ export class Span implements SpanInterface {
611626
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined,
612627
timestamp: this._endTime,
613628
trace_id: this._traceId,
614-
origin: this.origin,
629+
origin: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined,
615630
});
616631
}
617632

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

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ describe('span', () => {
8484
strArray: ['aa', 'bb'],
8585
boolArray: [true, false],
8686
arrayWithUndefined: [1, undefined, 2],
87+
// origin is set by default to 'manual' in the Span constructor
88+
'sentry.origin': 'manual',
8789
});
8890
});
8991

@@ -92,11 +94,12 @@ describe('span', () => {
9294

9395
span.setAttribute('str', 'bar');
9496

95-
expect(Object.keys(span['_attributes']).length).toEqual(1);
97+
// length 2 because `sentry.origin` is always set by default
98+
expect(Object.keys(span['_attributes']).length).toEqual(2);
9699

97100
span.setAttribute('str', undefined);
98101

99-
expect(Object.keys(span['_attributes']).length).toEqual(0);
102+
expect(Object.keys(span['_attributes']).length).toEqual(1);
100103
});
101104

102105
it('disallows invalid attribute types', () => {
@@ -119,7 +122,10 @@ describe('span', () => {
119122

120123
const initialAttributes = span['_attributes'];
121124

122-
expect(initialAttributes).toEqual({});
125+
expect(initialAttributes).toEqual({
126+
// origin is set by default to 'manual' in the Span constructor
127+
'sentry.origin': 'manual',
128+
});
123129

124130
const newAttributes = {
125131
str: 'bar',
@@ -145,6 +151,7 @@ describe('span', () => {
145151
strArray: ['aa', 'bb'],
146152
boolArray: [true, false],
147153
arrayWithUndefined: [1, undefined, 2],
154+
'sentry.origin': 'manual',
148155
});
149156

150157
expect(span['_attributes']).not.toBe(newAttributes);
@@ -164,6 +171,7 @@ describe('span', () => {
164171
strArray: ['aa', 'bb'],
165172
boolArray: [true, false],
166173
arrayWithUndefined: [1, undefined, 2],
174+
'sentry.origin': 'manual',
167175
});
168176
});
169177

@@ -172,11 +180,12 @@ describe('span', () => {
172180

173181
span.setAttribute('str', 'bar');
174182

175-
expect(Object.keys(span['_attributes']).length).toEqual(1);
183+
// length 2 because `sentry.origin` is always set by default
184+
expect(Object.keys(span['_attributes']).length).toEqual(2);
176185

177186
span.setAttributes({ str: undefined });
178187

179-
expect(Object.keys(span['_attributes']).length).toEqual(0);
188+
expect(Object.keys(span['_attributes']).length).toEqual(1);
180189
});
181190
});
182191

@@ -275,24 +284,38 @@ describe('span', () => {
275284
it('works without data & attributes', () => {
276285
const span = new Span();
277286

278-
expect(span['_getData']()).toEqual(undefined);
287+
expect(span['_getData']()).toEqual({
288+
// origin is set by default to 'manual' in the Span constructor
289+
'sentry.origin': 'manual',
290+
});
279291
});
280292

281293
it('works with data only', () => {
282294
const span = new Span();
283295
// eslint-disable-next-line deprecation/deprecation
284296
span.setData('foo', 'bar');
285297

286-
expect(span['_getData']()).toEqual({ foo: 'bar' });
287-
// eslint-disable-next-line deprecation/deprecation
288-
expect(span['_getData']()).toBe(span.data);
298+
expect(span['_getData']()).toEqual({
299+
foo: 'bar',
300+
// origin is set by default to 'manual' in the Span constructor
301+
'sentry.origin': 'manual',
302+
});
303+
expect(span['_getData']()).toStrictEqual({
304+
// eslint-disable-next-line deprecation/deprecation
305+
...span.data,
306+
'sentry.origin': 'manual',
307+
});
289308
});
290309

291310
it('works with attributes only', () => {
292311
const span = new Span();
293312
span.setAttribute('foo', 'bar');
294313

295-
expect(span['_getData']()).toEqual({ foo: 'bar' });
314+
expect(span['_getData']()).toEqual({
315+
foo: 'bar',
316+
// origin is set by default to 'manual' in the Span constructor
317+
'sentry.origin': 'manual',
318+
});
296319
// eslint-disable-next-line deprecation/deprecation
297320
expect(span['_getData']()).toBe(span.attributes);
298321
});
@@ -306,7 +329,13 @@ describe('span', () => {
306329
// eslint-disable-next-line deprecation/deprecation
307330
span.setData('baz', 'baz');
308331

309-
expect(span['_getData']()).toEqual({ foo: 'foo', bar: 'bar', baz: 'baz' });
332+
expect(span['_getData']()).toEqual({
333+
foo: 'foo',
334+
bar: 'bar',
335+
baz: 'baz',
336+
// origin is set by default to 'manual' in the Span constructor
337+
'sentry.origin': 'manual',
338+
});
310339
// eslint-disable-next-line deprecation/deprecation
311340
expect(span['_getData']()).not.toBe(span.attributes);
312341
// eslint-disable-next-line deprecation/deprecation

packages/core/test/lib/utils/spanUtils.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ describe('spanToJSON', () => {
5555
trace_id: span.spanContext().traceId,
5656
origin: 'manual',
5757
start_timestamp: span['_startTime'],
58+
data: {
59+
'sentry.origin': 'manual',
60+
},
5861
});
5962
});
6063

@@ -89,6 +92,7 @@ describe('spanToJSON', () => {
8992
timestamp: 456,
9093
data: {
9194
'sentry.op': 'test op',
95+
'sentry.origin': 'auto',
9296
},
9397
});
9498
});

packages/nextjs/test/integration/test/client/tracingFetch.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from '@playwright/test';
2-
import { Transaction } from '@sentry/types';
2+
import { SerializedEvent } from '@sentry/types';
33
import { countEnvelopes, getMultipleSentryEnvelopeRequests } from './utils/helpers';
44

55
test('should correctly instrument `fetch` for performance tracing', async ({ page }) => {
@@ -12,7 +12,7 @@ test('should correctly instrument `fetch` for performance tracing', async ({ pag
1212
});
1313
});
1414

15-
const transaction = await getMultipleSentryEnvelopeRequests<Transaction>(page, 1, {
15+
const transaction = await getMultipleSentryEnvelopeRequests<SerializedEvent>(page, 1, {
1616
url: '/fetch',
1717
envelopeType: 'transaction',
1818
});
@@ -27,7 +27,6 @@ test('should correctly instrument `fetch` for performance tracing', async ({ pag
2727
},
2828
});
2929

30-
// @ts-expect-error - We know that `spans` is inside Transaction envelopes
3130
expect(transaction[0].spans).toEqual(
3231
expect.arrayContaining([
3332
expect.objectContaining({
@@ -38,6 +37,7 @@ test('should correctly instrument `fetch` for performance tracing', async ({ pag
3837
'http.response_content_length': expect.any(Number),
3938
'http.response.status_code': 200,
4039
'sentry.op': 'http.client',
40+
'sentry.origin': 'auto.http.browser',
4141
},
4242
description: 'GET http://example.com',
4343
op: 'http.client',
@@ -47,6 +47,7 @@ test('should correctly instrument `fetch` for performance tracing', async ({ pag
4747
timestamp: expect.any(Number),
4848
trace_id: expect.any(String),
4949
status: expect.any(String),
50+
origin: 'auto.http.browser',
5051
}),
5152
]),
5253
);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ describe('Integration | Scope', () => {
8888
expect.objectContaining({
8989
contexts: expect.objectContaining({
9090
trace: {
91-
data: { 'otel.kind': 'INTERNAL' },
91+
data: { 'otel.kind': 'INTERNAL', 'sentry.origin': 'manual' },
9292
span_id: spanId,
9393
status: 'ok',
9494
trace_id: traceId,

0 commit comments

Comments
 (0)