Skip to content

Commit d6b3e51

Browse files
committed
Add the CLI version to telemetry events
This adds the CLI version to telemetry command-usage events. Note that the CLI server is created after the telemetry listener is created. The first few telemetry events may have a "not-set" value for the CLI version.
1 parent eabcd00 commit d6b3e51

File tree

4 files changed

+53
-9
lines changed

4 files changed

+53
-9
lines changed

extensions/ql-vscode/src/common/vscode/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function registerCommandWithErrorHandling(
7575
return undefined;
7676
} finally {
7777
const executionTime = Date.now() - startTime;
78-
telemetryListener?.sendCommandUsage(commandId, executionTime, error);
78+
void telemetryListener?.sendCommandUsage(commandId, executionTime, error);
7979
}
8080
});
8181
}

extensions/ql-vscode/src/extension.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ export async function activate(
306306

307307
const distributionConfigListener = new DistributionConfigListener();
308308
await initializeLogging(ctx);
309-
await initializeTelemetry(extension, ctx);
309+
const telemetryListener = await initializeTelemetry(extension, ctx);
310310
addUnhandledRejectionListener();
311311
install();
312312

@@ -395,6 +395,7 @@ export async function activate(
395395
variantAnalysisViewSerializer.onExtensionLoaded(
396396
codeQlExtension.variantAnalysisManager,
397397
);
398+
telemetryListener.cli = codeQlExtension.cliServer;
398399
}
399400

400401
return codeQlExtension;

extensions/ql-vscode/src/telemetry.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { extLogger } from "./common";
1919
import { UserCancellationException } from "./progress";
2020
import { showBinaryChoiceWithUrlDialog } from "./helpers";
2121
import { RedactableError } from "./pure/errors";
22+
import { CodeQLCliServer } from "./cli";
2223

2324
// Key is injected at build time through the APP_INSIGHTS_KEY environment variable.
2425
const key = "REPLACE-APP-INSIGHTS-KEY";
@@ -56,6 +57,8 @@ export class TelemetryListener extends ConfigListener {
5657

5758
private reporter?: TelemetryReporter;
5859

60+
private _cli?: CodeQLCliServer;
61+
5962
constructor(
6063
private readonly id: string,
6164
private readonly version: string,
@@ -147,7 +150,7 @@ export class TelemetryListener extends ConfigListener {
147150
void this.reporter?.dispose();
148151
}
149152

150-
sendCommandUsage(name: string, executionTime: number, error?: Error) {
153+
async sendCommandUsage(name: string, executionTime: number, error?: Error) {
151154
if (!this.reporter) {
152155
return;
153156
}
@@ -157,12 +160,18 @@ export class TelemetryListener extends ConfigListener {
157160
? CommandCompletion.Cancelled
158161
: CommandCompletion.Failed;
159162

163+
const cliVersion = this._cli
164+
? (await this._cli.getVersion()).toString()
165+
: // telemetry events that are sent before the cli is initialized will not have a version number
166+
"not-set";
167+
160168
this.reporter.sendTelemetryEvent(
161169
"command-usage",
162170
{
163171
name,
164172
status,
165173
isCanary: isCanary().toString(),
174+
cliVersion,
166175
},
167176
{ executionTime },
168177
);
@@ -241,6 +250,10 @@ export class TelemetryListener extends ConfigListener {
241250
return this.reporter;
242251
}
243252

253+
set cli(cli: CodeQLCliServer) {
254+
this._cli = cli;
255+
}
256+
244257
private disposeReporter() {
245258
if (this.reporter) {
246259
void this.reporter.dispose();
@@ -265,7 +278,7 @@ export let telemetryListener: TelemetryListener | undefined;
265278
export async function initializeTelemetry(
266279
extension: Extension<any>,
267280
ctx: ExtensionContext,
268-
): Promise<void> {
281+
): Promise<TelemetryListener> {
269282
if (telemetryListener !== undefined) {
270283
throw new Error("Telemetry is already initialized");
271284
}
@@ -279,4 +292,5 @@ export async function initializeTelemetry(
279292
// this is a particular problem during integration tests, which will hang if a modal popup is displayed.
280293
void telemetryListener.initialize();
281294
ctx.subscriptions.push(telemetryListener);
295+
return telemetryListener;
282296
}

extensions/ql-vscode/test/vscode-tests/no-workspace/telemetry.test.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,15 @@ describe("telemetry reporting", () => {
185185
it("should send an event", async () => {
186186
await telemetryListener.initialize();
187187

188-
telemetryListener.sendCommandUsage("command-id", 1234, undefined);
188+
await telemetryListener.sendCommandUsage("command-id", 1234, undefined);
189189

190190
expect(sendTelemetryEventSpy).toHaveBeenCalledWith(
191191
"command-usage",
192192
{
193193
name: "command-id",
194194
status: "Success",
195195
isCanary,
196+
cliVersion: "not-set",
196197
},
197198
{ executionTime: 1234 },
198199
);
@@ -203,7 +204,7 @@ describe("telemetry reporting", () => {
203204
it("should send a command usage event with an error", async () => {
204205
await telemetryListener.initialize();
205206

206-
telemetryListener.sendCommandUsage(
207+
await telemetryListener.sendCommandUsage(
207208
"command-id",
208209
1234,
209210
new UserCancellationException(),
@@ -215,6 +216,33 @@ describe("telemetry reporting", () => {
215216
name: "command-id",
216217
status: "Cancelled",
217218
isCanary,
219+
cliVersion: "not-set",
220+
},
221+
{ executionTime: 1234 },
222+
);
223+
224+
expect(sendTelemetryExceptionSpy).not.toBeCalled();
225+
});
226+
227+
it("should send a command usage event with a cli version", async () => {
228+
await telemetryListener.initialize();
229+
telemetryListener.cli = {
230+
getVersion: () => Promise.resolve("1.2.3"),
231+
} as any;
232+
233+
await telemetryListener.sendCommandUsage(
234+
"command-id",
235+
1234,
236+
new UserCancellationException(),
237+
);
238+
239+
expect(sendTelemetryEventSpy).toHaveBeenCalledWith(
240+
"command-usage",
241+
{
242+
name: "command-id",
243+
status: "Cancelled",
244+
isCanary,
245+
cliVersion: "1.2.3",
218246
},
219247
{ executionTime: 1234 },
220248
);
@@ -226,8 +254,8 @@ describe("telemetry reporting", () => {
226254
await telemetryListener.initialize();
227255
await enableTelemetry("codeQL.telemetry", false);
228256

229-
telemetryListener.sendCommandUsage("command-id", 1234, undefined);
230-
telemetryListener.sendCommandUsage("command-id", 1234, new Error());
257+
await telemetryListener.sendCommandUsage("command-id", 1234, undefined);
258+
await telemetryListener.sendCommandUsage("command-id", 1234, new Error());
231259

232260
expect(sendTelemetryEventSpy).not.toBeCalled();
233261
expect(sendTelemetryExceptionSpy).not.toBeCalled();
@@ -238,14 +266,15 @@ describe("telemetry reporting", () => {
238266
await enableTelemetry("codeQL.telemetry", false);
239267
await enableTelemetry("codeQL.telemetry", true);
240268

241-
telemetryListener.sendCommandUsage("command-id", 1234, undefined);
269+
await telemetryListener.sendCommandUsage("command-id", 1234, undefined);
242270

243271
expect(sendTelemetryEventSpy).toHaveBeenCalledWith(
244272
"command-usage",
245273
{
246274
name: "command-id",
247275
status: "Success",
248276
isCanary,
277+
cliVersion: "not-set",
249278
},
250279
{ executionTime: 1234 },
251280
);

0 commit comments

Comments
 (0)