Skip to content

Commit 81da58a

Browse files
authored
feat(angular/v8): Change decorator naming and add name parameter (#11057)
closes #11038
1 parent 88d41ea commit 81da58a

File tree

7 files changed

+84
-32
lines changed

7 files changed

+84
-32
lines changed

MIGRATION.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,35 @@ The SDK no longer filters out health check transactions by default. Instead, the
777777
by the Sentry backend by default. You can disable dropping them in your Sentry project settings. If you still want to
778778
drop specific transactions within the SDK you can either use the `ignoreTransactions` SDK option.
779779

780+
#### Angular Tracing Decorator renaming
781+
782+
The usage of `TraceClassDecorator` and the `TraceMethodDecorator` already implies that those are decorators. The word
783+
`Decorator` is now removed from the names to avoid multiple mentioning.
784+
785+
Additionally, the `TraceClass` and `TraceMethod` decorators accept an optional `name` parameter to set the transaction
786+
name. This was added because Angular minifies class and method names, and you might want to set a more descriptive name.
787+
If nothing provided, the name defaults to `'unnamed'`.
788+
789+
```js
790+
// v7
791+
@Sentry.TraceClassDecorator()
792+
export class HeaderComponent {
793+
@Sentry.TraceMethodDecorator()
794+
ngOnChanges(changes: SimpleChanges) {}
795+
}
796+
```
797+
798+
```js
799+
// v8
800+
@Sentry.TraceClass({ name: 'HeaderComponent' })
801+
export class HeaderComponent {
802+
@Sentry.TraceMethod({ name: 'ngOnChanges' })
803+
ngOnChanges(changes: SimpleChanges) {}
804+
}
805+
```
806+
807+
---
808+
780809
# Deprecations in 7.x
781810

782811
You can use the **Experimental** [@sentry/migr8](https://www.npmjs.com/package/@sentry/migr8) to automatically update
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AfterViewInit, Component, OnInit } from '@angular/core';
2-
import { TraceClassDecorator, TraceMethodDecorator, TraceModule } from '@sentry/angular-ivy';
2+
import { TraceClass, TraceMethod, TraceModule } from '@sentry/angular-ivy';
33
import { SampleComponent } from '../sample-component/sample-component.components';
44

55
@Component({
@@ -8,11 +8,11 @@ import { SampleComponent } from '../sample-component/sample-component.components
88
imports: [TraceModule, SampleComponent],
99
template: `<app-sample-component [trace]="'sample-component'"></app-sample-component>`,
1010
})
11-
@TraceClassDecorator()
11+
@TraceClass({ name: 'ComponentTrackingComponent' })
1212
export class ComponentTrackingComponent implements OnInit, AfterViewInit {
13-
@TraceMethodDecorator()
13+
@TraceMethod({ name: 'ngOnInit' })
1414
ngOnInit() {}
1515

16-
@TraceMethodDecorator()
16+
@TraceMethod()
1717
ngAfterViewInit() {}
1818
}

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ test.describe('TraceDirective', () => {
222222
});
223223
});
224224

225-
test.describe('TraceClassDecorator', () => {
225+
test.describe('TraceClass Decorator', () => {
226226
test('adds init span for decorated class', async ({ page }) => {
227227
const navigationTxnPromise = waitForTransaction('angular-17', async transactionEvent => {
228228
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'navigation';
@@ -244,8 +244,7 @@ test.describe('TraceClassDecorator', () => {
244244
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.angular.init',
245245
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.angular.trace_class_decorator',
246246
},
247-
// todo: right now, it shows the minified version of the component name - we will add a name input to the Decorator
248-
description: expect.any(String),
247+
description: '<ComponentTrackingComponent>',
249248
op: 'ui.angular.init',
250249
origin: 'auto.ui.angular.trace_class_decorator',
251250
start_timestamp: expect.any(Number),
@@ -255,8 +254,8 @@ test.describe('TraceClassDecorator', () => {
255254
});
256255
});
257256

258-
test.describe('TraceMethodDecorator', () => {
259-
test('instruments decorated methods (`ngOnInit` and `ngAfterViewInit`)', async ({ page }) => {
257+
test.describe('TraceMethod Decorator', () => {
258+
test('adds name to span description of decorated method `ngOnInit`', async ({ page }) => {
260259
const navigationTxnPromise = waitForTransaction('angular-17', async transactionEvent => {
261260
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'navigation';
262261
});
@@ -267,7 +266,6 @@ test.describe('TraceMethodDecorator', () => {
267266
const [_, navigationTxn] = await Promise.all([page.locator('#componentTracking').click(), navigationTxnPromise]);
268267

269268
const ngInitSpan = navigationTxn.spans?.find(span => span.op === 'ui.angular.ngOnInit');
270-
const ngAfterViewInitSpan = navigationTxn.spans?.find(span => span.op === 'ui.angular.ngAfterViewInit');
271269

272270
expect(ngInitSpan).toBeDefined();
273271
expect(ngInitSpan).toEqual(
@@ -276,14 +274,26 @@ test.describe('TraceMethodDecorator', () => {
276274
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.angular.ngOnInit',
277275
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.angular.trace_method_decorator',
278276
},
279-
// todo: right now, it shows the minified version of the component name - we will add a name input to the Decorator
280-
description: expect.any(String),
277+
description: '<ngOnInit>',
281278
op: 'ui.angular.ngOnInit',
282279
origin: 'auto.ui.angular.trace_method_decorator',
283280
start_timestamp: expect.any(Number),
284281
timestamp: expect.any(Number),
285282
}),
286283
);
284+
});
285+
286+
test('adds fallback name to span description of decorated method `ngAfterViewInit`', async ({ page }) => {
287+
const navigationTxnPromise = waitForTransaction('angular-17', async transactionEvent => {
288+
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'navigation';
289+
});
290+
291+
await page.goto(`/`);
292+
293+
// immediately navigate to a different route
294+
const [_, navigationTxn] = await Promise.all([page.locator('#componentTracking').click(), navigationTxnPromise]);
295+
296+
const ngAfterViewInitSpan = navigationTxn.spans?.find(span => span.op === 'ui.angular.ngAfterViewInit');
287297

288298
expect(ngAfterViewInitSpan).toBeDefined();
289299
expect(ngAfterViewInitSpan).toEqual(
@@ -292,8 +302,7 @@ test.describe('TraceMethodDecorator', () => {
292302
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.angular.ngAfterViewInit',
293303
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.angular.trace_method_decorator',
294304
},
295-
// todo: right now, it shows the minified version of the component name - we will add a name input to the Decorator
296-
description: expect.any(String),
305+
description: '<unnamed>',
297306
op: 'ui.angular.ngAfterViewInit',
298307
origin: 'auto.ui.angular.trace_method_decorator',
299308
start_timestamp: expect.any(Number),

packages/angular-ivy/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,34 +181,34 @@ Then, inside your component's template (keep in mind that the directive's name a
181181
<app-footer trace="footer"></app-footer>
182182
```
183183

184-
_TraceClassDecorator:_ used to track a duration between `OnInit` and `AfterViewInit` lifecycle hooks in components:
184+
_TraceClass:_ used to track a duration between `OnInit` and `AfterViewInit` lifecycle hooks in components:
185185

186186
```javascript
187187
import { Component } from '@angular/core';
188-
import { TraceClassDecorator } from '@sentry/angular-ivy';
188+
import { TraceClass } from '@sentry/angular-ivy';
189189

190190
@Component({
191191
selector: 'layout-header',
192192
templateUrl: './header.component.html',
193193
})
194-
@TraceClassDecorator()
194+
@TraceClass()
195195
export class HeaderComponent {
196196
// ...
197197
}
198198
```
199199

200-
_TraceMethodDecorator:_ used to track a specific lifecycle hooks as point-in-time spans in components:
200+
_TraceMethod:_ used to track a specific lifecycle hooks as point-in-time spans in components:
201201

202202
```javascript
203203
import { Component, OnInit } from '@angular/core';
204-
import { TraceMethodDecorator } from '@sentry/angular-ivy';
204+
import { TraceMethod } from '@sentry/angular-ivy';
205205

206206
@Component({
207207
selector: 'app-footer',
208208
templateUrl: './footer.component.html',
209209
})
210210
export class FooterComponent implements OnInit {
211-
@TraceMethodDecorator()
211+
@TraceMethod()
212212
ngOnInit() {}
213213
}
214214
```

packages/angular/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,34 +181,34 @@ Then, inside your component's template (keep in mind that the directive's name a
181181
<app-footer trace="footer"></app-footer>
182182
```
183183

184-
_TraceClassDecorator:_ used to track a duration between `OnInit` and `AfterViewInit` lifecycle hooks in components:
184+
_TraceClass:_ used to track a duration between `OnInit` and `AfterViewInit` lifecycle hooks in components:
185185

186186
```javascript
187187
import { Component } from '@angular/core';
188-
import { TraceClassDecorator } from '@sentry/angular';
188+
import { TraceClass } from '@sentry/angular';
189189

190190
@Component({
191191
selector: 'layout-header',
192192
templateUrl: './header.component.html',
193193
})
194-
@TraceClassDecorator()
194+
@TraceClass()
195195
export class HeaderComponent {
196196
// ...
197197
}
198198
```
199199

200-
_TraceMethodDecorator:_ used to track a specific lifecycle hooks as point-in-time spans in components:
200+
_TraceMethod:_ used to track a specific lifecycle hooks as point-in-time spans in components:
201201

202202
```javascript
203203
import { Component, OnInit } from '@angular/core';
204-
import { TraceMethodDecorator } from '@sentry/angular';
204+
import { TraceMethod } from '@sentry/angular';
205205

206206
@Component({
207207
selector: 'app-footer',
208208
templateUrl: './footer.component.html',
209209
})
210210
export class FooterComponent implements OnInit {
211-
@TraceMethodDecorator()
211+
@TraceMethod()
212212
ngOnInit() {}
213213
}
214214
```

packages/angular/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ export { init } from './sdk';
66
export { createErrorHandler, SentryErrorHandler } from './errorhandler';
77
export {
88
browserTracingIntegration,
9-
TraceClassDecorator,
10-
TraceMethodDecorator,
9+
TraceClass,
10+
TraceMethod,
1111
TraceDirective,
1212
TraceModule,
1313
TraceService,

packages/angular/src/tracing.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,17 @@ export class TraceDirective implements OnInit, AfterViewInit {
280280
})
281281
export class TraceModule {}
282282

283+
interface TraceClassOptions {
284+
/**
285+
* Name of the class
286+
*/
287+
name?: string;
288+
}
289+
283290
/**
284291
* Decorator function that can be used to capture initialization lifecycle of the whole component.
285292
*/
286-
export function TraceClassDecorator(): ClassDecorator {
293+
export function TraceClass(options?: TraceClassOptions): ClassDecorator {
287294
let tracingSpan: Span;
288295

289296
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
@@ -293,7 +300,7 @@ export function TraceClassDecorator(): ClassDecorator {
293300
target.prototype.ngOnInit = function (...args: any[]): ReturnType<typeof originalOnInit> {
294301
tracingSpan = startInactiveSpan({
295302
onlyIfParent: true,
296-
name: `<${target.name}>`,
303+
name: `<${options && options.name ? options.name : 'unnamed'}>`,
297304
op: ANGULAR_INIT_OP,
298305
attributes: {
299306
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.angular.trace_class_decorator',
@@ -319,10 +326,17 @@ export function TraceClassDecorator(): ClassDecorator {
319326
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
320327
}
321328

329+
interface TraceMethodOptions {
330+
/**
331+
* Name of the method (is added to the tracing span)
332+
*/
333+
name?: string;
334+
}
335+
322336
/**
323337
* Decorator function that can be used to capture a single lifecycle methods of the component.
324338
*/
325-
export function TraceMethodDecorator(): MethodDecorator {
339+
export function TraceMethod(options?: TraceMethodOptions): MethodDecorator {
326340
// eslint-disable-next-line @typescript-eslint/ban-types
327341
return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
328342
const originalMethod = descriptor.value;
@@ -332,7 +346,7 @@ export function TraceMethodDecorator(): MethodDecorator {
332346

333347
startInactiveSpan({
334348
onlyIfParent: true,
335-
name: `<${target.constructor.name}>`,
349+
name: `<${options && options.name ? options.name : 'unnamed'}>`,
336350
op: `${ANGULAR_OP}.${String(propertyKey)}`,
337351
startTime: now,
338352
attributes: {

0 commit comments

Comments
 (0)