@@ -63,12 +63,10 @@ export class BaseTelemetryAppender implements ITelemetryAppender {
6363 private _exceptionQueue : Array < { exception : Error ; data : AppenderData | undefined } > = [ ] ;
6464
6565 // Necessary information to create a telemetry client
66- private _clientFactory : ( key : string ) => Promise < BaseTelemetryClient > ;
67- private _key : string ;
66+ private _clientFactory : ( ) => Promise < BaseTelemetryClient > ;
6867
69- constructor ( key : string , clientFactory : ( key : string ) => Promise < BaseTelemetryClient > ) {
68+ constructor ( clientFactory : ( ) => Promise < BaseTelemetryClient > ) {
7069 this . _clientFactory = clientFactory ;
71- this . _key = key ;
7270 if ( getTelemetryLevel ( ) !== TelemetryLevel . OFF ) {
7371 this . instantiateAppender ( ) ;
7472 }
@@ -124,20 +122,25 @@ export class BaseTelemetryAppender implements ITelemetryAppender {
124122 this . _exceptionQueue = [ ] ;
125123 }
126124
125+ private isInstantiating = false ;
126+
127127 /**
128128 * Instantiates the telemetry client to make the appender "active"
129129 */
130130 instantiateAppender ( ) : void {
131- if ( this . _isInstantiated ) {
131+ if ( this . isInstantiating || this . _isInstantiated ) {
132132 return ;
133133 }
134+ this . isInstantiating = true ;
134135 // 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 => {
136137 this . _telemetryClient = client ;
137138 this . _isInstantiated = true ;
138139 this . _flushQueues ( ) ;
139140 } ) . catch ( err => {
140141 console . error ( err ) ;
142+ } ) . finally ( ( ) => {
143+ this . isInstantiating = false ;
141144 } ) ;
142145 }
143146}
@@ -146,12 +149,13 @@ export class BaseTelemetryReporter extends Disposable {
146149 private userOptIn = false ;
147150 private errorOptIn = false ;
148151 private _extension : vscode . Extension < any > | undefined ;
152+ private readonly appenders = new Map < string , ITelemetryAppender > ( ) ;
149153
150154 constructor (
151155 private extensionId : string ,
152156 private extensionVersion : string ,
153- private telemetryAppender : ITelemetryAppender ,
154157 private osShim : { release : string ; platform : string ; architecture : string } ,
158+ private readonly clientFactory : ( gitpodHost : string ) => Promise < BaseTelemetryClient >
155159 ) {
156160 super ( ) ;
157161
@@ -173,7 +177,7 @@ export class BaseTelemetryReporter extends Disposable {
173177 this . userOptIn = telemetryLevel === TelemetryLevel . ON ;
174178 this . errorOptIn = telemetryLevel === TelemetryLevel . ERROR || this . userOptIn ;
175179 if ( this . userOptIn || this . errorOptIn ) {
176- this . telemetryAppender . instantiateAppender ( ) ;
180+ this . appenders . forEach ( appender => appender . instantiateAppender ( ) ) ;
177181 }
178182 }
179183
@@ -354,11 +358,11 @@ export class BaseTelemetryReporter extends Disposable {
354358 * @param eventName The name of the event
355359 * @param properties The properties to send with the event
356360 */
357- public sendTelemetryEvent ( eventName : string , properties ?: TelemetryEventProperties ) : void {
361+ public sendTelemetryEvent ( gitpodHost : string , eventName : string , properties ?: TelemetryEventProperties ) : void {
358362 if ( this . userOptIn && eventName !== '' ) {
359363 properties = { ...properties , ...this . getCommonProperties ( ) } ;
360364 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 ) } ) ;
362366 }
363367 }
364368
@@ -367,10 +371,10 @@ export class BaseTelemetryReporter extends Disposable {
367371 * @param eventName The name of the event
368372 * @param properties The properties to send with the event
369373 */
370- public sendRawTelemetryEvent ( eventName : string , properties ?: RawTelemetryEventProperties ) : void {
374+ public sendRawTelemetryEvent ( gitpodHost : string , eventName : string , properties ?: RawTelemetryEventProperties ) : void {
371375 if ( this . userOptIn && eventName !== '' ) {
372376 properties = { ...properties , ...this . getCommonProperties ( ) } ;
373- this . telemetryAppender . logEvent ( `${ eventName } ` , { properties } ) ;
377+ this . getAppender ( gitpodHost ) . logEvent ( `${ eventName } ` , { properties } ) ;
374378 }
375379 }
376380
@@ -379,14 +383,14 @@ export class BaseTelemetryReporter extends Disposable {
379383 * @param eventName The name of the event
380384 * @param properties The properties to send with the event
381385 */
382- public sendTelemetryErrorEvent ( eventName : string , properties ?: { [ key : string ] : string } ) : void {
386+ public sendTelemetryErrorEvent ( gitpodHost : string , eventName : string , properties ?: { [ key : string ] : string } ) : void {
383387 if ( this . errorOptIn && eventName !== '' ) {
384388 // always clean the properties if first party
385389 // do not send any error properties if we shouldn't send error telemetry
386390 // if we have no errorProps, assume all are error props
387391 properties = { ...properties , ...this . getCommonProperties ( ) } ;
388392 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 ) } ) ;
390394 }
391395 }
392396
@@ -395,20 +399,31 @@ export class BaseTelemetryReporter extends Disposable {
395399 * @param error The error to send
396400 * @param properties The properties to send with the event
397401 */
398- public sendTelemetryException ( error : Error , properties ?: TelemetryEventProperties ) : void {
402+ public sendTelemetryException ( gitpodHost : string , error : Error , properties ?: TelemetryEventProperties ) : void {
399403 if ( this . errorOptIn && error ) {
400404 properties = { ...properties , ...this . getCommonProperties ( ) } ;
401405 const cleanProperties = this . cloneAndChange ( properties , ( _key : string , prop : string ) => this . anonymizeFilePaths ( prop , false ) ) ;
402406 // Also run the error stack through the anonymizer
403407 if ( error . stack ) {
404408 error . stack = this . anonymizeFilePaths ( error . stack , false ) ;
405409 }
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 ) ;
407421 }
422+ return appender ;
408423 }
409424
410425 public override async dispose ( ) : Promise < void > {
411426 super . dispose ( ) ;
412- await this . telemetryAppender . flush ( ) ;
427+ await Promise . allSettled ( [ ... this . appenders . values ( ) ] . map ( a => a . flush ( ) ) ) ;
413428 }
414429}
0 commit comments