-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
telemetry.ts
145 lines (124 loc) · 5.75 KB
/
telemetry.ts
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
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import TelemetryReporter from '@vscode/extension-telemetry';
import { getExperimentationServiceAsync, IExperimentationService, IExperimentationTelemetry, TargetPopulation } from 'vscode-tas-client';
import * as util from './common';
import { CppSettings } from './LanguageServer/settings';
import { logAndReturn } from './Utility/Async/returns';
import { is } from './Utility/System/guards';
interface IPackageInfo {
name: string;
version: string;
}
export class ExperimentationTelemetry implements IExperimentationTelemetry {
private sharedProperties: Record<string, string> = {};
constructor(private baseReporter: TelemetryReporter) { }
sendTelemetryEvent(eventName: string, properties?: Record<string, string>, measurements?: Record<string, number>): void {
this.baseReporter.sendTelemetryEvent(
eventName,
{
...this.sharedProperties,
...properties
},
measurements
);
}
sendTelemetryErrorEvent(eventName: string, properties?: Record<string, string>, _measurements?: Record<string, number>): void {
this.baseReporter.sendTelemetryErrorEvent(eventName, {
...this.sharedProperties,
...properties
});
}
setSharedProperty(name: string, value: string): void {
this.sharedProperties[name] = value;
}
postEvent(eventName: string, props: Map<string, string>): void {
const event: Record<string, string> = {};
for (const [key, value] of props) {
event[key] = value;
}
this.sendTelemetryEvent(eventName, event);
}
dispose(): Promise<any> {
return this.baseReporter.dispose();
}
}
let initializationPromise: Promise<IExperimentationService> | undefined;
let experimentationTelemetry: ExperimentationTelemetry | undefined;
const appInsightsKey: string = "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255";
export function activate(): void {
try {
if (util.extensionContext) {
const packageInfo: IPackageInfo = getPackageInfo();
if (packageInfo) {
const targetPopulation: TargetPopulation = util.getCppToolsTargetPopulation();
experimentationTelemetry = new ExperimentationTelemetry(new TelemetryReporter(appInsightsKey));
initializationPromise = getExperimentationServiceAsync(packageInfo.name, packageInfo.version, targetPopulation, experimentationTelemetry, util.extensionContext.globalState);
}
}
} catch (e) {
// Handle error with a try/catch, but do nothing for errors.
}
}
export function getExperimentationService(): Promise<IExperimentationService> | undefined {
return initializationPromise;
}
export async function isExperimentEnabled(experimentName: string): Promise<boolean> {
if (new CppSettings().experimentalFeatures) {
return true;
}
const experimentationService: IExperimentationService | undefined = await getExperimentationService();
const isEnabled: boolean | undefined = experimentationService?.getTreatmentVariable<boolean>("vscode", experimentName);
return isEnabled ?? false;
}
export async function deactivate(): Promise<void> {
await initializationPromise?.catch(logAndReturn.undefined);
await experimentationTelemetry?.dispose().catch(logAndReturn.undefined);
}
export function logDebuggerEvent(eventName: string, properties?: Record<string, string>, metrics?: Record<string, number>): void {
const sendTelemetry = () => {
if (experimentationTelemetry) {
const eventNamePrefix: string = "cppdbg/VS/Diagnostics/Debugger/";
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties, metrics);
}
};
// simpler expression of the original:
// Uses 'then' instead of 'await' because telemetry should be "fire and forget".
if (is.promise(initializationPromise)) {
return void initializationPromise.catch(logAndReturn.undefined).then(sendTelemetry).catch(logAndReturn.undefined);
}
sendTelemetry();
}
export function logLanguageServerEvent(eventName: string, properties?: Record<string, string>, metrics?: Record<string, number>): void {
const sendTelemetry = () => {
if (experimentationTelemetry) {
const eventNamePrefix: string = "C_Cpp/LanguageServer/";
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties, metrics);
}
};
if (is.promise(initializationPromise)) {
return void initializationPromise.catch(logAndReturn.undefined).then(sendTelemetry).catch(logAndReturn.undefined);
}
sendTelemetry();
}
export function logLanguageModelToolEvent(eventName: string, properties?: Record<string, string>, metrics?: Record<string, number>): void {
const sendTelemetry = () => {
if (experimentationTelemetry) {
const eventNamePrefix: string = "C_Cpp/Copilot/Chat/Tool/";
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties, metrics);
}
};
if (is.promise(initializationPromise)) {
return void initializationPromise.catch(logAndReturn.undefined).then(sendTelemetry).catch(logAndReturn.undefined);
}
sendTelemetry();
}
function getPackageInfo(): IPackageInfo {
return {
name: util.packageJson.publisher + "." + util.packageJson.name,
version: util.packageJson.version
};
}