|
1 | 1 | import { ErrorHandler, Injectable } from '@angular/core'; |
2 | 2 | import { Router } from '@angular/router'; |
3 | | -import { AngularPlugin } from '@microsoft/applicationinsights-angularplugin-js'; |
4 | | -import { ApplicationInsights, DistributedTracingModes } from '@microsoft/applicationinsights-web'; |
5 | 3 | import { environment } from '../enviroments/enviroment'; |
6 | | - |
7 | | -@Injectable() |
| 4 | + |
| 5 | +type MinimalAppInsights = { |
| 6 | + addTelemetryInitializer: (cb: (envelope: { tags?: Record<string, string> }) => void) => void; |
| 7 | + loadAppInsights: () => void; |
| 8 | + trackEvent: (event: { name: string }) => void; |
| 9 | + trackTrace: (trace: { message: string }) => void; |
| 10 | +}; |
| 11 | + |
| 12 | +@Injectable({ providedIn: 'root' }) |
8 | 13 | export class Insights { |
9 | | - private angularPlugin = new AngularPlugin(); |
10 | 14 | private initialized = false; |
11 | | - private appInsights = new ApplicationInsights({ |
12 | | - config: { |
13 | | - instrumentationKey: environment.instrumentationKey, |
14 | | - distributedTracingMode: DistributedTracingModes.AI_AND_W3C, |
15 | | - enableAutoRouteTracking: true, |
16 | | - enableCorsCorrelation: true, |
17 | | - // Prefer modern lifecycle events to avoid deprecated unload listeners. |
18 | | - disablePageUnloadEvents: ['unload', 'beforeunload'], |
19 | | - correlationHeaderDomains: [ |
20 | | - 'writefluency.com', |
21 | | - 'api.writefluency.com', |
22 | | - 'writefluency.com:8080', |
23 | | - 'localhost:5000', |
24 | | - ], |
25 | | - extensions: [this.angularPlugin], |
26 | | - extensionConfig: { |
27 | | - [this.angularPlugin.identifier]: { |
28 | | - router: this.router, |
29 | | - errorServices: [new ErrorHandler()], |
30 | | - }, |
31 | | - }, |
32 | | - }, |
33 | | - }); |
34 | | - |
| 15 | + private initializePromise: Promise<void> | null = null; |
| 16 | + private appInsights: MinimalAppInsights | null = null; |
| 17 | + |
35 | 18 | constructor(private router: Router) { |
36 | 19 | if (typeof window === 'undefined' || !environment.production) { |
37 | 20 | return; |
38 | 21 | } |
39 | 22 |
|
40 | 23 | // Defer telemetry startup so it does not compete with LCP-critical resources. |
41 | 24 | window.setTimeout(() => { |
42 | | - this.initializeTelemetry(); |
| 25 | + void this.initializeTelemetry().catch(() => undefined); |
43 | 26 | }, 4000); |
44 | 27 | } |
45 | 28 |
|
46 | | - private initializeTelemetry(): void { |
47 | | - if (typeof window === 'undefined' || !environment.production) { |
48 | | - return; |
| 29 | + private initializeTelemetry(): Promise<void> { |
| 30 | + if (typeof window === 'undefined' || !environment.production || this.initialized) { |
| 31 | + return Promise.resolve(); |
49 | 32 | } |
50 | 33 |
|
51 | | - if (this.initialized) { |
52 | | - return; |
| 34 | + if (!this.initializePromise) { |
| 35 | + this.initializePromise = this.loadAndStartTelemetry().catch((error) => { |
| 36 | + this.initializePromise = null; |
| 37 | + throw error; |
| 38 | + }); |
53 | 39 | } |
54 | 40 |
|
55 | | - this.initialized = true; |
| 41 | + return this.initializePromise; |
| 42 | + } |
| 43 | + |
| 44 | + private async loadAndStartTelemetry(): Promise<void> { |
| 45 | + const [{ AngularPlugin }, { ApplicationInsights, DistributedTracingModes }] = await Promise.all([ |
| 46 | + import('@microsoft/applicationinsights-angularplugin-js'), |
| 47 | + import('@microsoft/applicationinsights-web'), |
| 48 | + ]); |
| 49 | + |
| 50 | + const angularPlugin = new AngularPlugin(); |
| 51 | + const appInsights = new ApplicationInsights({ |
| 52 | + config: { |
| 53 | + instrumentationKey: environment.instrumentationKey, |
| 54 | + distributedTracingMode: DistributedTracingModes.AI_AND_W3C, |
| 55 | + enableAutoRouteTracking: true, |
| 56 | + enableCorsCorrelation: true, |
| 57 | + // Prefer modern lifecycle events to avoid deprecated unload listeners. |
| 58 | + disablePageUnloadEvents: ['unload', 'beforeunload'], |
| 59 | + correlationHeaderDomains: [ |
| 60 | + 'writefluency.com', |
| 61 | + 'api.writefluency.com', |
| 62 | + 'writefluency.com:8080', |
| 63 | + 'localhost:5000', |
| 64 | + ], |
| 65 | + extensions: [angularPlugin], |
| 66 | + extensionConfig: { |
| 67 | + [angularPlugin.identifier]: { |
| 68 | + router: this.router, |
| 69 | + errorServices: [new ErrorHandler()], |
| 70 | + }, |
| 71 | + }, |
| 72 | + }, |
| 73 | + }); |
56 | 74 |
|
57 | | - this.appInsights.addTelemetryInitializer((envelope) => { |
58 | | - if(!envelope.tags) { |
59 | | - envelope.tags = {}; |
60 | | - } |
61 | | - envelope.tags['ai.cloud.role'] = 'wf-webapp'; |
62 | | - envelope.tags['ai.cloud.roleInstance'] = 'angular-client'; |
| 75 | + appInsights.addTelemetryInitializer((envelope: { tags?: Record<string, string> }) => { |
| 76 | + envelope.tags ??= {}; |
| 77 | + envelope.tags['ai.cloud.role'] = 'wf-webapp'; |
| 78 | + envelope.tags['ai.cloud.roleInstance'] = 'angular-client'; |
63 | 79 | }); |
64 | 80 |
|
65 | | - this.appInsights.loadAppInsights(); |
| 81 | + appInsights.loadAppInsights(); |
| 82 | + this.appInsights = appInsights as MinimalAppInsights; |
| 83 | + this.initialized = true; |
66 | 84 | } |
67 | 85 |
|
68 | 86 | // expose methods that can be used in components and services |
69 | 87 | trackEvent(name: string): void { |
70 | | - this.initializeTelemetry(); |
71 | | - this.appInsights.trackEvent({ name }); |
| 88 | + if (!environment.production) { |
| 89 | + return; |
| 90 | + } |
| 91 | + |
| 92 | + if (this.appInsights) { |
| 93 | + this.appInsights.trackEvent({ name }); |
| 94 | + return; |
| 95 | + } |
| 96 | + |
| 97 | + void this.initializeTelemetry() |
| 98 | + .then(() => this.appInsights?.trackEvent({ name })) |
| 99 | + .catch(() => undefined); |
72 | 100 | } |
73 | 101 |
|
74 | 102 | trackTrace(message: string): void { |
75 | | - this.initializeTelemetry(); |
76 | | - this.appInsights.trackTrace({ message }); |
| 103 | + if (!environment.production) { |
| 104 | + return; |
| 105 | + } |
| 106 | + |
| 107 | + if (this.appInsights) { |
| 108 | + this.appInsights.trackTrace({ message }); |
| 109 | + return; |
| 110 | + } |
| 111 | + |
| 112 | + void this.initializeTelemetry() |
| 113 | + .then(() => this.appInsights?.trackTrace({ message })) |
| 114 | + .catch(() => undefined); |
77 | 115 | } |
78 | 116 | } |
0 commit comments