1- import type {
2- Extension ,
3- ExtensionContext ,
4- ConfigurationChangeEvent ,
5- } from "vscode" ;
6- import { ConfigurationTarget , env } from "vscode" ;
1+ import type { Extension , ExtensionContext } from "vscode" ;
72import TelemetryReporter from "vscode-extension-telemetry" ;
8- import {
9- ConfigListener ,
10- CANARY_FEATURES ,
11- ENABLE_TELEMETRY ,
12- LOG_TELEMETRY ,
13- isIntegrationTestMode ,
14- isCanary ,
15- } from "../../config" ;
3+ import { LOG_TELEMETRY , isCanary } from "../../config" ;
164import type { TelemetryClient } from "applicationinsights" ;
175import { extLogger } from "../logging/vscode" ;
186import { UserCancellationException } from "./progress" ;
19- import { showBinaryChoiceWithUrlDialog } from "./dialog" ;
207import type { RedactableError } from "../errors" ;
218import type { SemVer } from "semver" ;
229import type { AppTelemetry } from "../telemetry" ;
2310import type { EnvelopeTelemetry } from "applicationinsights/out/Declarations/Contracts" ;
11+ import type { Disposable } from "../disposable-object" ;
2412
2513// Key is injected at build time through the APP_INSIGHTS_KEY environment variable.
2614const key = "REPLACE-APP-INSIGHTS-KEY" ;
@@ -55,80 +43,25 @@ const baseDataPropertiesToRemove = [
5543
5644const NOT_SET_CLI_VERSION = "not-set" ;
5745
58- export class ExtensionTelemetryListener
59- extends ConfigListener
60- implements AppTelemetry
61- {
62- private reporter ?: TelemetryReporter ;
46+ export class ExtensionTelemetryListener implements AppTelemetry , Disposable {
47+ private readonly reporter : TelemetryReporter ;
6348
6449 private cliVersionStr = NOT_SET_CLI_VERSION ;
6550
66- constructor (
67- private readonly id : string ,
68- private readonly version : string ,
69- private readonly key : string ,
70- private readonly ctx : ExtensionContext ,
71- ) {
72- super ( ) ;
73-
74- env . onDidChangeTelemetryEnabled ( async ( ) => {
75- await this . initialize ( ) ;
76- } ) ;
77- }
78-
79- /**
80- * This function handles changes to relevant configuration elements. There are 2 configuration
81- * ids that this function cares about:
82- *
83- * * `codeQL.telemetry.enableTelemetry`: If this one has changed, then we need to re-initialize
84- * the reporter and the reporter may wind up being removed.
85- * * `codeQL.canary`: A change here could possibly re-trigger a dialog popup.
86- *
87- * Note that the global telemetry setting also gate-keeps whether or not to send telemetry events
88- * to Application Insights. However, this gatekeeping happens inside of the vscode-extension-telemetry
89- * package. So, this does not need to be handled here.
90- *
91- * @param e the configuration change event
92- */
93- async handleDidChangeConfiguration (
94- e : ConfigurationChangeEvent ,
95- ) : Promise < void > {
96- if ( e . affectsConfiguration ( ENABLE_TELEMETRY . qualifiedName ) ) {
97- await this . initialize ( ) ;
98- }
99-
100- // Re-request telemetry so that users can see the dialog again.
101- // Re-request if codeQL.canary is being set to `true` and telemetry
102- // is not currently enabled.
103- if (
104- e . affectsConfiguration ( CANARY_FEATURES . qualifiedName ) &&
105- CANARY_FEATURES . getValue ( ) &&
106- ! ENABLE_TELEMETRY . getValue ( )
107- ) {
108- await this . setTelemetryRequested ( false ) ;
109- await this . requestTelemetryPermission ( ) ;
110- }
111- }
112-
113- async initialize ( ) {
114- await this . requestTelemetryPermission ( ) ;
115-
116- this . disposeReporter ( ) ;
117-
118- if ( ENABLE_TELEMETRY . getValue < boolean > ( ) ) {
119- this . createReporter ( ) ;
120- }
121- }
122-
123- private createReporter ( ) {
51+ constructor ( id : string , version : string , key : string ) {
52+ // We can always initialize this and send events using it because the vscode-extension-telemetry will check
53+ // whether the `telemetry.telemetryLevel` setting is enabled.
12454 this . reporter = new TelemetryReporter (
125- this . id ,
126- this . version ,
127- this . key ,
55+ id ,
56+ version ,
57+ key ,
12858 /* anonymize stack traces */ true ,
12959 ) ;
130- this . push ( this . reporter ) ;
13160
61+ this . addTelemetryProcessor ( ) ;
62+ }
63+
64+ private addTelemetryProcessor ( ) {
13265 // The appInsightsClient field is private but we want to access it anyway
13366 const client = this . reporter [ "appInsightsClient" ] as TelemetryClient ;
13467 if ( client ) {
@@ -151,14 +84,10 @@ export class ExtensionTelemetryListener
15184 }
15285
15386 dispose ( ) {
154- super . dispose ( ) ;
155- void this . reporter ?. dispose ( ) ;
87+ void this . reporter . dispose ( ) ;
15688 }
15789
15890 sendCommandUsage ( name : string , executionTime : number , error ?: Error ) : void {
159- if ( ! this . reporter ) {
160- return ;
161- }
16291 const status = ! error
16392 ? CommandCompletion . Success
16493 : error instanceof UserCancellationException
@@ -178,10 +107,6 @@ export class ExtensionTelemetryListener
178107 }
179108
180109 sendUIInteraction ( name : string ) : void {
181- if ( ! this . reporter ) {
182- return ;
183- }
184-
185110 this . reporter . sendTelemetryEvent (
186111 "ui-interaction" ,
187112 {
@@ -197,10 +122,6 @@ export class ExtensionTelemetryListener
197122 error : RedactableError ,
198123 extraProperties ?: { [ key : string ] : string } ,
199124 ) : void {
200- if ( ! this . reporter ) {
201- return ;
202- }
203-
204125 const properties : { [ key : string ] : string } = {
205126 isCanary : isCanary ( ) . toString ( ) ,
206127 cliVersion : this . cliVersionStr ,
@@ -215,10 +136,6 @@ export class ExtensionTelemetryListener
215136 }
216137
217138 sendConfigInformation ( config : Record < string , string > ) : void {
218- if ( ! this . reporter ) {
219- return ;
220- }
221-
222139 this . reporter . sendTelemetryEvent (
223140 "config" ,
224141 {
@@ -230,37 +147,6 @@ export class ExtensionTelemetryListener
230147 ) ;
231148 }
232149
233- /**
234- * Displays a popup asking the user if they want to enable telemetry
235- * for this extension.
236- */
237- async requestTelemetryPermission ( ) {
238- if ( ! this . wasTelemetryRequested ( ) ) {
239- // if global telemetry is disabled, avoid showing the dialog or making any changes
240- let result = undefined ;
241- if (
242- env . isTelemetryEnabled &&
243- // Avoid showing the dialog if we are in integration test mode.
244- ! isIntegrationTestMode ( )
245- ) {
246- // Extension won't start until this completes.
247- result = await showBinaryChoiceWithUrlDialog (
248- "Does the CodeQL Extension by GitHub have your permission to collect usage data and metrics to help us improve CodeQL for VSCode?" ,
249- "https://codeql.github.com/docs/codeql-for-visual-studio-code/about-telemetry-in-codeql-for-visual-studio-code" ,
250- ) ;
251- }
252- if ( result !== undefined ) {
253- await Promise . all ( [
254- this . setTelemetryRequested ( true ) ,
255- ENABLE_TELEMETRY . updateValue < boolean > (
256- result ,
257- ConfigurationTarget . Global ,
258- ) ,
259- ] ) ;
260- }
261- }
262- }
263-
264150 /**
265151 * Exposed for testing
266152 */
@@ -271,21 +157,6 @@ export class ExtensionTelemetryListener
271157 set cliVersion ( version : SemVer | undefined ) {
272158 this . cliVersionStr = version ? version . toString ( ) : NOT_SET_CLI_VERSION ;
273159 }
274-
275- private disposeReporter ( ) {
276- if ( this . reporter ) {
277- void this . reporter . dispose ( ) ;
278- this . reporter = undefined ;
279- }
280- }
281-
282- private wasTelemetryRequested ( ) : boolean {
283- return ! ! this . ctx . globalState . get < boolean > ( "telemetry-request-viewed" ) ;
284- }
285-
286- private async setTelemetryRequested ( newValue : boolean ) : Promise < void > {
287- await this . ctx . globalState . update ( "telemetry-request-viewed" , newValue ) ;
288- }
289160}
290161
291162/**
@@ -305,11 +176,7 @@ export async function initializeTelemetry(
305176 extension . id ,
306177 extension . packageJSON . version ,
307178 key ,
308- ctx ,
309179 ) ;
310- // do not await initialization, since doing so will sometimes cause a modal popup.
311- // this is a particular problem during integration tests, which will hang if a modal popup is displayed.
312- void telemetryListener . initialize ( ) ;
313180 ctx . subscriptions . push ( telemetryListener ) ;
314181 return telemetryListener ;
315182}
0 commit comments