-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(performance): AngularFire Performance Monitoring (#2064)
* AngularFirePerformance! * Build with node:lts and longer timeout * Don't blow up when ng v8 or 9-rc drop * Changelog for 5.2 * Change package.json to angular/fire for new github design
- Loading branch information
1 parent
e32164d
commit 2469e77
Showing
22 changed files
with
473 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# Getting started with Performance Monitoring | ||
|
||
## Automatic page load tracing | ||
|
||
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. | ||
|
||
```ts | ||
import { AngularFireModule } from '@angular/fire'; | ||
import { AngularFirePerformanceModule } from '@angular/fire/performance'; | ||
import { environment } from '../environments/environment'; | ||
|
||
@NgModule({ | ||
imports: [ | ||
BrowserModule, | ||
AngularFireModule.initializeApp(environment.firebase), | ||
AngularFirePerformanceModule, | ||
... | ||
], | ||
declarations: [ AppComponent ], | ||
bootstrap: [ AppComponent ] | ||
}) | ||
export class AppModule {} | ||
``` | ||
|
||
The page load trace breaks down into the following default metrics: | ||
|
||
* [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 | ||
* [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 | ||
* [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 | ||
* [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 | ||
* [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 | ||
* [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 | ||
* **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 | ||
|
||
## Manual traces | ||
|
||
You can inject `AngularFirePerformance` to perform manual traces on Observables. | ||
|
||
```ts | ||
constructor(private afp: AngularFirePerformance, private afs: AngularFirestore) {} | ||
|
||
ngOnInit() { | ||
this.articles = afs.collection('articles') | ||
.collection('articles', ref => ref.orderBy('publishedAt', 'desc')) | ||
.snapshotChanges() | ||
.pipe( | ||
// measure the amount of time between the Observable being subscribed to and first emission (or completion) | ||
this.afp.trace('getArticles'), | ||
map(articles => ...) | ||
); | ||
} | ||
``` | ||
|
||
### `trace(name:string)` | ||
|
||
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: | ||
|
||
### `traceUntil(name:string, test: (T) => Boolean)` | ||
|
||
Trace the observable until the first emission that passes the provided test. | ||
|
||
### `traceWhile(name:string, test: (T) => Boolean)` | ||
|
||
Trace the observable until the first emission that fails the provided test. | ||
|
||
### `traceUntilLast(name:string)` | ||
|
||
Trace the observable until completion. | ||
|
||
### `traceUntilFirst(name: string)` | ||
|
||
Traces the observable until the first emission. | ||
|
||
## Advanced usage | ||
|
||
### Configuration via Dependency Injection | ||
|
||
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: | ||
|
||
```ts | ||
import { NgModule } from '@angular/core'; | ||
import { AngularFirePerformanceModule, AUTOMATICALLY_TRACE_CORE_NG_METRICS } from '@angular/fire/functions'; | ||
|
||
@NgModule({ | ||
imports: [ | ||
... | ||
AngularFirePerformanceModule, | ||
... | ||
], | ||
... | ||
providers: [ | ||
{ provide: AUTOMATICALLY_TRACE_CORE_NG_METRICS, useValue: false } | ||
] | ||
}) | ||
export class AppModule {} | ||
``` | ||
|
||
Similarly, setting `INSTRUMENTATION_ENABLED` or `DATA_COLLECTION_ENABLED` to false disable all automatic and custom traces respectively. | ||
|
||
### Get at an observable form of trace | ||
|
||
`trace$(name:string)` provides an observable version of `firebase/perf`'s `.trace` method; the basis for `AngularFirePerfomance`'s pipes. | ||
|
||
`.subscribe()` is equivalent to calling `.start()` | ||
`.unsubscribe()` is equivalent to calling `.stop()` | ||
|
||
### Using `TraceOptions` to collect additional metrics | ||
|
||
`TraceOptions` can be provided to the aformentioned operators to collect custom metrics and attributes on your traces: | ||
|
||
```ts | ||
type TraceOptions = { | ||
metrics?: { [key:string]: number }, | ||
attributes?: { [key:string]: string }, | ||
attribute$?: { [key:string]: Observable<string> }, | ||
incrementMetric$: { [key:string]: Observable<number|void|null|undefined> }, | ||
metric$?: { [key:string]: Observable<number> } | ||
}; | ||
``` | ||
|
||
#### Usage: | ||
|
||
```ts | ||
const articleLength$ = this.articles.pipe( | ||
map(actions => actions.length) | ||
); | ||
|
||
const articleSize$ = this.articles.pipe( | ||
map(actions => actions.reduce((sum, a) => sum += JSON.stringify(a.payload.doc.data()).length)) | ||
) | ||
|
||
this.articles = afs.collection('articles') | ||
.collection('articles', ref => ref.orderBy('publishedAt', 'desc')) | ||
.snapshotChanges() | ||
.pipe( | ||
this.afp.trace('getArticles', { | ||
attributes: { gitSha: '1d277f823ad98dd739fb86e9a6c440aa8237ff3a' }, | ||
metrics: { something: 42 }, | ||
metrics$: { count: articleLength$, size: articleSize$ }, | ||
attributes$: { user: this.afAuth.user }, | ||
incrementMetric$: { buttonClicks: fromEvent(button, 'click') } | ||
}), | ||
share() | ||
); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './performance.spec'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './public_api'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "@angular/fire/performance", | ||
"version": "ANGULARFIRE2_VERSION", | ||
"description": "The performance monitoring module", | ||
"main": "../bundles/performance.umd.js", | ||
"module": "index.js", | ||
"es2015": "./es2015/index.js", | ||
"keywords": [ | ||
"angular", | ||
"firebase", | ||
"rxjs" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/angular/angularfire2.git" | ||
}, | ||
"author": "angular,firebase", | ||
"license": "MIT", | ||
"peerDependencies": { | ||
"@angular/fire": "ANGULARFIRE2_VERSION", | ||
"@angular/common": "ANGULAR_VERSION", | ||
"@angular/core": "ANGULAR_VERSION", | ||
"@angular/platform-browser": "ANGULAR_VERSION", | ||
"@angular/platform-browser-dynamic": "ANGULAR_VERSION", | ||
"firebase": "FIREBASE_VERSION", | ||
"rxjs": "RXJS_VERSION", | ||
"zone.js": "ZONEJS_VERSION" | ||
}, | ||
"typings": "index.d.ts" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { NgModule } from '@angular/core'; | ||
import { AngularFirePerformance } from './performance'; | ||
|
||
import 'firebase/performance'; | ||
|
||
@NgModule({ | ||
providers: [ AngularFirePerformance ] | ||
}) | ||
export class AngularFirePerformanceModule { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { TestBed, inject } from '@angular/core/testing'; | ||
import { FirebaseApp, AngularFireModule } from '@angular/fire'; | ||
import { AngularFirePerformance, AngularFirePerformanceModule } from '@angular/fire/performance'; | ||
import { COMMON_CONFIG } from './test-config'; | ||
|
||
describe('AngularFirePerformance', () => { | ||
let app: FirebaseApp; | ||
let afp: AngularFirePerformance; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [ | ||
AngularFireModule.initializeApp(COMMON_CONFIG), | ||
AngularFirePerformanceModule | ||
] | ||
}); | ||
inject([FirebaseApp, AngularFirePerformance], (app_: FirebaseApp, _perf: AngularFirePerformance) => { | ||
app = app_; | ||
afp = _perf; | ||
})(); | ||
}); | ||
|
||
afterEach(done => { | ||
app.delete(); | ||
done(); | ||
}); | ||
|
||
it('should be exist', () => { | ||
expect(afp instanceof AngularFirePerformance).toBe(true); | ||
}); | ||
|
||
it('should have the Performance instance', () => { | ||
expect(afp.performance).toBeDefined(); | ||
}); | ||
|
||
}); |
Oops, something went wrong.