Repository navigation
Expand file tree
/
Copy pathperformance.ts
More file actions
100 lines (84 loc) · 3.76 KB
/
Copy pathperformance.ts
File metadata and controls
100 lines (84 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { Injectable, NgZone, ApplicationRef, InjectionToken, Inject, Optional } from '@angular/core';
import { Observable } from 'rxjs';
import { first, tap } from 'rxjs/operators';
import { performance } from 'firebase/app';
export const AUTOMATICALLY_TRACE_CORE_NG_METRICS = new InjectionToken<boolean>('angularfire2.performance.auto_trace');
export 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>}
};
export const getInstance = (options: { automaticallyTraceCoreNgMetrics?: boolean, appRef: ApplicationRef, zone: NgZone }) => new AngularFirePerformance(options.automaticallyTraceCoreNgMetrics || null, options.appRef, options.zone);
@Injectable()
export class AngularFirePerformance {
performance: performance.Performance;
constructor(
@Optional() @Inject(AUTOMATICALLY_TRACE_CORE_NG_METRICS) automaticallyTraceCoreNgMetrics:boolean|null,
appRef: ApplicationRef,
private zone: NgZone
) {
this.performance = zone.runOutsideAngular(() => performance());
if (automaticallyTraceCoreNgMetrics != false) {
// TODO detirmine more built in metrics
appRef.isStable.pipe(
this.traceComplete('isStable'),
first(it => it)
).subscribe();
}
}
trace$ = (name:string, options?: TraceOptions) => new Observable<void>(emitter =>
this.zone.runOutsideAngular(() => {
const trace = this.performance.trace(name);
options && options.metrics && Object.keys(options.metrics).forEach(metric => {
trace.putMetric(metric, options!.metrics![metric])
});
options && options.attributes && Object.keys(options.attributes).forEach(attribute => {
trace.putAttribute(attribute, options!.attributes![attribute])
});
const attributeSubscriptions = options && options.attribute$ ? Object.keys(options.attribute$).map(attribute =>
options!.attribute$![attribute].subscribe(next => trace.putAttribute(attribute, next))
) : [];
const metricSubscriptions = options && options.metric$ ? Object.keys(options.metric$).map(metric =>
options!.metric$![metric].subscribe(next => trace.putMetric(metric, next))
) : [];
const incrementOnSubscriptions = options && options.incrementMetric$ ? Object.keys(options.incrementMetric$).map(metric =>
options!.incrementMetric$![metric].subscribe(next => trace.incrementMetric(metric, next || undefined))
) : [];
emitter.next(trace.start());
return { unsubscribe: () => {
trace.stop();
metricSubscriptions.forEach(m => m.unsubscribe());
incrementOnSubscriptions.forEach(m => m.unsubscribe());
attributeSubscriptions.forEach(m => m.unsubscribe());
}};
})
);
traceUntil = <T=any>(name:string, test: (a:T) => boolean, options?: TraceOptions) => (source$: Observable<T>) => {
const traceSubscription = this.trace$(name, options).subscribe();
return source$.pipe(
tap(a => { if (test(a)) { traceSubscription.unsubscribe() }})
)
};
traceComplete = <T=any>(name:string, options?: TraceOptions) => (source$: Observable<T>) => {
const traceSubscription = this.trace$(name, options).subscribe();
return source$.pipe(
tap(
() => {},
() => {},
() => traceSubscription.unsubscribe()
)
)
};
trace = <T=any>(name:string, options?: TraceOptions) => (source$: Observable<T>) => {
const traceSubscription = this.trace$(name, options).subscribe();
return source$.pipe(
tap(
() => traceSubscription.unsubscribe(),
() => {},
() => traceSubscription.unsubscribe()
)
)
};
}