|
| 1 | +# Getting started with Performance Monitoring |
| 2 | + |
| 3 | +## Automatic page load tracing |
| 4 | + |
| 5 | +Understand your Angular application's real-world performance with [Firebase Performance Monitoring](https://firebase.google.com/docs/perf-mon). Performance Monitoring automatically provides a trace for **page load** when you add `AngularFirePerformanceModule` into your App Module's imports. |
| 6 | + |
| 7 | +```ts |
| 8 | +import { AngularFireModule } from '@angular/fire'; |
| 9 | +import { AngularFirePerformanceModule } from '@angular/fire/performance'; |
| 10 | +import { environment } from '../environments/environment'; |
| 11 | + |
| 12 | +@NgModule({ |
| 13 | + imports: [ |
| 14 | + BrowserModule, |
| 15 | + AngularFireModule.initializeApp(environment.firebase), |
| 16 | + AngularFirePerformanceModule, |
| 17 | + ... |
| 18 | + ], |
| 19 | + declarations: [ AppComponent ], |
| 20 | + bootstrap: [ AppComponent ] |
| 21 | +}) |
| 22 | +export class AppModule {} |
| 23 | +``` |
| 24 | + |
| 25 | +The page load trace breaks down into the following default metrics: |
| 26 | + |
| 27 | +* [first paint traces](https://firebase.google.com/docs/perf-mon/automatic-web#first-paint) — measure the time between when the user navigates to a page and when any visual change happens |
| 28 | +* [first contentful paint traces](https://firebase.google.com/docs/perf-mon/automatic-web#contentful-paint) — measure the time between when a user navigates to a page and when meaningful content displays, like an image or text |
| 29 | +* [domInteractive traces](https://firebase.google.com/docs/perf-mon/automatic-web#domInteractive) — measure the time between when the user navigates to a page and when the page is considered interactive for the user |
| 30 | +* [domContentLoadedEventEnd traces](https://firebase.google.com/docs/perf-mon/automatic-web#domContentLoaded) — measure the time between when the user navigates to a page and when the initial HTML document is completely loaded and parsed |
| 31 | +* [loadEventEnd traces](https://firebase.google.com/docs/perf-mon/automatic-web#loadEventEnd) — measure the time between when the user navigates to the page and when the current document's load event completes |
| 32 | +* [first input delay traces](https://firebase.google.com/docs/perf-mon/automatic-web#input-delay) — measure the time between when the user interacts with a page and when the browser is able to respond to that input |
| 33 | +* **Angular specific traces** - measure the time needed for `ApplicationRef.isStable` to be true, an important metric to track if you're concerned about solving Zone.js issues for proper functionality of NGSW and Server Side Rendering |
| 34 | + |
| 35 | +## Manual traces |
| 36 | + |
| 37 | +You can inject `AngularFirePerformance` to perform manual traces on Observables. |
| 38 | + |
| 39 | +```ts |
| 40 | +constructor(private afp: AngularFirePerformance, private afs: AngularFirestore) {} |
| 41 | + |
| 42 | +ngOnInit() { |
| 43 | + this.articles = afs.collection('articles') |
| 44 | + .collection('articles', ref => ref.orderBy('publishedAt', 'desc')) |
| 45 | + .snapshotChanges() |
| 46 | + .pipe( |
| 47 | + // measure the amount of time between the Observable being subscribed to and first emission (or completion) |
| 48 | + this.afp.trace('getArticles'), |
| 49 | + map(articles => ...) |
| 50 | + ); |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +### `trace(name:string)` |
| 55 | + |
| 56 | +The most basic operator, `trace` will measure the amount of time it takes for your observable to either complete or emit its first value. Beyond the basic trace there are several other operators: |
| 57 | + |
| 58 | +### `traceUntil(name:string, test: (T) => Boolean)` |
| 59 | + |
| 60 | +Trace the observable until the first emission that passes the provided test. |
| 61 | + |
| 62 | +### `traceWhile(name:string, test: (T) => Boolean)` |
| 63 | + |
| 64 | +Trace the observable until the first emission that fails the provided test. |
| 65 | + |
| 66 | +### `traceUntilLast(name:string)` |
| 67 | + |
| 68 | +Trace the observable until completion. |
| 69 | + |
| 70 | +### `traceUntilFirst(name: string)` |
| 71 | + |
| 72 | +Traces the observable until the first emission. |
| 73 | + |
| 74 | +## Advanced usage |
| 75 | + |
| 76 | +### Configuration via Dependency Injection |
| 77 | + |
| 78 | +By default, `AngularFirePerformanceModule` traces your Angular application's time to `ApplicationRef.isStable`. `isStable` is an important metric to track if you're concerned about proper functionality of NGSW and Server Side Rendering. If you want to opt-out of the tracing of this metric use the `AUTOMATICALLY_TRACE_CORE_NG_METRICS` injection token: |
| 79 | + |
| 80 | +```ts |
| 81 | +import { NgModule } from '@angular/core'; |
| 82 | +import { AngularFirePerformanceModule, AUTOMATICALLY_TRACE_CORE_NG_METRICS } from '@angular/fire/functions'; |
| 83 | + |
| 84 | +@NgModule({ |
| 85 | + imports: [ |
| 86 | + ... |
| 87 | + AngularFirePerformanceModule, |
| 88 | + ... |
| 89 | + ], |
| 90 | + ... |
| 91 | + providers: [ |
| 92 | + { provide: AUTOMATICALLY_TRACE_CORE_NG_METRICS, useValue: false } |
| 93 | + ] |
| 94 | +}) |
| 95 | +export class AppModule {} |
| 96 | +``` |
| 97 | + |
| 98 | +Similarly, setting `INSTRUMENTATION_ENABLED` or `DATA_COLLECTION_ENABLED` to false disable all automatic and custom traces respectively. |
| 99 | + |
| 100 | +### Get at an observable form of trace |
| 101 | + |
| 102 | +`trace$(name:string)` provides an observable version of `firebase/perf`'s `.trace` method; the basis for `AngularFirePerfomance`'s pipes. |
| 103 | + |
| 104 | +`.subscribe()` is equivalent to calling `.start()` |
| 105 | +`.unsubscribe()` is equivalent to calling `.stop()` |
| 106 | + |
| 107 | +### Using `TraceOptions` to collect additional metrics |
| 108 | + |
| 109 | +`TraceOptions` can be provided to the aformentioned operators to collect custom metrics and attributes on your traces: |
| 110 | + |
| 111 | +```ts |
| 112 | +type TraceOptions = { |
| 113 | + metrics?: { [key:string]: number }, |
| 114 | + attributes?: { [key:string]: string }, |
| 115 | + attribute$?: { [key:string]: Observable<string> }, |
| 116 | + incrementMetric$: { [key:string]: Observable<number|void|null|undefined> }, |
| 117 | + metric$?: { [key:string]: Observable<number> } |
| 118 | +}; |
| 119 | +``` |
| 120 | + |
| 121 | +#### Usage: |
| 122 | + |
| 123 | +```ts |
| 124 | +const articleLength$ = this.articles.pipe( |
| 125 | + map(actions => actions.length) |
| 126 | +); |
| 127 | + |
| 128 | +const articleSize$ = this.articles.pipe( |
| 129 | + map(actions => actions.reduce((sum, a) => sum += JSON.stringify(a.payload.doc.data()).length)) |
| 130 | +) |
| 131 | + |
| 132 | +this.articles = afs.collection('articles') |
| 133 | + .collection('articles', ref => ref.orderBy('publishedAt', 'desc')) |
| 134 | + .snapshotChanges() |
| 135 | + .pipe( |
| 136 | + this.afp.trace('getArticles', { |
| 137 | + attributes: { gitSha: '1d277f823ad98dd739fb86e9a6c440aa8237ff3a' }, |
| 138 | + metrics: { something: 42 }, |
| 139 | + metrics$: { count: articleLength$, size: articleSize$ }, |
| 140 | + attributes$: { user: this.afAuth.user }, |
| 141 | + incrementMetric$: { buttonClicks: fromEvent(button, 'click') } |
| 142 | + }), |
| 143 | + share() |
| 144 | + ); |
| 145 | +``` |
0 commit comments