@@ -9,6 +9,7 @@ import * as path from 'path'
9
9
import uuidv4 = require( 'uuid/v4' )
10
10
import { ExtensionContext } from 'vscode'
11
11
import { AwsContext } from '../awsContext'
12
+ import { getLogger } from '../logger'
12
13
import { DefaultTelemetryClient } from './defaultTelemetryClient'
13
14
import { DefaultTelemetryPublisher } from './defaultTelemetryPublisher'
14
15
import { recordSessionEnd , recordSessionStart } from './telemetry'
@@ -48,8 +49,8 @@ export class DefaultTelemetryService implements TelemetryService {
48
49
}
49
50
50
51
this . startTime = new Date ( )
51
- this . _eventQueue = DefaultTelemetryService . readEventsFromCache ( this . persistFilePath )
52
52
53
+ this . _eventQueue = [ ]
53
54
this . _flushPeriod = DefaultTelemetryService . DEFAULT_FLUSH_PERIOD_MILLIS
54
55
55
56
if ( publisher !== undefined ) {
@@ -62,6 +63,7 @@ export class DefaultTelemetryService implements TelemetryService {
62
63
}
63
64
64
65
public async start ( ) : Promise < void > {
66
+ this . _eventQueue . push ( ...DefaultTelemetryService . readEventsFromCache ( this . persistFilePath ) )
65
67
recordSessionStart ( )
66
68
await this . startTimer ( )
67
69
}
@@ -244,14 +246,72 @@ export class DefaultTelemetryService implements TelemetryService {
244
246
245
247
private static readEventsFromCache ( cachePath : string ) : TelemetryEvent [ ] {
246
248
try {
247
- const events = JSON . parse ( fs . readFileSync ( cachePath , 'utf-8' ) ) as TelemetryEvent [ ]
249
+ const input = JSON . parse ( fs . readFileSync ( cachePath , 'utf-8' ) )
250
+ const events = filterTelemetryCacheEvents ( input )
248
251
events . forEach ( ( element : TelemetryEvent ) => {
252
+ // This is coercing the createTime into a Date type: it's read in as a string
249
253
element . createTime = new Date ( element . createTime )
250
254
} )
251
255
252
256
return events
253
- } catch {
257
+ } catch ( error ) {
258
+ // tslint:disable-next-line: no-unsafe-any
259
+ getLogger ( ) . error ( error )
260
+
254
261
return [ ]
255
262
}
256
263
}
257
264
}
265
+
266
+ export function filterTelemetryCacheEvents ( input : any ) : TelemetryEvent [ ] {
267
+ if ( ! Array . isArray ( input ) ) {
268
+ getLogger ( ) . error ( `Input into filterTelemetryCacheEvents:\n${ input } \nis not an array!` )
269
+
270
+ return [ ]
271
+ }
272
+ const arr = input as any [ ]
273
+
274
+ return arr
275
+ . filter ( ( item : any ) => {
276
+ // Make sure the item is an object
277
+ if ( item !== Object ( item ) ) {
278
+ getLogger ( ) . error ( `Item in telemetry cache:\n${ item } \nis not an object! skipping!` )
279
+
280
+ return false
281
+ }
282
+
283
+ return true
284
+ } )
285
+ . filter ( ( item : Object ) => {
286
+ // Only accept objects that have createTime and data because that's what's required by TelemetryEvent
287
+ if ( ! item . hasOwnProperty ( 'createTime' ) || ! item . hasOwnProperty ( 'data' ) ) {
288
+ getLogger ( ) . warn ( `Item in telemetry cache: ${ item } \n does not have 'data' or 'createTime'! skipping!` )
289
+
290
+ return false
291
+ }
292
+
293
+ return true
294
+ } )
295
+ . filter ( ( item : TelemetryEvent ) => {
296
+ // skip it if data is not an array or empty
297
+ if ( ! Array . isArray ( item . data ) || item . data . length === 0 ) {
298
+ getLogger ( ) . warn ( `Item in telemetry cache: ${ item } \n has invalid data field: ${ item . data } ! skipping!` )
299
+
300
+ return false
301
+ }
302
+
303
+ // Only accept objects that have value and metricname which are the base things required for telemetry
304
+ return item . data . every ( data => {
305
+ // Make sure data is actually an object then check that it has the required properties
306
+ if ( data !== Object ( data ) || ! data . hasOwnProperty ( 'Value' ) || ! data . hasOwnProperty ( 'MetricName' ) ) {
307
+ getLogger ( ) . warn (
308
+ `Item in telemetry cache: ${ item } \n has invalid data in the field 'data': ${ data } ! skipping!`
309
+ )
310
+
311
+ return false
312
+ }
313
+
314
+ return true
315
+ } )
316
+ } ) as TelemetryEvent [ ]
317
+ }
0 commit comments