@@ -6,6 +6,11 @@ import logger from '../logger.js';
6
6
import { mongoLogId } from 'mongodb-log-writer' ;
7
7
import { ApiClient } from '../common/atlas/apiClient.js' ;
8
8
import { ApiClientError } from '../common/atlas/apiClientError.js' ;
9
+ import fs from 'fs/promises' ;
10
+ import path from 'path' ;
11
+
12
+ const isTelemetryEnabled = config . telemetry === 'enabled' ;
13
+ const CACHE_FILE = path . join ( process . cwd ( ) , '.telemetry-cache.json' ) ;
9
14
10
15
export class Telemetry {
11
16
constructor ( private readonly session : Session ) { }
@@ -23,10 +28,8 @@ export class Telemetry {
23
28
os_version : config . os_version ,
24
29
} ;
25
30
26
- private readonly isTelemetryEnabled = config . telemetry === 'enabled' ;
27
-
28
31
async emitToolEvent ( command : string , category : string , startTime : number , result : 'success' | 'failure' , error ?: Error ) : Promise < void > {
29
- if ( ! this . isTelemetryEnabled ) {
32
+ if ( ! isTelemetryEnabled ) {
30
33
logger . debug ( mongoLogId ( 1_000_000 ) , "telemetry" , `Telemetry is disabled, skipping event.` ) ;
31
34
return ;
32
35
}
@@ -50,26 +53,72 @@ export class Telemetry {
50
53
event . properties . error_code = error ?. message ;
51
54
}
52
55
53
- await this . emit ( event ) ;
56
+ await this . emit ( [ event ] ) ;
54
57
}
55
58
56
- private async emit ( event : BaseEvent ) : Promise < void > {
59
+ private async emit ( events : BaseEvent [ ] ) : Promise < void > {
60
+ // First try to read any cached events
61
+ const cachedEvents = await this . readCache ( ) ;
62
+ const allEvents = [ ...cachedEvents , ...events ] ;
63
+
64
+ logger . debug ( mongoLogId ( 1_000_000 ) , "telemetry" , `Attempting to send ${ allEvents . length } events (${ cachedEvents . length } cached)` ) ;
65
+
57
66
try {
58
67
if ( this . session . apiClient ) {
59
- await this . session . apiClient . sendEvents ( [ event ] ) ;
68
+ await this . session . apiClient . sendEvents ( allEvents ) ;
69
+ // If successful, clear the cache
70
+ await this . clearCache ( ) ;
71
+ return ;
60
72
}
61
73
} catch ( error ) {
62
74
logger . warning ( mongoLogId ( 1_000_000 ) , "telemetry" , `Error sending event to authenticated client: ${ error } ` ) ;
75
+ // Cache the events that failed to send
76
+ await this . cacheEvents ( allEvents ) ;
63
77
}
64
78
65
- // if it is unauthenticated, send to temp client
79
+ // Try unauthenticated client as fallback
66
80
try {
67
81
const tempApiClient = new ApiClient ( {
68
82
baseUrl : config . apiBaseUrl ,
69
83
} ) ;
70
- await tempApiClient . sendEvents ( [ event ] ) ;
84
+ await tempApiClient . sendEvents ( allEvents ) ;
85
+ // If successful, clear the cache
86
+ await this . clearCache ( ) ;
71
87
} catch ( error ) {
72
88
logger . warning ( mongoLogId ( 1_000_000 ) , "telemetry" , `Error sending event to unauthenticated client: ${ error } ` ) ;
89
+ // Cache the events that failed to send
90
+ await this . cacheEvents ( allEvents ) ;
91
+ }
92
+ }
93
+
94
+ private async readCache ( ) : Promise < BaseEvent [ ] > {
95
+ try {
96
+ const data = await fs . readFile ( CACHE_FILE , 'utf-8' ) ;
97
+ return JSON . parse ( data ) ;
98
+ } catch ( error ) {
99
+ if ( ( error as NodeJS . ErrnoException ) . code !== 'ENOENT' ) {
100
+ logger . warning ( mongoLogId ( 1_000_000 ) , "telemetry" , `Error reading telemetry cache: ${ error } ` ) ;
101
+ }
102
+ return [ ] ;
103
+ }
104
+ }
105
+
106
+ private async cacheEvents ( events : BaseEvent [ ] ) : Promise < void > {
107
+ try {
108
+ await fs . writeFile ( CACHE_FILE , JSON . stringify ( events , null , 2 ) ) ;
109
+ logger . debug ( mongoLogId ( 1_000_000 ) , "telemetry" , `Cached ${ events . length } events for later sending` ) ;
110
+ } catch ( error ) {
111
+ logger . warning ( mongoLogId ( 1_000_000 ) , "telemetry" , `Failed to cache telemetry events: ${ error } ` ) ;
112
+ }
113
+ }
114
+
115
+ private async clearCache ( ) : Promise < void > {
116
+ try {
117
+ await fs . unlink ( CACHE_FILE ) ;
118
+ } catch ( error ) {
119
+ if ( ( error as NodeJS . ErrnoException ) . code !== 'ENOENT' ) {
120
+ logger . warning ( mongoLogId ( 1_000_000 ) , "telemetry" , `Error clearing telemetry cache: ${ error } ` ) ;
121
+ }
73
122
}
74
123
}
75
124
}
0 commit comments