This repository was archived by the owner on Jan 5, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 291
Expand file tree
/
Copy pathapplicationInsightsTelemetryClient.ts
More file actions
223 lines (198 loc) · 8.08 KB
/
applicationInsightsTelemetryClient.ts
File metadata and controls
223 lines (198 loc) · 8.08 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/**
* @module botbuilder-applicationinsights
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import * as appInsights from 'applicationinsights';
import * as cls from 'cls-hooked';
import * as crypto from 'crypto';
import {
Activity,
BotTelemetryClient,
BotPageViewTelemetryClient,
TelemetryDependency,
TelemetryEvent,
TelemetryException,
TelemetryTrace,
TelemetryPageView,
} from 'botbuilder-core';
// This is the currently recommended work-around for using Application Insights with async/await
// https://github.com/Microsoft/ApplicationInsights-node.js/issues/296
// This allows AppInsights to automatically apply the appropriate context objects deep inside the async/await chain.
import {
CorrelationContext,
CorrelationContextManager,
} from 'applicationinsights/out/AutoCollection/CorrelationContextManager';
const origGetCurrentContext = CorrelationContextManager.getCurrentContext;
const ns = cls.createNamespace('my.request');
function getCurrentContext(): CorrelationContext {
return ns.get('ctx') || origGetCurrentContext();
}
// Overwrite the built-in getCurrentContext() method with a new one.
CorrelationContextManager.getCurrentContext = getCurrentContext;
export const ApplicationInsightsWebserverMiddleware: any = (req: any, res: any, next: any): void => {
// Check to see if the request contains an incoming request.
// If so, set it into the Application Insights context.
const activity: Partial<Activity> = req.body;
if (activity && activity.id) {
const context: CorrelationContext = appInsights.getCorrelationContext();
context['activity'] = req.body;
}
ns.bindEmitter(req);
ns.bindEmitter(res);
ns.run((): void => {
ns.set('ctx', origGetCurrentContext());
next();
});
};
/**
* This is a wrapper class around the Application Insights node client.
* This is primarily designed to be used alongside the WaterfallDialog telemetry collection.
* It provides a pre-configured App Insights client, and wrappers around
* the major tracking functions, allowing it to conform to Botbuilder's generic BotTelemetryClient interface.
* To use it, create pass in an instrumentation key:
*
* ```
* const myDialog = new WaterfallDialog('my_dialog', steps);
* const appInsightsClient = new ApplicationInsightsTelemetryClient(my_instrumentation_key);
* myDialog.telemetryClient = appInsightsClient;
* ```
*/
export class ApplicationInsightsTelemetryClient implements BotTelemetryClient, BotPageViewTelemetryClient {
private client: appInsights.TelemetryClient;
private config: appInsights.Configuration;
/**
* Creates a new instance of the
* [ApplicationInsightsTelemetryClient](xref:botbuilder-applicationinsights.ApplicationInsightsTelemetryClient)
* class.
*
* @param connectionString The ApplicationInsights connection string.
*
* @remarks The settings parameter is passed directly into appInsights.setup().
* https://www.npmjs.com/package/applicationinsights#basic-usage
*/
constructor(connectionString: string);
/**
* Creates a new instance of the
* [ApplicationInsightsTelemetryClient](xref:botbuilder-applicationinsights.ApplicationInsightsTelemetryClient)
* class.
*
* @param instrumentationKey The ApplicationInsights instrumentation key.
*
* @remarks The settings parameter is passed directly into appInsights.setup().
* https://www.npmjs.com/package/applicationinsights#basic-usage
*/
constructor(instrumentationKey: string);
/**
* @internal
*/
constructor(setupString: string) {
this.config = appInsights
.setup(setupString)
.setAutoDependencyCorrelation(true)
.setAutoCollectRequests(true)
.setAutoCollectPerformance(true)
.setAutoCollectExceptions(true)
.setAutoCollectDependencies(true)
.start();
this.client = appInsights.defaultClient;
this.client.addTelemetryProcessor(addBotIdentifiers);
}
// Protects against JSON.stringify cycles
private toJSON(): unknown {
return { name: 'ApplicationInsightsTelemetryClient' };
}
/**
* Provides access to the Application Insights configuration that is running here.
* Allows developers to adjust the options, for example:
* `appInsightsClient.configuration.setAutoCollectDependencies(false)`
*
* @returns app insights configuration
*/
get configuration(): appInsights.Configuration {
return this.config;
}
/**
* Provides direct access to the telemetry client object, which might be necessary for some operations.
*
* @returns app insights telemetry client
*/
get defaultClient(): appInsights.TelemetryClient {
return this.client;
}
/**
* Sends information about an external dependency (outgoing call) in the application.
*
* @param telemetry The [TelemetryDependency](xref:botbuilder-core.TelemetryDependency) to track.
*/
trackDependency(telemetry: TelemetryDependency): void {
this.defaultClient.trackDependency(telemetry);
}
/**
* Logs custom events with extensible named fields.
*
* @param telemetry The [TelemetryEvent](xref:botbuilder-core.TelemetryEvent) to track.
*/
trackEvent(telemetry: TelemetryEvent): void {
const { name, properties, metrics: measurements } = telemetry;
this.defaultClient.trackEvent({ name, properties, measurements });
}
/**
* Logs a system exception.
*
* @param telemetry The [TelemetryException](xref:botbuilder-core.TelemetryException) to track.
*/
trackException(telemetry: TelemetryException): void {
this.defaultClient.trackException(telemetry);
}
/**
* Sends a trace message.
*
* @param telemetry The [TelemetryTrace](xref:botbuilder-core.TelemetryTrace) to track.
*/
trackTrace(telemetry: TelemetryTrace): void {
this.defaultClient.trackTrace(telemetry);
}
/**
* Logs a dialog entry as an Application Insights page view.
*
* @param telemetry The [TelemetryPageView](xref:botbuilder-core.TelemetryPageView) to track.
*/
trackPageView(telemetry: TelemetryPageView): void {
this.defaultClient.trackPageView(telemetry);
}
/**
* Flushes the in-memory buffer and any metrics being pre-aggregated.
*/
flush(): void {
this.defaultClient.flush();
}
}
/* Define the telemetry initializer function which is responsible for setting the userId. sessionId and some other values
* so that application insights can correlate related events.
*/
function addBotIdentifiers(envelope: appInsights.Contracts.Envelope, context: { [name: string]: any }): boolean {
if (context.correlationContext && context.correlationContext.activity) {
const activity: Partial<Activity> = context.correlationContext.activity;
const telemetryItem: any = envelope.data['baseData']; // TODO: update when envelope ts definition includes baseData
const userId: string = activity.from ? activity.from.id : '';
const channelId: string = activity.channelId || '';
const conversationId: string = activity.conversation ? activity.conversation.id : '';
// Hashed ID is used due to max session ID length for App Insights session Id
const sessionId: string = conversationId
? crypto.createHash('sha256').update(conversationId).digest('base64')
: '';
// set user id and session id
envelope.tags[appInsights.defaultClient.context.keys.userId] = channelId + userId;
envelope.tags[appInsights.defaultClient.context.keys.sessionId] = sessionId;
// Add additional properties
telemetryItem.properties = telemetryItem.properties || {};
telemetryItem.properties.activityId = activity.id;
telemetryItem.properties.channelId = channelId;
telemetryItem.properties.activityType = activity.type;
telemetryItem.properties.conversationId = conversationId;
}
return true;
}