4
4
5
5
import * as vscode from "vscode" ;
6
6
import type { TelemetryEventMeasurements , TelemetryEventProperties , RawTelemetryEventProperties } from "../../lib/telemetryReporter" ;
7
+ import { ITelemetryAppender } from "./baseTelemetryAppender" ;
7
8
import { getTelemetryLevel , TelemetryLevel } from "./util" ;
8
9
9
10
export interface AppenderData {
10
11
properties ?: RawTelemetryEventProperties ,
11
12
measurements ?: TelemetryEventMeasurements
12
13
}
13
- export interface ITelemetryAppender {
14
- logEvent ( eventName : string , data ?: AppenderData ) : void ;
15
- logException ( exception : Error , data ?: AppenderData ) : void ;
16
- flush ( ) : void | Promise < void > ;
17
- instantiateAppender ( ) : void ;
18
- }
19
14
20
15
/**
21
16
* A replacement option for the app insights client. This allows the appender to filter out any sensitive or unnecessary information from the telemetry server.
22
17
*/
23
- export interface ReplacementOption {
18
+ export interface ReplacementOption {
24
19
25
20
/**
26
21
* A regular expression matching any property to be removed or replaced from the telemetry server.
@@ -287,6 +282,32 @@ export class BaseTelemetryReporter {
287
282
}
288
283
}
289
284
285
+ /**
286
+ * Internal function which logs telemetry events and takes extra options.
287
+ * @param eventName The name of the event
288
+ * @param properties The properties of the event
289
+ * @param measurements The measurements (numeric values) to send with the event
290
+ * @param sanitize Whether or not to sanitize to the properties and measures
291
+ * @param dangerous Whether or not to ignore telemetry level
292
+ */
293
+ private internalSendTelemetryEvent (
294
+ eventName : string ,
295
+ properties : TelemetryEventProperties | undefined ,
296
+ measurements : TelemetryEventMeasurements | undefined ,
297
+ sanitize : boolean ,
298
+ dangerous : boolean
299
+ ) : void {
300
+ if ( ( this . userOptIn || dangerous ) && eventName !== "" ) {
301
+ properties = { ...properties , ...this . getCommonProperties ( ) } ;
302
+ if ( sanitize ) {
303
+ const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , this . firstParty ) ) ;
304
+ properties = this . removePropertiesWithPossibleUserInfo ( cleanProperties ) ;
305
+ }
306
+ eventName = `${ this . extensionId } /${ eventName } ` ;
307
+ dangerous ? this . telemetryAppender . logEventDangerously ( eventName , { properties, measurements } ) : this . telemetryAppender . logEvent ( eventName , { properties, measurements } ) ;
308
+ }
309
+ }
310
+
290
311
/**
291
312
* Given an event name, some properties, and measurements sends a telemetry event.
292
313
* Properties are sanitized on best-effort basis to remove sensitive data prior to sending.
@@ -295,11 +316,7 @@ export class BaseTelemetryReporter {
295
316
* @param measurements The measurements (numeric values) to send with the event
296
317
*/
297
318
public sendTelemetryEvent ( eventName : string , properties ?: TelemetryEventProperties , measurements ?: TelemetryEventMeasurements ) : void {
298
- if ( this . userOptIn && eventName !== "" ) {
299
- properties = { ...properties , ...this . getCommonProperties ( ) } ;
300
- const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , this . firstParty ) ) ;
301
- this . telemetryAppender . logEvent ( `${ this . extensionId } /${ eventName } ` , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) , measurements : measurements } ) ;
302
- }
319
+ this . internalSendTelemetryEvent ( eventName , properties , measurements , true , false ) ;
303
320
}
304
321
305
322
/**
@@ -309,9 +326,58 @@ export class BaseTelemetryReporter {
309
326
* @param measurements The measurements (numeric values) to send with the event
310
327
*/
311
328
public sendRawTelemetryEvent ( eventName : string , properties ?: RawTelemetryEventProperties , measurements ?: TelemetryEventMeasurements ) : void {
312
- if ( this . userOptIn && eventName !== "" ) {
329
+ this . internalSendTelemetryEvent ( eventName , properties , measurements , false , false ) ;
330
+ }
331
+
332
+ /**
333
+ * **DANGEROUS** Given an event name, some properties, and measurements sends a telemetry event without checking telemetry setting
334
+ * Do not use unless in a controlled environment i.e. sending telmetry from a CI pipeline or testing during development
335
+ * @param eventName The name of the event
336
+ * @param properties The properties to send with the event
337
+ * @param measurements The measurements (numeric values) to send with the event
338
+ * @param sanitize Whether or not to sanitize to the properties and measures, defaults to true
339
+ */
340
+ public sendDangerousTelemetryEvent ( eventName : string , properties ?: TelemetryEventProperties , measurements ?: TelemetryEventMeasurements , sanitize = true ) : void {
341
+ // Since telemetry is probably off when sending dangerously, we must start the appender
342
+ this . telemetryAppender . instantiateAppender ( ) ;
343
+ this . internalSendTelemetryEvent ( eventName , properties , measurements , sanitize , true ) ;
344
+ }
345
+
346
+ /**
347
+ * Internal function which logs telemetry error events and takes extra options.
348
+ * @param eventName The name of the event
349
+ * @param properties The properties of the event
350
+ * @param measurements The measurements (numeric values) to send with the event
351
+ * @param errorProps Properties to readct. If undefined then we assume all properties belong to the error prop and will be anonymized
352
+ * @param sanitize Whether or not to sanitize to the properties and measures
353
+ * @param dangerous Whether or not to ignore telemetry level
354
+ */
355
+ private internalSendTelemetryErrorEvent (
356
+ eventName : string ,
357
+ properties : TelemetryEventProperties | undefined ,
358
+ measurements : TelemetryEventMeasurements | undefined ,
359
+ errorProps : string [ ] | undefined ,
360
+ sanitize : boolean ,
361
+ dangerous : boolean
362
+ ) : void {
363
+ if ( ( this . shouldSendErrorTelemetry ( ) || dangerous ) && eventName !== "" ) {
364
+
313
365
properties = { ...properties , ...this . getCommonProperties ( ) } ;
314
- this . telemetryAppender . logEvent ( `${ this . extensionId } /${ eventName } ` , { properties, measurements } ) ;
366
+ if ( sanitize ) {
367
+ // always clean the properties if first party
368
+ // do not send any error properties if we shouldn't send error telemetry
369
+ // if we have no errorProps, assume all are error props
370
+ const cleanProperties = this . cloneAndChange ( properties , ( key : string , prop : string ) => {
371
+
372
+ if ( errorProps === undefined || errorProps . indexOf ( key ) !== - 1 ) {
373
+ return "REDACTED" ;
374
+ }
375
+
376
+ return this . anonymizeFilePaths ( prop , this . firstParty ) ;
377
+ } ) ;
378
+ properties = this . removePropertiesWithPossibleUserInfo ( cleanProperties ) ;
379
+ }
380
+ dangerous ? this . telemetryAppender . logEventDangerously ( eventName , { properties, measurements } ) : this . telemetryAppender . logEvent ( eventName , { properties, measurements } ) ;
315
381
}
316
382
}
317
383
@@ -322,24 +388,51 @@ export class BaseTelemetryReporter {
322
388
* @param measurements The measurements (numeric values) to send with the event
323
389
* @param errorProps If not present then we assume all properties belong to the error prop and will be anonymized
324
390
*/
325
- public sendTelemetryErrorEvent ( eventName : string , properties ?: { [ key : string ] : string } , measurements ?: { [ key : string ] : number } , errorProps ?: string [ ] ) : void {
326
- if ( this . errorOptIn && eventName !== "" ) {
327
- // always clean the properties if first party
328
- // do not send any error properties if we shouldn't send error telemetry
329
- // if we have no errorProps, assume all are error props
330
- properties = { ...properties , ...this . getCommonProperties ( ) } ;
331
- const cleanProperties = this . cloneAndChange ( properties , ( key : string , prop : string ) => {
332
- if ( this . shouldSendErrorTelemetry ( ) ) {
333
- return this . anonymizeFilePaths ( prop , this . firstParty ) ;
334
- }
391
+ public sendTelemetryErrorEvent ( eventName : string , properties ?: TelemetryEventProperties , measurements ?: TelemetryEventMeasurements , errorProps ?: string [ ] ) : void {
392
+ this . internalSendTelemetryErrorEvent ( eventName , properties , measurements , errorProps , true , false ) ;
393
+ }
335
394
336
- if ( errorProps === undefined || errorProps . indexOf ( key ) !== - 1 ) {
337
- return "REDACTED" ;
338
- }
395
+ /**
396
+ * **DANGEROUS** Given an event name, some properties, and measurements sends a telemetry error event without checking telemetry setting
397
+ * Do not use unless in a controlled environment i.e. sending telmetry from a CI pipeline or testing during development
398
+ * @param eventName The name of the event
399
+ * @param properties The properties to send with the event
400
+ * @param measurements The measurements (numeric values) to send with the event
401
+ * @param errorProps If not present then we assume all properties belong to the error prop and will be anonymized
402
+ * @param sanitize Whether or not to run the properties and measures through sanitiziation, defaults to true
403
+ */
404
+ public sendDangerousTelemetryErrorEvent ( eventName : string , properties ?: TelemetryEventProperties , measurements ?: TelemetryEventMeasurements , errorProps ?: string [ ] , sanitize = true ) : void {
405
+ // Since telemetry is probably off when sending dangerously, we must start the appender
406
+ this . telemetryAppender . instantiateAppender ( ) ;
407
+ this . internalSendTelemetryErrorEvent ( eventName , properties , measurements , errorProps , sanitize , true ) ;
408
+ }
339
409
340
- return this . anonymizeFilePaths ( prop , this . firstParty ) ;
341
- } ) ;
342
- this . telemetryAppender . logEvent ( `${ this . extensionId } /${ eventName } ` , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) , measurements : measurements } ) ;
410
+ /**
411
+ * Internal function which logs telemetry exceptions and takes extra options
412
+ * @param error: The error to send
413
+ * @param properties The properties of the event
414
+ * @param measurements The measurements (numeric values) to send with the event
415
+ * @param sanitize Whether or not to sanitize to the properties and measures
416
+ * @param dangerous Whether or not to ignore telemetry level
417
+ */
418
+ private internalSendTelemetryException (
419
+ error : Error ,
420
+ properties : TelemetryEventProperties | undefined ,
421
+ measurements : TelemetryEventMeasurements | undefined ,
422
+ sanitize : boolean ,
423
+ dangerous : boolean
424
+ ) : void {
425
+ if ( ( this . shouldSendErrorTelemetry ( ) || dangerous ) && error ) {
426
+ properties = { ...properties , ...this . getCommonProperties ( ) } ;
427
+ if ( sanitize ) {
428
+ const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , this . firstParty ) ) ;
429
+ // Also run the error stack through the anonymizer
430
+ if ( error . stack ) {
431
+ error . stack = this . anonymizeFilePaths ( error . stack , this . firstParty ) ;
432
+ }
433
+ properties = this . removePropertiesWithPossibleUserInfo ( cleanProperties ) ;
434
+ }
435
+ dangerous ? this . telemetryAppender . logExceptionDangerously ( error , { properties, measurements } ) : this . telemetryAppender . logException ( error , { properties, measurements } ) ;
343
436
}
344
437
}
345
438
@@ -350,15 +443,21 @@ export class BaseTelemetryReporter {
350
443
* @param measurements The measurements (numeric values) to send with the event
351
444
*/
352
445
public sendTelemetryException ( error : Error , properties ?: TelemetryEventProperties , measurements ?: TelemetryEventMeasurements ) : void {
353
- if ( this . shouldSendErrorTelemetry ( ) && this . errorOptIn && error ) {
354
- properties = { ...properties , ...this . getCommonProperties ( ) } ;
355
- const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , this . firstParty ) ) ;
356
- // Also run the error stack through the anonymizer
357
- if ( error . stack ) {
358
- error . stack = this . anonymizeFilePaths ( error . stack , this . firstParty ) ;
359
- }
360
- this . telemetryAppender . logException ( error , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) , measurements : measurements } ) ;
361
- }
446
+ this . internalSendTelemetryException ( error , properties , measurements , true , false ) ;
447
+ }
448
+
449
+ /**
450
+ * **DANGEROUS** Given an error, properties, and measurements. Sends an exception event without checking the telemetry setting
451
+ * Do not use unless in a controlled environment i.e. sending telmetry from a CI pipeline or testing during development
452
+ * @param eventName The name of the event
453
+ * @param properties The properties to send with the event
454
+ * @param measurements The measurements (numeric values) to send with the event
455
+ * @param sanitize Whether or not to sanitize to the properties and measures, defaults to true
456
+ */
457
+ public sendDangerousTelemetryException ( error : Error , properties ?: TelemetryEventProperties , measurements ?: TelemetryEventMeasurements , sanitize = true ) : void {
458
+ // Since telemetry is probably off when sending dangerously, we must start the appender
459
+ this . telemetryAppender . instantiateAppender ( ) ;
460
+ this . internalSendTelemetryException ( error , properties , measurements , sanitize , true ) ;
362
461
}
363
462
364
463
/**
0 commit comments