Skip to content

Commit 5fd5c5d

Browse files
authored
feat(angular): Export custom browserTracingIntegration() (#10353)
Also deprecate the routing Instrumentation. This is WIP on top of #10351, to show how that would work. No idea how to get the tests working for this, though...
1 parent 6155af5 commit 5fd5c5d

File tree

8 files changed

+104
-25
lines changed

8 files changed

+104
-25
lines changed

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ import * as Sentry from '@sentry/angular-ivy';
77
Sentry.init({
88
dsn: 'https://3b6c388182fb435097f41d181be2b2ba@o4504321058471936.ingest.sentry.io/4504321066008576',
99
tracesSampleRate: 1.0,
10-
integrations: [
11-
new Sentry.BrowserTracing({
12-
routingInstrumentation: Sentry.routingInstrumentation,
13-
}),
14-
],
10+
integrations: [Sentry.browserTracingIntegration({})],
1511
tunnel: `http://localhost:3031/`, // proxy server
1612
debug: true,
1713
});

packages/angular-ivy/README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,14 @@ Registering a Trace Service is a 3-step process.
9393
instrumentation:
9494

9595
```javascript
96-
import { init, instrumentAngularRouting, BrowserTracing } from '@sentry/angular-ivy';
96+
import { init, browserTracingIntegration } from '@sentry/angular-ivy';
9797

9898
init({
9999
dsn: '__DSN__',
100-
integrations: [
101-
new BrowserTracing({
102-
tracingOrigins: ['localhost', 'https://yourserver.io/api'],
103-
routingInstrumentation: instrumentAngularRouting,
104-
}),
100+
integrations: [
101+
browserTracingIntegration(),
105102
],
103+
tracePropagationTargets: ['localhost', 'https://yourserver.io/api'],
106104
tracesSampleRate: 1,
107105
});
108106
```

packages/angular/README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,14 @@ Registering a Trace Service is a 3-step process.
9393
instrumentation:
9494

9595
```javascript
96-
import { init, instrumentAngularRouting, BrowserTracing } from '@sentry/angular';
96+
import { init, browserTracingIntegration } from '@sentry/angular';
9797

9898
init({
9999
dsn: '__DSN__',
100100
integrations: [
101-
new BrowserTracing({
102-
tracingOrigins: ['localhost', 'https://yourserver.io/api'],
103-
routingInstrumentation: instrumentAngularRouting,
104-
}),
101+
browserTracingIntegration(),
105102
],
103+
tracePropagationTargets: ['localhost', 'https://yourserver.io/api'],
106104
tracesSampleRate: 1,
107105
});
108106
```

packages/angular/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ export { createErrorHandler, SentryErrorHandler } from './errorhandler';
77
export {
88
// eslint-disable-next-line deprecation/deprecation
99
getActiveTransaction,
10-
// TODO `instrumentAngularRouting` is just an alias for `routingInstrumentation`; deprecate the latter at some point
10+
// eslint-disable-next-line deprecation/deprecation
1111
instrumentAngularRouting, // new name
12+
// eslint-disable-next-line deprecation/deprecation
1213
routingInstrumentation, // legacy name
14+
browserTracingIntegration,
1315
TraceClassDecorator,
1416
TraceMethodDecorator,
1517
TraceDirective,

packages/angular/src/tracing.ts

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,21 @@ import type { ActivatedRouteSnapshot, Event, RouterState } from '@angular/router
77
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
88
import { NavigationCancel, NavigationError, Router } from '@angular/router';
99
import { NavigationEnd, NavigationStart, ResolveEnd } from '@angular/router';
10-
import { WINDOW, getCurrentScope } from '@sentry/browser';
11-
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, spanToJSON } from '@sentry/core';
12-
import type { Span, Transaction, TransactionContext } from '@sentry/types';
10+
import {
11+
WINDOW,
12+
browserTracingIntegration as originalBrowserTracingIntegration,
13+
getCurrentScope,
14+
startBrowserTracingNavigationSpan,
15+
} from '@sentry/browser';
16+
import {
17+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
18+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
19+
getActiveSpan,
20+
getClient,
21+
spanToJSON,
22+
startInactiveSpan,
23+
} from '@sentry/core';
24+
import type { Integration, Span, Transaction, TransactionContext } from '@sentry/types';
1325
import { logger, stripUrlQueryAndFragment, timestampInSeconds } from '@sentry/utils';
1426
import type { Observable } from 'rxjs';
1527
import { Subscription } from 'rxjs';
@@ -23,8 +35,12 @@ let instrumentationInitialized: boolean;
2335
let stashedStartTransaction: (context: TransactionContext) => Transaction | undefined;
2436
let stashedStartTransactionOnLocationChange: boolean;
2537

38+
let hooksBasedInstrumentation = false;
39+
2640
/**
2741
* Creates routing instrumentation for Angular Router.
42+
*
43+
* @deprecated Use `browserTracingIntegration()` instead, which includes Angular-specific instrumentation out of the box.
2844
*/
2945
export function routingInstrumentation(
3046
customStartTransaction: (context: TransactionContext) => Transaction | undefined,
@@ -47,8 +63,35 @@ export function routingInstrumentation(
4763
}
4864
}
4965

66+
/**
67+
* Creates routing instrumentation for Angular Router.
68+
*
69+
* @deprecated Use `browserTracingIntegration()` instead, which includes Angular-specific instrumentation out of the box.
70+
*/
71+
// eslint-disable-next-line deprecation/deprecation
5072
export const instrumentAngularRouting = routingInstrumentation;
5173

74+
/**
75+
* A custom BrowserTracing integration for Angular.
76+
*
77+
* Use this integration in combination with `TraceService`
78+
*/
79+
export function browserTracingIntegration(
80+
options: Parameters<typeof originalBrowserTracingIntegration>[0] = {},
81+
): Integration {
82+
// If the user opts out to set this up, we just don't initialize this.
83+
// That way, the TraceService will not actually do anything, functionally disabling this.
84+
if (options.instrumentNavigation !== false) {
85+
instrumentationInitialized = true;
86+
hooksBasedInstrumentation = true;
87+
}
88+
89+
return originalBrowserTracingIntegration({
90+
...options,
91+
instrumentNavigation: false,
92+
});
93+
}
94+
5295
/**
5396
* Grabs active transaction off scope.
5497
*
@@ -74,7 +117,44 @@ export class TraceService implements OnDestroy {
74117
return;
75118
}
76119

120+
if (this._routingSpan) {
121+
this._routingSpan.end();
122+
this._routingSpan = null;
123+
}
124+
125+
const client = getClient();
77126
const strippedUrl = stripUrlQueryAndFragment(navigationEvent.url);
127+
128+
if (client && hooksBasedInstrumentation) {
129+
if (!getActiveSpan()) {
130+
startBrowserTracingNavigationSpan(client, {
131+
name: strippedUrl,
132+
op: 'navigation',
133+
origin: 'auto.navigation.angular',
134+
attributes: {
135+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
136+
},
137+
});
138+
}
139+
140+
// eslint-disable-next-line deprecation/deprecation
141+
this._routingSpan =
142+
startInactiveSpan({
143+
name: `${navigationEvent.url}`,
144+
op: ANGULAR_ROUTING_OP,
145+
origin: 'auto.ui.angular',
146+
tags: {
147+
'routing.instrumentation': '@sentry/angular',
148+
url: strippedUrl,
149+
...(navigationEvent.navigationTrigger && {
150+
navigationTrigger: navigationEvent.navigationTrigger,
151+
}),
152+
},
153+
}) || null;
154+
155+
return;
156+
}
157+
78158
// eslint-disable-next-line deprecation/deprecation
79159
let activeTransaction = getActiveTransaction();
80160

@@ -90,9 +170,6 @@ export class TraceService implements OnDestroy {
90170
}
91171

92172
if (activeTransaction) {
93-
if (this._routingSpan) {
94-
this._routingSpan.end();
95-
}
96173
// eslint-disable-next-line deprecation/deprecation
97174
this._routingSpan = activeTransaction.startChild({
98175
description: `${navigationEvent.url}`,
@@ -132,6 +209,7 @@ export class TraceService implements OnDestroy {
132209
if (transaction && attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === 'url') {
133210
transaction.updateName(route);
134211
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
212+
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, `auto.${spanToJSON(transaction).op}.angular`);
135213
}
136214
}),
137215
);

packages/angular/test/tracing.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ describe('Angular Tracing', () => {
4444
transaction = undefined;
4545
});
4646

47+
/* eslint-disable deprecation/deprecation */
4748
describe('instrumentAngularRouting', () => {
4849
it('should attach the transaction source on the pageload transaction', () => {
4950
const startTransaction = jest.fn();
@@ -57,6 +58,7 @@ describe('Angular Tracing', () => {
5758
});
5859
});
5960
});
61+
/* eslint-enable deprecation/deprecation */
6062

6163
describe('getParameterizedRouteFromSnapshot', () => {
6264
it.each([

packages/angular/test/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export class TestEnv {
5050
useTraceService?: boolean;
5151
additionalProviders?: Provider[];
5252
}): Promise<TestEnv> {
53+
// eslint-disable-next-line deprecation/deprecation
5354
instrumentAngularRouting(
5455
conf.customStartTransaction || jest.fn(),
5556
conf.startTransactionOnPageLoad !== undefined ? conf.startTransactionOnPageLoad : true,

packages/tracing-internal/src/browser/browserTracingIntegration.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,9 @@ export const browserTracingIntegration = ((_options: Partial<BrowserTracingOptio
336336
startTimestamp: browserPerformanceTimeOrigin ? browserPerformanceTimeOrigin / 1000 : undefined,
337337
op: 'pageload',
338338
origin: 'auto.pageload.browser',
339-
metadata: { source: 'url' },
339+
attributes: {
340+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
341+
},
340342
};
341343
startBrowserTracingPageLoadSpan(client, context);
342344
}
@@ -363,7 +365,9 @@ export const browserTracingIntegration = ((_options: Partial<BrowserTracingOptio
363365
name: WINDOW.location.pathname,
364366
op: 'navigation',
365367
origin: 'auto.navigation.browser',
366-
metadata: { source: 'url' },
368+
attributes: {
369+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
370+
},
367371
};
368372

369373
startBrowserTracingNavigationSpan(client, context);

0 commit comments

Comments
 (0)