@@ -63,12 +63,10 @@ export class BaseTelemetryAppender implements ITelemetryAppender {
63
63
private _exceptionQueue : Array < { exception : Error ; data : AppenderData | undefined } > = [ ] ;
64
64
65
65
// Necessary information to create a telemetry client
66
- private _clientFactory : ( key : string ) => Promise < BaseTelemetryClient > ;
67
- private _key : string ;
66
+ private _clientFactory : ( ) => Promise < BaseTelemetryClient > ;
68
67
69
- constructor ( key : string , clientFactory : ( key : string ) => Promise < BaseTelemetryClient > ) {
68
+ constructor ( clientFactory : ( ) => Promise < BaseTelemetryClient > ) {
70
69
this . _clientFactory = clientFactory ;
71
- this . _key = key ;
72
70
if ( getTelemetryLevel ( ) !== TelemetryLevel . OFF ) {
73
71
this . instantiateAppender ( ) ;
74
72
}
@@ -124,20 +122,25 @@ export class BaseTelemetryAppender implements ITelemetryAppender {
124
122
this . _exceptionQueue = [ ] ;
125
123
}
126
124
125
+ private isInstantiating = false ;
126
+
127
127
/**
128
128
* Instantiates the telemetry client to make the appender "active"
129
129
*/
130
130
instantiateAppender ( ) : void {
131
- if ( this . _isInstantiated ) {
131
+ if ( this . isInstantiating || this . _isInstantiated ) {
132
132
return ;
133
133
}
134
+ this . isInstantiating = true ;
134
135
// Call the client factory to get the client and then let it know it's instatntiated
135
- this . _clientFactory ( this . _key ) . then ( client => {
136
+ this . _clientFactory ( ) . then ( client => {
136
137
this . _telemetryClient = client ;
137
138
this . _isInstantiated = true ;
138
139
this . _flushQueues ( ) ;
139
140
} ) . catch ( err => {
140
141
console . error ( err ) ;
142
+ } ) . finally ( ( ) => {
143
+ this . isInstantiating = false ;
141
144
} ) ;
142
145
}
143
146
}
@@ -146,12 +149,13 @@ export class BaseTelemetryReporter extends Disposable {
146
149
private userOptIn = false ;
147
150
private errorOptIn = false ;
148
151
private _extension : vscode . Extension < any > | undefined ;
152
+ private readonly appenders = new Map < string , ITelemetryAppender > ( ) ;
149
153
150
154
constructor (
151
155
private extensionId : string ,
152
156
private extensionVersion : string ,
153
- private telemetryAppender : ITelemetryAppender ,
154
157
private osShim : { release : string ; platform : string ; architecture : string } ,
158
+ private readonly clientFactory : ( gitpodHost : string ) => Promise < BaseTelemetryClient >
155
159
) {
156
160
super ( ) ;
157
161
@@ -173,7 +177,7 @@ export class BaseTelemetryReporter extends Disposable {
173
177
this . userOptIn = telemetryLevel === TelemetryLevel . ON ;
174
178
this . errorOptIn = telemetryLevel === TelemetryLevel . ERROR || this . userOptIn ;
175
179
if ( this . userOptIn || this . errorOptIn ) {
176
- this . telemetryAppender . instantiateAppender ( ) ;
180
+ this . appenders . forEach ( appender => appender . instantiateAppender ( ) ) ;
177
181
}
178
182
}
179
183
@@ -354,11 +358,11 @@ export class BaseTelemetryReporter extends Disposable {
354
358
* @param eventName The name of the event
355
359
* @param properties The properties to send with the event
356
360
*/
357
- public sendTelemetryEvent ( eventName : string , properties ?: TelemetryEventProperties ) : void {
361
+ public sendTelemetryEvent ( gitpodHost : string , eventName : string , properties ?: TelemetryEventProperties ) : void {
358
362
if ( this . userOptIn && eventName !== '' ) {
359
363
properties = { ...properties , ...this . getCommonProperties ( ) } ;
360
364
const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , false ) ) ;
361
- this . telemetryAppender . logEvent ( `${ eventName } ` , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) } ) ;
365
+ this . getAppender ( gitpodHost ) . logEvent ( `${ eventName } ` , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) } ) ;
362
366
}
363
367
}
364
368
@@ -367,10 +371,10 @@ export class BaseTelemetryReporter extends Disposable {
367
371
* @param eventName The name of the event
368
372
* @param properties The properties to send with the event
369
373
*/
370
- public sendRawTelemetryEvent ( eventName : string , properties ?: RawTelemetryEventProperties ) : void {
374
+ public sendRawTelemetryEvent ( gitpodHost : string , eventName : string , properties ?: RawTelemetryEventProperties ) : void {
371
375
if ( this . userOptIn && eventName !== '' ) {
372
376
properties = { ...properties , ...this . getCommonProperties ( ) } ;
373
- this . telemetryAppender . logEvent ( `${ eventName } ` , { properties } ) ;
377
+ this . getAppender ( gitpodHost ) . logEvent ( `${ eventName } ` , { properties } ) ;
374
378
}
375
379
}
376
380
@@ -379,14 +383,14 @@ export class BaseTelemetryReporter extends Disposable {
379
383
* @param eventName The name of the event
380
384
* @param properties The properties to send with the event
381
385
*/
382
- public sendTelemetryErrorEvent ( eventName : string , properties ?: { [ key : string ] : string } ) : void {
386
+ public sendTelemetryErrorEvent ( gitpodHost : string , eventName : string , properties ?: { [ key : string ] : string } ) : void {
383
387
if ( this . errorOptIn && eventName !== '' ) {
384
388
// always clean the properties if first party
385
389
// do not send any error properties if we shouldn't send error telemetry
386
390
// if we have no errorProps, assume all are error props
387
391
properties = { ...properties , ...this . getCommonProperties ( ) } ;
388
392
const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , false ) ) ;
389
- this . telemetryAppender . logEvent ( `${ eventName } ` , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) } ) ;
393
+ this . getAppender ( gitpodHost ) . logEvent ( `${ eventName } ` , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) } ) ;
390
394
}
391
395
}
392
396
@@ -395,20 +399,31 @@ export class BaseTelemetryReporter extends Disposable {
395
399
* @param error The error to send
396
400
* @param properties The properties to send with the event
397
401
*/
398
- public sendTelemetryException ( error : Error , properties ?: TelemetryEventProperties ) : void {
402
+ public sendTelemetryException ( gitpodHost : string , error : Error , properties ?: TelemetryEventProperties ) : void {
399
403
if ( this . errorOptIn && error ) {
400
404
properties = { ...properties , ...this . getCommonProperties ( ) } ;
401
405
const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , false ) ) ;
402
406
// Also run the error stack through the anonymizer
403
407
if ( error . stack ) {
404
408
error . stack = this . anonymizeFilePaths ( error . stack , false ) ;
405
409
}
406
- this . telemetryAppender . logException ( error , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) } ) ;
410
+ this . getAppender ( gitpodHost ) . logException ( error , { properties : this . removePropertiesWithPossibleUserInfo ( cleanProperties ) } ) ;
411
+ }
412
+ }
413
+
414
+ private getAppender ( gitpodHost : string ) {
415
+ const gitpodHostUrl = new URL ( gitpodHost ) ;
416
+ const serviceUrl = gitpodHostUrl . toString ( ) . replace ( / \/ $ / , '' ) . toLowerCase ( ) ;
417
+ let appender = this . appenders . get ( serviceUrl ) ;
418
+ if ( ! appender ) {
419
+ appender = new BaseTelemetryAppender ( ( ) => this . clientFactory ( serviceUrl ) ) ;
420
+ this . appenders . set ( serviceUrl , appender ) ;
407
421
}
422
+ return appender ;
408
423
}
409
424
410
425
public override async dispose ( ) : Promise < void > {
411
426
super . dispose ( ) ;
412
- await this . telemetryAppender . flush ( ) ;
427
+ await Promise . allSettled ( [ ... this . appenders . values ( ) ] . map ( a => a . flush ( ) ) ) ;
413
428
}
414
429
}
0 commit comments