@@ -16,17 +16,23 @@ import { language } from 'vs/base/common/platform';
16
16
import { Disposable } from 'vs/base/common/lifecycle' ;
17
17
import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry' ;
18
18
import { TelemetryTrustedValue } from 'vs/platform/telemetry/common/telemetryUtils' ;
19
- import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
19
+ import { ConfigurationTarget , ConfigurationTargetToString , IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
20
20
import { ITextFileService , ITextFileSaveEvent , ITextFileResolveEvent } from 'vs/workbench/services/textfile/common/textfiles' ;
21
21
import { extname , basename , isEqual , isEqualOrParent } from 'vs/base/common/resources' ;
22
22
import { URI } from 'vs/base/common/uri' ;
23
+ import { Event } from 'vs/base/common/event' ;
23
24
import { Schemas } from 'vs/base/common/network' ;
24
25
import { getMimeTypes } from 'vs/editor/common/services/languagesAssociations' ;
25
26
import { hash } from 'vs/base/common/hash' ;
26
27
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite' ;
27
28
import { ViewContainerLocation } from 'vs/workbench/common/views' ;
28
29
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile' ;
29
30
import { mainWindow } from 'vs/base/browser/window' ;
31
+ import { IConfigurationRegistry , Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry' ;
32
+ import { isBoolean , isNumber , isString } from 'vs/base/common/types' ;
33
+ import { LayoutSettings } from 'vs/workbench/services/layout/browser/layoutService' ;
34
+ import { AutoUpdateConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions' ;
35
+ import { KEYWORD_ACTIVIATION_SETTING_ID } from 'vs/workbench/contrib/chat/common/chatService' ;
30
36
31
37
type TelemetryData = {
32
38
mimeType : TelemetryTrustedValue < string > ;
@@ -58,7 +64,6 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
58
64
@IWorkbenchThemeService themeService : IWorkbenchThemeService ,
59
65
@IWorkbenchEnvironmentService environmentService : IWorkbenchEnvironmentService ,
60
66
@IUserDataProfileService private readonly userDataProfileService : IUserDataProfileService ,
61
- @IConfigurationService configurationService : IConfigurationService ,
62
67
@IPaneCompositePartService paneCompositeService : IPaneCompositePartService ,
63
68
@ITextFileService textFileService : ITextFileService
64
69
) {
@@ -229,4 +234,177 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
229
234
}
230
235
}
231
236
232
- Registry . as < IWorkbenchContributionsRegistry > ( WorkbenchExtensions . Workbench ) . registerWorkbenchContribution ( TelemetryContribution , LifecyclePhase . Restored ) ;
237
+ class ConfigurationTelemetryContribution extends Disposable implements IWorkbenchContribution {
238
+
239
+ private readonly configurationRegistry = Registry . as < IConfigurationRegistry > ( ConfigurationExtensions . Configuration ) ;
240
+
241
+ constructor (
242
+ @IConfigurationService private readonly configurationService : IConfigurationService ,
243
+ @ITelemetryService private readonly telemetryService : ITelemetryService ,
244
+ ) {
245
+ super ( ) ;
246
+
247
+ // Debounce the event by 1000 ms and merge all affected keys into one event
248
+ const debouncedConfigService = Event . debounce ( configurationService . onDidChangeConfiguration , ( last , cur ) => {
249
+ const newAffectedKeys : ReadonlySet < string > = last ? new Set ( [ ...last . affectedKeys , ...cur . affectedKeys ] ) : cur . affectedKeys ;
250
+ return { ...cur , affectedKeys : newAffectedKeys } ;
251
+ } , 1000 , true ) ;
252
+
253
+ debouncedConfigService ( event => {
254
+ if ( event . source !== ConfigurationTarget . DEFAULT ) {
255
+ type UpdateConfigurationClassification = {
256
+ owner : 'sandy081' ;
257
+ comment : 'Event which fires when user updates settings' ;
258
+ configurationSource : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'What configuration file was updated i.e user or workspace' } ;
259
+ configurationKeys : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'What configuration keys were updated' } ;
260
+ } ;
261
+ type UpdateConfigurationEvent = {
262
+ configurationSource : string ;
263
+ configurationKeys : string [ ] ;
264
+ } ;
265
+ telemetryService . publicLog2 < UpdateConfigurationEvent , UpdateConfigurationClassification > ( 'updateConfiguration' , {
266
+ configurationSource : ConfigurationTargetToString ( event . source ) ,
267
+ configurationKeys : Array . from ( event . affectedKeys )
268
+ } ) ;
269
+ }
270
+ } ) ;
271
+
272
+ const { user, workspace } = configurationService . keys ( ) ;
273
+ for ( const setting of user ) {
274
+ this . reportTelemetry ( setting , ConfigurationTarget . USER_LOCAL ) ;
275
+ }
276
+ for ( const setting of workspace ) {
277
+ this . reportTelemetry ( setting , ConfigurationTarget . WORKSPACE ) ;
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Report value of a setting only if it is an enum, boolean, or number or an array of those.
283
+ */
284
+ private getValueToReport ( key : string , target : ConfigurationTarget . USER_LOCAL | ConfigurationTarget . WORKSPACE ) : any {
285
+ const schema = this . configurationRegistry . getConfigurationProperties ( ) [ key ] ;
286
+ const inpsectData = this . configurationService . inspect ( key ) ;
287
+ const value = target === ConfigurationTarget . USER_LOCAL ? inpsectData . user ?. value : inpsectData . workspace ?. value ;
288
+ if ( isNumber ( value ) || isBoolean ( value ) ) {
289
+ return value ;
290
+ }
291
+ if ( isString ( value ) ) {
292
+ if ( schema ?. enum ?. includes ( value ) ) {
293
+ return value ;
294
+ }
295
+ return undefined ;
296
+ }
297
+ if ( Array . isArray ( value ) ) {
298
+ if ( value . every ( v => isNumber ( v ) || isBoolean ( v ) || ( isString ( v ) && schema ?. enum ?. includes ( v ) ) ) ) {
299
+ return value ;
300
+ }
301
+ }
302
+ return undefined ;
303
+ }
304
+
305
+ private reportTelemetry ( key : string , target : ConfigurationTarget . USER_LOCAL | ConfigurationTarget . WORKSPACE ) : void {
306
+ type UpdatedSettingEvent = {
307
+ value : any ;
308
+ source : string ;
309
+ } ;
310
+ const source = ConfigurationTargetToString ( target ) ;
311
+
312
+ switch ( key ) {
313
+
314
+ case LayoutSettings . ACTIVITY_BAR_LOCATION :
315
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
316
+ owner : 'sandy081' ;
317
+ comment : 'This is used to know where activity bar is shown in the workbench.' ;
318
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
319
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
320
+ } > ( 'workbench.activityBar.location' , { value : this . getValueToReport ( key , target ) , source } ) ;
321
+ return ;
322
+
323
+ case AutoUpdateConfigurationKey :
324
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
325
+ owner : 'sandy081' ;
326
+ comment : 'This is used to know if extensions are getting auto updated or not' ;
327
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
328
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
329
+ } > ( 'extensions.autoUpdate' , { value : this . getValueToReport ( key , target ) , source } ) ;
330
+ return ;
331
+
332
+ case 'files.autoSave' :
333
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
334
+ owner : 'isidorn' ;
335
+ comment : 'This is used to know if auto save is enabled or not' ;
336
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
337
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
338
+ } > ( 'files.autoSave' , { value : this . getValueToReport ( key , target ) , source } ) ;
339
+ return ;
340
+
341
+ case 'editor.stickyScroll.enabled' :
342
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
343
+ owner : 'aiday-mar' ;
344
+ comment : 'This is used to know if editor sticky scroll is enabled or not' ;
345
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
346
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
347
+ } > ( 'editor.stickyScroll.enabled' , { value : this . getValueToReport ( key , target ) , source } ) ;
348
+ return ;
349
+
350
+ case KEYWORD_ACTIVIATION_SETTING_ID :
351
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
352
+ owner : 'bpasero' ;
353
+ comment : 'This is used to know if voice keyword activation is enabled or not' ;
354
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
355
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
356
+ } > ( 'accessibility.voice.keywordActivation' , { value : this . getValueToReport ( key , target ) , source } ) ;
357
+ return ;
358
+
359
+ case 'window.zoomLevel' :
360
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
361
+ owner : 'bpasero' ;
362
+ comment : 'This is used to know if window zoom level is configured or not' ;
363
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
364
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
365
+ } > ( 'window.zoomLevel' , { value : this . getValueToReport ( key , target ) , source } ) ;
366
+ return ;
367
+
368
+ case 'window.zoomPerWindow' :
369
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
370
+ owner : 'bpasero' ;
371
+ comment : 'This is used to know if window zoom per window is configured or not' ;
372
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
373
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
374
+ } > ( 'window.zoomPerWindow' , { value : this . getValueToReport ( key , target ) , source } ) ;
375
+ return ;
376
+
377
+ case 'window.titleBarStyle' :
378
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
379
+ owner : 'benibenj' ;
380
+ comment : 'This is used to know if window title bar style is set to custom or not' ;
381
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
382
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
383
+ } > ( 'window.titleBarStyle' , { value : this . getValueToReport ( key , target ) , source } ) ;
384
+ return ;
385
+
386
+ case 'window.customTitleBarVisibility' :
387
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
388
+ owner : 'benibenj' ;
389
+ comment : 'This is used to know if window custom title bar visibility is configured or not' ;
390
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
391
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
392
+ } > ( 'window.customTitleBarVisibility' , { value : this . getValueToReport ( key , target ) , source } ) ;
393
+ return ;
394
+
395
+ case 'window.nativeTabs' :
396
+ this . telemetryService . publicLog2 < UpdatedSettingEvent , {
397
+ owner : 'benibenj' ;
398
+ comment : 'This is used to know if window native tabs are enabled or not' ;
399
+ value : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'value of the setting' } ;
400
+ source : { classification : 'SystemMetaData' ; purpose : 'FeatureInsight' ; comment : 'source of the setting' } ;
401
+ } > ( 'window.nativeTabs' , { value : this . getValueToReport ( key , target ) , source } ) ;
402
+ return ;
403
+ }
404
+ }
405
+
406
+ }
407
+
408
+ const workbenchContributionRegistry = Registry . as < IWorkbenchContributionsRegistry > ( WorkbenchExtensions . Workbench ) ;
409
+ workbenchContributionRegistry . registerWorkbenchContribution ( TelemetryContribution , LifecyclePhase . Restored ) ;
410
+ workbenchContributionRegistry . registerWorkbenchContribution ( ConfigurationTelemetryContribution , LifecyclePhase . Eventually ) ;
0 commit comments