@@ -13,17 +13,25 @@ import * as cp from 'child_process';
13
13
import { getWorkspaceFolderPath } from './util' ;
14
14
import { toolExecutionEnvironment } from './goEnv' ;
15
15
16
- // Name of the prompt telemetry command. This is also used to determine if the gopls instance supports telemetry.
17
- // Exported for testing.
16
+ /**
17
+ * Name of the prompt telemetry command. This is also used to determine if the
18
+ * gopls instance supports telemetry.
19
+ * Exported for testing.
20
+ */
18
21
export const GOPLS_MAYBE_PROMPT_FOR_TELEMETRY = 'gopls.maybe_prompt_for_telemetry' ;
19
22
20
- // Key for the global state that holds the very first time the telemetry-enabled gopls was observed.
21
- // Exported for testing.
23
+ /**
24
+ * Key for the global state that holds the very first time the telemetry-enabled
25
+ * gopls was observed.
26
+ * Exported for testing.
27
+ */
22
28
export const TELEMETRY_START_TIME_KEY = 'telemetryStartTime' ;
23
29
24
- // Run our encode/decode function for the Date object, to be defensive
25
- // from vscode Memento API behavior change.
26
- // Exported for testing.
30
+ /**
31
+ * Run our encode/decode function for the Date object, to be defensive from
32
+ * vscode Memento API behavior change.
33
+ * Exported for testing.
34
+ */
27
35
export function recordTelemetryStartTime ( storage : vscode . Memento , date : Date ) {
28
36
storage . update ( TELEMETRY_START_TIME_KEY , date . toJSON ( ) ) ;
29
37
}
@@ -43,32 +51,57 @@ function readTelemetryStartTime(storage: vscode.Memento): Date | null {
43
51
enum ReporterState {
44
52
NOT_INITIALIZED ,
45
53
IDLE ,
46
- STARTING ,
47
54
RUNNING
48
55
}
49
56
50
- // exported for testing.
57
+ /**
58
+ * Manages Go telemetry data and persists them to disk using a storage tool.
59
+ *
60
+ * **Usage:**
61
+ * 1. Call `setTool(tool)` once, before any other methods.
62
+ * 2. Call `add(key, value)` to add values associated with keys.
63
+ * 3. Data is automatically flushed to disk periodically.
64
+ * 4. To force an immediate flush, call `flush(true)`.
65
+ *
66
+ * **Example:**
67
+ * ```typescript
68
+ * const r = new TelemetryReporter();
69
+ * r.setTool(vscgo);
70
+ * r.add("count", 10);
71
+ * r.add("count", 5);
72
+ * r.flush(true); // Force a flush
73
+ * ```
74
+ *
75
+ * Exported for testing.
76
+ */
51
77
export class TelemetryReporter implements vscode . Disposable {
52
78
private _state = ReporterState . NOT_INITIALIZED ;
53
79
private _counters : { [ key : string ] : number } = { } ;
54
80
private _flushTimer : NodeJS . Timeout | undefined ;
55
81
private _tool = '' ;
56
82
constructor ( flushIntervalMs = 60_000 , private counterFile : string = '' ) {
57
83
if ( flushIntervalMs > 0 ) {
58
- // periodically call flush.
84
+ // Periodically call flush.
59
85
this . _flushTimer = setInterval ( this . flush . bind ( this ) , flushIntervalMs ) ;
60
86
}
61
87
}
62
88
89
+ /**
90
+ * Initializes the tool.
91
+ * This method should be called once. Subsequent calls have no effect.
92
+ */
63
93
public setTool ( tool : string ) {
64
- // allow only once.
94
+ // Allow only once.
65
95
if ( tool === '' || this . _state !== ReporterState . NOT_INITIALIZED ) {
66
96
return ;
67
97
}
68
98
this . _state = ReporterState . IDLE ;
69
99
this . _tool = tool ;
70
100
}
71
101
102
+ /**
103
+ * Adds a numeric value to a counter associated with the given key.
104
+ */
72
105
public add ( key : string , value : number ) {
73
106
if ( value <= 0 ) {
74
107
return ;
@@ -77,16 +110,20 @@ export class TelemetryReporter implements vscode.Disposable {
77
110
this . _counters [ key ] = ( this . _counters [ key ] || 0 ) + value ;
78
111
}
79
112
80
- // flush is called periodically (by the callback set up in the constructor)
81
- // or when the extension is deactivated (with force=true).
113
+ /**
114
+ * Flushes Go telemetry data.
115
+ * * When `force` is true, telemetry is flushed immediately, bypassing the
116
+ * IDLE state check.
117
+ * * When `force` is false, telemetry is flushed only if the reporter is IDLE.
118
+ */
82
119
public async flush ( force = false ) {
83
120
// If flush runs with force=true, ignore the state and skip state update.
84
121
if ( ! force && this . _state !== ReporterState . IDLE ) {
85
122
// vscgo is not installed yet or is running. flush next time.
86
123
return 0 ;
87
124
}
88
125
if ( ! force ) {
89
- this . _state = ReporterState . STARTING ;
126
+ this . _state = ReporterState . RUNNING ;
90
127
}
91
128
try {
92
129
await this . writeGoTelemetry ( ) ;
@@ -142,11 +179,13 @@ export class TelemetryReporter implements vscode.Disposable {
142
179
clearInterval ( this . _flushTimer ) ;
143
180
}
144
181
this . _flushTimer = undefined ;
145
- await this . flush ( true ) ; // flush any remaining data in buffer.
182
+ await this . flush ( true ) ; // Flush any remaining data in buffer.
146
183
}
147
184
}
148
185
149
- // global telemetryReporter instance.
186
+ /**
187
+ * Global telemetryReporter instance.
188
+ */
150
189
export const telemetryReporter = new TelemetryReporter ( ) ;
151
190
152
191
// TODO(hyangah): consolidate the list of all the telemetries and bucketting functions.
@@ -155,8 +194,10 @@ export function addTelemetryEvent(name: string, count: number) {
155
194
telemetryReporter . add ( name , count ) ;
156
195
}
157
196
158
- // Go extension delegates most of the telemetry logic to gopls.
159
- // TelemetryService provides API to interact with gopls's telemetry.
197
+ /**
198
+ * Go extension delegates most of the telemetry logic to gopls.
199
+ * TelemetryService provides API to interact with gopls's telemetry.
200
+ */
160
201
export class TelemetryService {
161
202
private active = false ;
162
203
constructor (
@@ -219,8 +260,10 @@ export class TelemetryService {
219
260
}
220
261
}
221
262
222
- // Set telemetry env vars for gopls. See gopls/internal/server/prompt.go
223
- // TODO(hyangah): add an integration testing after gopls v0.17 becomes available.
263
+ /**
264
+ * Set telemetry env vars for gopls. See gopls/internal/server/prompt.go
265
+ * TODO(hyangah): add an integration testing after gopls v0.17 becomes available.
266
+ */
224
267
export function setTelemetryEnvVars ( globalState : vscode . Memento , env : NodeJS . ProcessEnv ) {
225
268
if ( ! env [ 'GOTELEMETRY_GOPLS_CLIENT_TOKEN' ] ) {
226
269
env [ 'GOTELEMETRY_GOPLS_CLIENT_TOKEN' ] = `${ hashMachineID ( ) + 1 } ` ; // [1, 1000]
@@ -234,7 +277,9 @@ export function setTelemetryEnvVars(globalState: vscode.Memento, env: NodeJS.Pro
234
277
}
235
278
}
236
279
237
- // Map vscode.env.machineId to an integer in [0, 1000).
280
+ /**
281
+ * Map vscode.env.machineId to an integer in [0, 1000).
282
+ */
238
283
function hashMachineID ( salt ?: string ) : number {
239
284
const hash = createHash ( 'md5' ) . update ( `${ vscode . env . machineId } ${ salt } ` ) . digest ( 'hex' ) ;
240
285
return parseInt ( hash . substring ( 0 , 8 ) , 16 ) % 1000 ;
0 commit comments