Skip to content

ref(tracing): Add origin to spans #8765

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/angular/src/tracing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function routingInstrumentation(
customStartTransaction({
name: WINDOW.location.pathname,
op: 'pageload',
origin: 'auto.pageload.angular',
metadata: { source: 'url' },
});
}
Expand Down Expand Up @@ -84,6 +85,7 @@ export class TraceService implements OnDestroy {
activeTransaction = stashedStartTransaction({
name: strippedUrl,
op: 'navigation',
origin: 'auto.navigation.angular',
metadata: { source: 'url' },
});
}
Expand All @@ -95,6 +97,7 @@ export class TraceService implements OnDestroy {
this._routingSpan = activeTransaction.startChild({
description: `${navigationEvent.url}`,
op: ANGULAR_ROUTING_OP,
origin: 'auto.ui.angular',
tags: {
'routing.instrumentation': '@sentry/angular',
url: strippedUrl,
Expand Down Expand Up @@ -192,6 +195,7 @@ export class TraceDirective implements OnInit, AfterViewInit {
this._tracingSpan = activeTransaction.startChild({
description: `<${this.componentName}>`,
op: ANGULAR_INIT_OP,
origin: 'auto.ui.angular.trace_directive',
});
}
}
Expand Down Expand Up @@ -233,6 +237,7 @@ export function TraceClassDecorator(): ClassDecorator {
tracingSpan = activeTransaction.startChild({
description: `<${target.name}>`,
op: ANGULAR_INIT_OP,
origin: 'auto.ui.angular.trace_class_decorator',
});
}
if (originalOnInit) {
Expand Down Expand Up @@ -270,6 +275,7 @@ export function TraceMethodDecorator(): MethodDecorator {
description: `<${target.constructor.name}>`,
endTimestamp: now,
op: `${ANGULAR_OP}.${String(propertyKey)}`,
origin: 'auto.ui.angular.trace_method_decorator',
startTimestamp: now,
});
}
Expand Down
8 changes: 8 additions & 0 deletions packages/angular/test/tracing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe('Angular Tracing', () => {
expect(startTransaction).toHaveBeenCalledWith({
name: '/',
op: 'pageload',
origin: 'auto.pageload.angular',
metadata: { source: 'url' },
});
});
Expand Down Expand Up @@ -137,6 +138,7 @@ describe('Angular Tracing', () => {
expect(customStartTransaction).toHaveBeenCalledWith({
name: url,
op: 'pageload',
origin: 'auto.pageload.angular',
metadata: { source: 'url' },
});

Expand Down Expand Up @@ -327,6 +329,7 @@ describe('Angular Tracing', () => {
expect(customStartTransaction).toHaveBeenCalledWith({
name: url,
op: 'navigation',
origin: 'auto.navigation.angular',
metadata: { source: 'url' },
});
expect(transaction.setName).toHaveBeenCalledWith(result, 'route');
Expand Down Expand Up @@ -358,6 +361,7 @@ describe('Angular Tracing', () => {

expect(transaction.startChild).toHaveBeenCalledWith({
op: 'ui.angular.init',
origin: 'auto.ui.angular.trace_directive',
description: '<unknown>',
});

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

expect(transaction.startChild).toHaveBeenCalledWith({
op: 'ui.angular.init',
origin: 'auto.ui.angular.trace_directive',
description: '<test-component>',
});

Expand Down Expand Up @@ -458,6 +463,7 @@ describe('Angular Tracing', () => {
expect(transaction.startChild).toHaveBeenCalledWith({
description: '<DecoratedComponent>',
op: 'ui.angular.init',
origin: 'auto.ui.angular.trace_class_decorator',
});

expect(origNgOnInitMock).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -511,13 +517,15 @@ describe('Angular Tracing', () => {
expect(transaction.startChild.mock.calls[0][0]).toEqual({
description: '<DecoratedComponent>',
op: 'ui.angular.ngOnInit',
origin: 'auto.ui.angular.trace_method_decorator',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
});

expect(transaction.startChild.mock.calls[1][0]).toEqual({
description: '<DecoratedComponent>',
op: 'ui.angular.ngAfterViewInit',
origin: 'auto.ui.angular.trace_method_decorator',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
});
Expand Down
6 changes: 5 additions & 1 deletion packages/browser/src/profiling/hubextensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,11 @@ export function wrapTransactionWithProfiling(transaction: Transaction): Transact

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

return profiler
.stop()
Expand Down
46 changes: 17 additions & 29 deletions packages/core/src/tracing/span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
Primitive,
Span as SpanInterface,
SpanContext,
SpanOrigin,
TraceContext,
Transaction,
} from '@sentry/types';
Expand Down Expand Up @@ -115,30 +116,27 @@ export class Span implements SpanInterface {
*/
public instrumenter: Instrumenter;

/**
* The origin of the span, giving context about what created the span.
*/
public origin?: SpanOrigin;

/**
* You should never call the constructor manually, always use `Sentry.startTransaction()`
* or call `startChild()` on an existing span.
* @internal
* @hideconstructor
* @hidden
*/
public constructor(spanContext?: SpanContext) {
this.traceId = uuid4();
this.spanId = uuid4().substring(16);
this.startTimestamp = timestampInSeconds();
this.tags = {};
this.data = {};
this.instrumenter = 'sentry';

if (!spanContext) {
return this;
}
if (spanContext.traceId) {
this.traceId = spanContext.traceId;
}
if (spanContext.spanId) {
this.spanId = spanContext.spanId;
}
public constructor(spanContext: SpanContext = {}) {
this.traceId = spanContext.traceId || uuid4();
this.spanId = spanContext.spanId || uuid4().substring(16);
this.startTimestamp = spanContext.startTimestamp || timestampInSeconds();
this.tags = spanContext.tags || {};
this.data = spanContext.data || {};
this.instrumenter = spanContext.instrumenter || 'sentry';
this.origin = spanContext.origin || 'manual';

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: (or no action required) we might wanna streamline some of the other assignments here as well but it's ouf of scope for this PR. feel free to ignore

if (spanContext.parentSpanId) {
this.parentSpanId = spanContext.parentSpanId;
}
Expand All @@ -155,24 +153,12 @@ export class Span implements SpanInterface {
if (spanContext.name) {
this.description = spanContext.name;
}
if (spanContext.data) {
this.data = spanContext.data;
}
if (spanContext.tags) {
this.tags = spanContext.tags;
}
if (spanContext.status) {
this.status = spanContext.status;
}
if (spanContext.startTimestamp) {
this.startTimestamp = spanContext.startTimestamp;
}
if (spanContext.endTimestamp) {
this.endTimestamp = spanContext.endTimestamp;
}
if (spanContext.instrumenter) {
this.instrumenter = spanContext.instrumenter;
}
}

/**
Expand Down Expand Up @@ -355,6 +341,7 @@ export class Span implements SpanInterface {
tags?: { [key: string]: Primitive };
timestamp?: number;
trace_id: string;
origin?: SpanOrigin;
} {
return dropUndefinedKeys({
data: Object.keys(this.data).length > 0 ? this.data : undefined,
Expand All @@ -367,6 +354,7 @@ export class Span implements SpanInterface {
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined,
timestamp: this.endTimestamp,
trace_id: this.traceId,
origin: this.origin,
});
}
}
Expand Down
9 changes: 8 additions & 1 deletion packages/ember/addon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,14 @@ export const instrumentRoutePerformance = <T extends RouteConstructor>(BaseRoute
if (!currentTransaction) {
return result;
}
currentTransaction.startChild({ op, description, startTimestamp }).finish();
currentTransaction
.startChild({
op,
description,
origin: 'auto.ui.ember',
startTimestamp,
})
.finish();
return result;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export function _instrumentEmberRouter(
activeTransaction = startTransaction({
name: `route:${routeInfo.name}`,
op: 'pageload',
origin: 'auto.pageload.ember',
tags: {
url,
toRoute: routeInfo.name,
Expand All @@ -141,6 +142,7 @@ export function _instrumentEmberRouter(
activeTransaction = startTransaction({
name: `route:${toRoute}`,
op: 'navigation',
origin: 'auto.navigation.ember',
tags: {
fromRoute,
toRoute,
Expand All @@ -150,6 +152,7 @@ export function _instrumentEmberRouter(
transitionSpan = activeTransaction?.startChild({
op: 'ui.ember.transition',
description: `route:${fromRoute} -> route:${toRoute}`,
origin: 'auto.ui.ember',
});
});

Expand Down Expand Up @@ -211,6 +214,7 @@ function _instrumentEmberRunloop(config: EmberSentryConfig): void {
activeTransaction
?.startChild({
op: `ui.ember.runloop.${queue}`,
origin: 'auto.ui.ember',
startTimestamp: currentQueueStart,
endTimestamp: now,
})
Expand Down Expand Up @@ -287,6 +291,7 @@ function processComponentRenderAfter(
activeTransaction?.startChild({
op,
description: payload.containerKey || payload.object,
origin: 'auto.ui.ember',
startTimestamp: begin.now,
endTimestamp: now,
});
Expand Down Expand Up @@ -370,6 +375,7 @@ function _instrumentInitialLoad(config: EmberSentryConfig): void {
const transaction = getActiveTransaction();
const span = transaction?.startChild({
op: 'ui.ember.init',
origin: 'auto.ui.ember',
startTimestamp,
});
span?.finish(endTimestamp);
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/src/client/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export function nextRouterInstrumentation(
const nextRouteChangeSpan = navigationTransaction.startChild({
op: 'ui.nextjs.route-change',
description: 'Next.js Route Change',
origin: 'auto.navigation.nextjs',
});

const finishRouteChangeSpan = (): void => {
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/src/common/utils/edgeWrapperUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function withEdgeWrapping<H extends EdgeRouteHandler>(
span = prevSpan.startChild({
description: options.spanDescription,
op: options.spanOp,
origin: 'auto.function.nextjs',
});
} else if (req instanceof Request) {
const sentryTrace = req.headers.get('sentry-trace') || '';
Expand All @@ -39,6 +40,7 @@ export function withEdgeWrapping<H extends EdgeRouteHandler>(
span = startTransaction({
name: options.spanDescription,
op: options.spanOp,
origin: 'auto.ui.nextjs.withEdgeWrapping',
...traceparentData,
metadata: {
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
Expand Down
4 changes: 4 additions & 0 deletions packages/nextjs/src/common/utils/wrapperUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
{
op: 'http.server',
name: options.requestedRouteName,
origin: 'auto.function.nextjs',
...traceparentData,
status: 'ok',
metadata: {
Expand Down Expand Up @@ -131,12 +132,14 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
dataFetcherSpan = spanToContinue.startChild({
op: 'function.nextjs',
description: `${options.dataFetchingMethodName} (${options.dataFetcherRouteName})`,
origin: 'auto.function.nextjs',
status: 'ok',
});
} else {
dataFetcherSpan = startTransaction({
op: 'function.nextjs',
name: `${options.dataFetchingMethodName} (${options.dataFetcherRouteName})`,
origin: 'auto.function.nextjs',
...traceparentData,
status: 'ok',
metadata: {
Expand Down Expand Up @@ -203,6 +206,7 @@ export async function callDataFetcherTraced<F extends (...args: any[]) => Promis
// route's transaction
const span = transaction.startChild({
op: 'function.nextjs',
origin: 'auto.function.nextjs',
description: `${dataFetchingMethodName} (${parameterizedRoute})`,
status: 'ok',
});
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/src/common/wrapApiHandlerWithSentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export function withSentry(apiHandler: NextApiHandler, parameterizedRoute?: stri
{
name: `${reqMethod}${reqPath}`,
op: 'http.server',
origin: 'auto.http.nextjs',
...traceparentData,
metadata: {
dynamicSamplingContext: traceparentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
op: 'function.nextjs',
name: `${componentType} Server Component (${componentRoute})`,
status: 'ok',
origin: 'auto.function.nextjs',
...traceparentData,
metadata: {
source: 'component',
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/test/config/withSentry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ describe('withSentry', () => {
{
name: 'GET http://dogs.are.great',
op: 'http.server',
origin: 'auto.http.nextjs',

metadata: {
source: 'route',
Expand Down
11 changes: 10 additions & 1 deletion packages/node-experimental/src/integrations/express.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Instrumentation } from '@opentelemetry/instrumentation';
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
import { addOtelSpanData } from '@sentry/opentelemetry-node';
import type { Integration } from '@sentry/types';

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

/** @inheritDoc */
public setupInstrumentation(): void | Instrumentation[] {
return [new ExpressInstrumentation()];
return [
new ExpressInstrumentation({
requestHook(span) {
addOtelSpanData(span.spanContext().spanId, {
origin: 'auto.http.otel-express',
});
},
}),
];
}
}
Loading