Skip to content

Commit 0fd86bc

Browse files
mydealforstLms24
authored
ref(tracing): Add origin to spans (#8765)
This adds an `origin` to all spans, which defaults to `manual` but is set to something more meaningful for all our auto instrumentation. I tried to come up with reasonable origin names, I hope it makes sense everywhere 😅 Also note that this now uses a new TS feature which seems to be correctly transpiled to TS 3.8, as far as I can tell! 🎉 Closes #8510 --------- Co-authored-by: Luca Forstner <[email protected]> Co-authored-by: Lukas Stracke <[email protected]>
1 parent e72c047 commit 0fd86bc

File tree

85 files changed

+346
-43
lines changed

Some content is hidden

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

85 files changed

+346
-43
lines changed

packages/angular/src/tracing.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export function routingInstrumentation(
3939
customStartTransaction({
4040
name: WINDOW.location.pathname,
4141
op: 'pageload',
42+
origin: 'auto.pageload.angular',
4243
metadata: { source: 'url' },
4344
});
4445
}
@@ -84,6 +85,7 @@ export class TraceService implements OnDestroy {
8485
activeTransaction = stashedStartTransaction({
8586
name: strippedUrl,
8687
op: 'navigation',
88+
origin: 'auto.navigation.angular',
8789
metadata: { source: 'url' },
8890
});
8991
}
@@ -95,6 +97,7 @@ export class TraceService implements OnDestroy {
9597
this._routingSpan = activeTransaction.startChild({
9698
description: `${navigationEvent.url}`,
9799
op: ANGULAR_ROUTING_OP,
100+
origin: 'auto.ui.angular',
98101
tags: {
99102
'routing.instrumentation': '@sentry/angular',
100103
url: strippedUrl,
@@ -192,6 +195,7 @@ export class TraceDirective implements OnInit, AfterViewInit {
192195
this._tracingSpan = activeTransaction.startChild({
193196
description: `<${this.componentName}>`,
194197
op: ANGULAR_INIT_OP,
198+
origin: 'auto.ui.angular.trace_directive',
195199
});
196200
}
197201
}
@@ -233,6 +237,7 @@ export function TraceClassDecorator(): ClassDecorator {
233237
tracingSpan = activeTransaction.startChild({
234238
description: `<${target.name}>`,
235239
op: ANGULAR_INIT_OP,
240+
origin: 'auto.ui.angular.trace_class_decorator',
236241
});
237242
}
238243
if (originalOnInit) {
@@ -270,6 +275,7 @@ export function TraceMethodDecorator(): MethodDecorator {
270275
description: `<${target.constructor.name}>`,
271276
endTimestamp: now,
272277
op: `${ANGULAR_OP}.${String(propertyKey)}`,
278+
origin: 'auto.ui.angular.trace_method_decorator',
273279
startTimestamp: now,
274280
});
275281
}

packages/angular/test/tracing.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ describe('Angular Tracing', () => {
4848
expect(startTransaction).toHaveBeenCalledWith({
4949
name: '/',
5050
op: 'pageload',
51+
origin: 'auto.pageload.angular',
5152
metadata: { source: 'url' },
5253
});
5354
});
@@ -137,6 +138,7 @@ describe('Angular Tracing', () => {
137138
expect(customStartTransaction).toHaveBeenCalledWith({
138139
name: url,
139140
op: 'pageload',
141+
origin: 'auto.pageload.angular',
140142
metadata: { source: 'url' },
141143
});
142144

@@ -327,6 +329,7 @@ describe('Angular Tracing', () => {
327329
expect(customStartTransaction).toHaveBeenCalledWith({
328330
name: url,
329331
op: 'navigation',
332+
origin: 'auto.navigation.angular',
330333
metadata: { source: 'url' },
331334
});
332335
expect(transaction.setName).toHaveBeenCalledWith(result, 'route');
@@ -358,6 +361,7 @@ describe('Angular Tracing', () => {
358361

359362
expect(transaction.startChild).toHaveBeenCalledWith({
360363
op: 'ui.angular.init',
364+
origin: 'auto.ui.angular.trace_directive',
361365
description: '<unknown>',
362366
});
363367

@@ -384,6 +388,7 @@ describe('Angular Tracing', () => {
384388

385389
expect(transaction.startChild).toHaveBeenCalledWith({
386390
op: 'ui.angular.init',
391+
origin: 'auto.ui.angular.trace_directive',
387392
description: '<test-component>',
388393
});
389394

@@ -458,6 +463,7 @@ describe('Angular Tracing', () => {
458463
expect(transaction.startChild).toHaveBeenCalledWith({
459464
description: '<DecoratedComponent>',
460465
op: 'ui.angular.init',
466+
origin: 'auto.ui.angular.trace_class_decorator',
461467
});
462468

463469
expect(origNgOnInitMock).toHaveBeenCalledTimes(1);
@@ -511,13 +517,15 @@ describe('Angular Tracing', () => {
511517
expect(transaction.startChild.mock.calls[0][0]).toEqual({
512518
description: '<DecoratedComponent>',
513519
op: 'ui.angular.ngOnInit',
520+
origin: 'auto.ui.angular.trace_method_decorator',
514521
startTimestamp: expect.any(Number),
515522
endTimestamp: expect.any(Number),
516523
});
517524

518525
expect(transaction.startChild.mock.calls[1][0]).toEqual({
519526
description: '<DecoratedComponent>',
520527
op: 'ui.angular.ngAfterViewInit',
528+
origin: 'auto.ui.angular.trace_method_decorator',
521529
startTimestamp: expect.any(Number),
522530
endTimestamp: expect.any(Number),
523531
});

packages/browser/src/profiling/hubextensions.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,11 @@ export function wrapTransactionWithProfiling(transaction: Transaction): Transact
174174

175175
// This is temporary - we will use the collected span data to evaluate
176176
// if deferring txn.finish until profiler resolves is a viable approach.
177-
const stopProfilerSpan = transaction.startChild({ description: 'profiler.stop', op: 'profiler' });
177+
const stopProfilerSpan = transaction.startChild({
178+
description: 'profiler.stop',
179+
op: 'profiler',
180+
origin: 'auto.profiler.browser',
181+
});
178182

179183
return profiler
180184
.stop()

packages/core/src/tracing/span.ts

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
Primitive,
55
Span as SpanInterface,
66
SpanContext,
7+
SpanOrigin,
78
TraceContext,
89
Transaction,
910
} from '@sentry/types';
@@ -115,30 +116,27 @@ export class Span implements SpanInterface {
115116
*/
116117
public instrumenter: Instrumenter;
117118

119+
/**
120+
* The origin of the span, giving context about what created the span.
121+
*/
122+
public origin?: SpanOrigin;
123+
118124
/**
119125
* You should never call the constructor manually, always use `Sentry.startTransaction()`
120126
* or call `startChild()` on an existing span.
121127
* @internal
122128
* @hideconstructor
123129
* @hidden
124130
*/
125-
public constructor(spanContext?: SpanContext) {
126-
this.traceId = uuid4();
127-
this.spanId = uuid4().substring(16);
128-
this.startTimestamp = timestampInSeconds();
129-
this.tags = {};
130-
this.data = {};
131-
this.instrumenter = 'sentry';
132-
133-
if (!spanContext) {
134-
return this;
135-
}
136-
if (spanContext.traceId) {
137-
this.traceId = spanContext.traceId;
138-
}
139-
if (spanContext.spanId) {
140-
this.spanId = spanContext.spanId;
141-
}
131+
public constructor(spanContext: SpanContext = {}) {
132+
this.traceId = spanContext.traceId || uuid4();
133+
this.spanId = spanContext.spanId || uuid4().substring(16);
134+
this.startTimestamp = spanContext.startTimestamp || timestampInSeconds();
135+
this.tags = spanContext.tags || {};
136+
this.data = spanContext.data || {};
137+
this.instrumenter = spanContext.instrumenter || 'sentry';
138+
this.origin = spanContext.origin || 'manual';
139+
142140
if (spanContext.parentSpanId) {
143141
this.parentSpanId = spanContext.parentSpanId;
144142
}
@@ -155,24 +153,12 @@ export class Span implements SpanInterface {
155153
if (spanContext.name) {
156154
this.description = spanContext.name;
157155
}
158-
if (spanContext.data) {
159-
this.data = spanContext.data;
160-
}
161-
if (spanContext.tags) {
162-
this.tags = spanContext.tags;
163-
}
164156
if (spanContext.status) {
165157
this.status = spanContext.status;
166158
}
167-
if (spanContext.startTimestamp) {
168-
this.startTimestamp = spanContext.startTimestamp;
169-
}
170159
if (spanContext.endTimestamp) {
171160
this.endTimestamp = spanContext.endTimestamp;
172161
}
173-
if (spanContext.instrumenter) {
174-
this.instrumenter = spanContext.instrumenter;
175-
}
176162
}
177163

178164
/**
@@ -355,6 +341,7 @@ export class Span implements SpanInterface {
355341
tags?: { [key: string]: Primitive };
356342
timestamp?: number;
357343
trace_id: string;
344+
origin?: SpanOrigin;
358345
} {
359346
return dropUndefinedKeys({
360347
data: Object.keys(this.data).length > 0 ? this.data : undefined,
@@ -367,6 +354,7 @@ export class Span implements SpanInterface {
367354
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined,
368355
timestamp: this.endTimestamp,
369356
trace_id: this.traceId,
357+
origin: this.origin,
370358
});
371359
}
372360
}

packages/ember/addon/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,14 @@ export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute
8787
if (!currentTransaction) {
8888
return result;
8989
}
90-
currentTransaction.startChild({ op, description, startTimestamp }).finish();
90+
currentTransaction
91+
.startChild({
92+
op,
93+
description,
94+
origin: 'auto.ui.ember',
95+
startTimestamp,
96+
})
97+
.finish();
9198
return result;
9299
};
93100

packages/ember/addon/instance-initializers/sentry-performance.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ export function _instrumentEmberRouter(
119119
activeTransaction = startTransaction({
120120
name: `route:${routeInfo.name}`,
121121
op: 'pageload',
122+
origin: 'auto.pageload.ember',
122123
tags: {
123124
url,
124125
toRoute: routeInfo.name,
@@ -141,6 +142,7 @@ export function _instrumentEmberRouter(
141142
activeTransaction = startTransaction({
142143
name: `route:${toRoute}`,
143144
op: 'navigation',
145+
origin: 'auto.navigation.ember',
144146
tags: {
145147
fromRoute,
146148
toRoute,
@@ -150,6 +152,7 @@ export function _instrumentEmberRouter(
150152
transitionSpan = activeTransaction?.startChild({
151153
op: 'ui.ember.transition',
152154
description: `route:${fromRoute} -> route:${toRoute}`,
155+
origin: 'auto.ui.ember',
153156
});
154157
});
155158

@@ -211,6 +214,7 @@ function _instrumentEmberRunloop(config: EmberSentryConfig): void {
211214
activeTransaction
212215
?.startChild({
213216
op: `ui.ember.runloop.${queue}`,
217+
origin: 'auto.ui.ember',
214218
startTimestamp: currentQueueStart,
215219
endTimestamp: now,
216220
})
@@ -287,6 +291,7 @@ function processComponentRenderAfter(
287291
activeTransaction?.startChild({
288292
op,
289293
description: payload.containerKey || payload.object,
294+
origin: 'auto.ui.ember',
290295
startTimestamp: begin.now,
291296
endTimestamp: now,
292297
});
@@ -370,6 +375,7 @@ function _instrumentInitialLoad(config: EmberSentryConfig): void {
370375
const transaction = getActiveTransaction();
371376
const span = transaction?.startChild({
372377
op: 'ui.ember.init',
378+
origin: 'auto.ui.ember',
373379
startTimestamp,
374380
});
375381
span?.finish(endTimestamp);

packages/nextjs/src/client/performance.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export function nextRouterInstrumentation(
178178
const nextRouteChangeSpan = navigationTransaction.startChild({
179179
op: 'ui.nextjs.route-change',
180180
description: 'Next.js Route Change',
181+
origin: 'auto.navigation.nextjs',
181182
});
182183

183184
const finishRouteChangeSpan = (): void => {

packages/nextjs/src/common/utils/edgeWrapperUtils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export function withEdgeWrapping<H extends EdgeRouteHandler>(
2323
span = prevSpan.startChild({
2424
description: options.spanDescription,
2525
op: options.spanOp,
26+
origin: 'auto.function.nextjs',
2627
});
2728
} else if (req instanceof Request) {
2829
const sentryTrace = req.headers.get('sentry-trace') || '';
@@ -39,6 +40,7 @@ export function withEdgeWrapping<H extends EdgeRouteHandler>(
3940
span = startTransaction({
4041
name: options.spanDescription,
4142
op: options.spanOp,
43+
origin: 'auto.ui.nextjs.withEdgeWrapping',
4244
...traceparentData,
4345
metadata: {
4446
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,

packages/nextjs/src/common/utils/wrapperUtils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
104104
{
105105
op: 'http.server',
106106
name: options.requestedRouteName,
107+
origin: 'auto.function.nextjs',
107108
...traceparentData,
108109
status: 'ok',
109110
metadata: {
@@ -131,12 +132,14 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
131132
dataFetcherSpan = spanToContinue.startChild({
132133
op: 'function.nextjs',
133134
description: `${options.dataFetchingMethodName} (${options.dataFetcherRouteName})`,
135+
origin: 'auto.function.nextjs',
134136
status: 'ok',
135137
});
136138
} else {
137139
dataFetcherSpan = startTransaction({
138140
op: 'function.nextjs',
139141
name: `${options.dataFetchingMethodName} (${options.dataFetcherRouteName})`,
142+
origin: 'auto.function.nextjs',
140143
...traceparentData,
141144
status: 'ok',
142145
metadata: {
@@ -203,6 +206,7 @@ export async function callDataFetcherTraced<F extends (...args: any[]) => Promis
203206
// route's transaction
204207
const span = transaction.startChild({
205208
op: 'function.nextjs',
209+
origin: 'auto.function.nextjs',
206210
description: `${dataFetchingMethodName} (${parameterizedRoute})`,
207211
status: 'ok',
208212
});

packages/nextjs/src/common/wrapApiHandlerWithSentry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ export function withSentry(apiHandler: NextApiHandler, parameterizedRoute?: stri
129129
{
130130
name: `${reqMethod}${reqPath}`,
131131
op: 'http.server',
132+
origin: 'auto.http.nextjs',
132133
...traceparentData,
133134
metadata: {
134135
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,

packages/nextjs/src/common/wrapServerComponentWithSentry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
4343
op: 'function.nextjs',
4444
name: `${componentType} Server Component (${componentRoute})`,
4545
status: 'ok',
46+
origin: 'auto.function.nextjs',
4647
...traceparentData,
4748
metadata: {
4849
source: 'component',

packages/nextjs/test/config/withSentry.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ describe('withSentry', () => {
8080
{
8181
name: 'GET http://dogs.are.great',
8282
op: 'http.server',
83+
origin: 'auto.http.nextjs',
8384

8485
metadata: {
8586
source: 'route',

packages/node-experimental/src/integrations/express.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
3+
import { addOtelSpanData } from '@sentry/opentelemetry-node';
34
import type { Integration } from '@sentry/types';
45

56
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
@@ -27,6 +28,14 @@ export class Express extends NodePerformanceIntegration<void> implements Integra
2728

2829
/** @inheritDoc */
2930
public setupInstrumentation(): void | Instrumentation[] {
30-
return [new ExpressInstrumentation()];
31+
return [
32+
new ExpressInstrumentation({
33+
requestHook(span) {
34+
addOtelSpanData(span.spanContext().spanId, {
35+
origin: 'auto.http.otel-express',
36+
});
37+
},
38+
}),
39+
];
3140
}
3241
}

0 commit comments

Comments
 (0)