55
66'use strict' ;
77
8- import * as Platform from 'vs/base/common/platform' ;
9- import * as uuid from 'vs/base/common/uuid' ;
8+ import { localize } from 'vs/nls' ;
109import { escapeRegExpCharacters } from 'vs/base/common/strings' ;
11- import { IWorkspaceContextService , IEnvironment } from 'vs/platform/workspace/common/workspace' ;
1210import { ITelemetryService , ITelemetryAppender , ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry' ;
11+ import { optional } from 'vs/platform/instantiation/common/instantiation' ;
12+ import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
13+ import { IConfigurationRegistry , Extensions } from 'vs/platform/configuration/common/configurationRegistry' ;
1314import ErrorTelemetry from 'vs/platform/telemetry/common/errorTelemetry' ;
1415import { IdleMonitor , UserStatus } from 'vs/base/browser/idleMonitor' ;
1516import { TPromise } from 'vs/base/common/winjs.base' ;
1617import { IDisposable , dispose } from 'vs/base/common/lifecycle' ;
1718import { TimeKeeper , ITimerEvent } from 'vs/base/common/timer' ;
18- import { withDefaults , cloneAndChange , mixin } from 'vs/base/common/objects' ;
19+ import { cloneAndChange , mixin } from 'vs/base/common/objects' ;
20+ import { Registry } from 'vs/platform/platform' ;
1921
2022export interface ITelemetryServiceConfig {
2123 appender : ITelemetryAppender [ ] ;
22- commonProperties ?: TPromise < { [ name : string ] : any } > [ ] ;
24+ commonProperties ?: TPromise < { [ name : string ] : any } > ;
2325 piiPaths ?: string [ ] ;
2426 userOptIn ?: boolean ;
2527 enableHardIdle ?: boolean ;
2628 enableSoftIdle ?: boolean ;
2729}
2830
29- function createDefaultProperties ( environment : IEnvironment ) : { [ name : string ] : any } {
30-
31- let seq = 0 ;
32- const startTime = Date . now ( ) ;
33- const sessionID = uuid . generateUuid ( ) + Date . now ( ) ;
34-
35- let result = {
36- sessionID,
37- commitHash : environment . commitHash ,
38- version : environment . version
39- } ;
40-
41- // complex names and dynamic values
42- Object . defineProperties ( result , {
43- 'timestamp' : {
44- get : ( ) => new Date ( ) ,
45- enumerable : true
46- } ,
47- 'common.timesincesessionstart' : {
48- get : ( ) => Date . now ( ) - startTime ,
49- enumerable : true
50- } ,
51- 'common.platform' : {
52- get : ( ) => Platform . Platform [ Platform . platform ] ,
53- enumerable : true
54- } ,
55- 'common.sequence' : {
56- get : ( ) => seq ++ ,
57- enumerable : true
58- }
59- } ) ;
60-
61- return result ;
62- }
63-
6431export class TelemetryService implements ITelemetryService {
6532
6633 // how long of inactivity before a user is considered 'inactive' - 2 minutes
@@ -71,31 +38,25 @@ export class TelemetryService implements ITelemetryService {
7138
7239 public serviceId = ITelemetryService ;
7340
74- protected _configuration : ITelemetryServiceConfig ;
75- protected _disposables : IDisposable [ ] = [ ] ;
76-
41+ private _configuration : ITelemetryServiceConfig ;
42+ private _disposables : IDisposable [ ] = [ ] ;
7743 private _timeKeeper : TimeKeeper ;
7844 private _hardIdleMonitor : IdleMonitor ;
7945 private _softIdleMonitor : IdleMonitor ;
80-
81- private _commonProperties : TPromise < { [ name : string ] : any } > ;
8246 private _cleanupPatterns : [ RegExp , string ] [ ] = [ ] ;
8347
8448 constructor (
8549 config : ITelemetryServiceConfig ,
86- @IWorkspaceContextService contextService : IWorkspaceContextService
50+ @optional ( IConfigurationService ) private _configurationService : IConfigurationService
8751 ) {
88- this . _configuration = withDefaults ( config , < ITelemetryServiceConfig > {
52+ this . _configuration = mixin ( config , < ITelemetryServiceConfig > {
8953 appender : [ ] ,
90- commonProperties : [ ] ,
54+ commonProperties : TPromise . as ( { } ) ,
9155 piiPaths : [ ] ,
9256 enableHardIdle : true ,
9357 enableSoftIdle : true ,
9458 userOptIn : true
95- } ) ;
96-
97- this . _commonProperties = TPromise . join ( this . _configuration . commonProperties )
98- . then ( values => values . reduce ( ( p , c ) => mixin ( p , c ) , createDefaultProperties ( contextService . getConfiguration ( ) . env ) ) ) ;
59+ } , false ) ;
9960
10061 // static cleanup patterns for:
10162 // #1 `file:///DANGEROUS/PATH/resources/app/Useful/Information`
@@ -127,6 +88,17 @@ export class TelemetryService implements ITelemetryService {
12788 this . _softIdleMonitor . addOneTimeIdleListener ( ( ) => this . _onUserIdle ( ) ) ;
12889 this . _disposables . push ( this . _softIdleMonitor ) ;
12990 }
91+
92+ if ( this . _configurationService ) {
93+ this . _updateUserOptIn ( ) ;
94+ this . _configurationService . onDidUpdateConfiguration ( this . _updateUserOptIn , this , this . _disposables ) ;
95+ this . publicLog ( 'optInStatus' , { optIn : this . _configuration . userOptIn } ) ;
96+ }
97+ }
98+
99+ private _updateUserOptIn ( ) : void {
100+ const config = this . _configurationService . getConfiguration < any > ( TELEMETRY_SECTION_ID ) ;
101+ this . _configuration . userOptIn = config ? config . enableTelemetry : this . _configuration . userOptIn ;
130102 }
131103
132104 private _onUserIdle ( ) : void {
@@ -153,7 +125,7 @@ export class TelemetryService implements ITelemetryService {
153125 }
154126
155127 public getTelemetryInfo ( ) : TPromise < ITelemetryInfo > {
156- return this . _commonProperties . then ( values => {
128+ return this . _configuration . commonProperties . then ( values => {
157129 // well known properties
158130 let sessionId = values [ 'sessionID' ] ;
159131 let instanceId = values [ 'common.instanceId' ] ;
@@ -179,23 +151,20 @@ export class TelemetryService implements ITelemetryService {
179151 return event ;
180152 }
181153
182- public publicLog ( eventName : string , data ?: any ) : void {
183- this . _handleEvent ( eventName , data ) ;
184- }
154+ public publicLog ( eventName : string , data ?: any ) : TPromise < any > {
185155
186- private _handleEvent ( eventName : string , data ?: any ) : void {
187156 if ( this . _hardIdleMonitor && this . _hardIdleMonitor . getStatus ( ) === UserStatus . Idle ) {
188- return ;
157+ return TPromise . as ( undefined ) ;
189158 }
190159
191160 // don't send events when the user is optout unless the event is the opt{in|out} signal
192161 if ( ! this . _configuration . userOptIn && eventName !== 'optInStatus' ) {
193- return ;
162+ return TPromise . as ( undefined ) ;
194163 }
195164
196- // (first) add common properties
197- this . _commonProperties . then ( values => {
165+ return this . _configuration . commonProperties . then ( values => {
198166
167+ // (first) add common properties
199168 data = mixin ( data , values ) ;
200169
201170 // (last) remove all PII from data
@@ -209,7 +178,8 @@ export class TelemetryService implements ITelemetryService {
209178 appender . log ( eventName , data ) ;
210179 }
211180
212- } ) . done ( undefined , err => {
181+ } , err => {
182+ // unsure what to do now...
213183 console . error ( err ) ;
214184 } ) ;
215185 }
@@ -226,3 +196,19 @@ export class TelemetryService implements ITelemetryService {
226196 }
227197}
228198
199+
200+ const TELEMETRY_SECTION_ID = 'telemetry' ;
201+
202+ Registry . as < IConfigurationRegistry > ( Extensions . Configuration ) . registerConfiguration ( {
203+ 'id' : TELEMETRY_SECTION_ID ,
204+ 'order' : 20 ,
205+ 'type' : 'object' ,
206+ 'title' : localize ( 'telemetryConfigurationTitle' , "Telemetry configuration" ) ,
207+ 'properties' : {
208+ 'telemetry.enableTelemetry' : {
209+ 'type' : 'boolean' ,
210+ 'description' : localize ( 'telemetry.enableTelemetry' , "Enable usage data and errors to be sent to Microsoft." ) ,
211+ 'default' : true
212+ }
213+ }
214+ } ) ;
0 commit comments