@@ -39,9 +39,9 @@ export class Tracer {
39
39
40
40
this . tracingConsent = new TracingConsentCache ( ctx . extensionContext . workspaceState )
41
41
42
- this . remoteWorkspaceDumpUrl = this . ctx . extensionConfig . get < string > ( 'remoteWorkspaceDumpUrl' )
43
- this . remoteTracingUrl = this . ctx . extensionConfig . get < string > ( 'remoteTracingUrl' )
44
- const maximumMessageSize = this . ctx . extensionConfig . get < number > ( 'tracing .maximumMessageSize' )
42
+ this . remoteWorkspaceDumpUrl = this . ctx . extensionConfig . get < string > ( 'trace. remoteWorkspaceDumpUrl' )
43
+ this . remoteTracingUrl = this . ctx . extensionConfig . get < string > ( 'trace. remoteTracingUrl' )
44
+ const maximumMessageSize = this . ctx . extensionConfig . get < number > ( 'trace .maximumMessageSize' )
45
45
this . maximumMessageSize = maximumMessageSize === undefined || maximumMessageSize < 0 ? 0 : maximumMessageSize | 0
46
46
47
47
this . machineId = ( ( ) => {
@@ -73,16 +73,17 @@ export class Tracer {
73
73
this . sessionId = new Date ( ) . toISOString ( )
74
74
}
75
75
76
- run ( ) : { lspOutputChannel ?: vscode . OutputChannel } {
76
+ run ( ) : vscode . OutputChannel | undefined {
77
77
const consentCommandDisposable = vscode . commands . registerCommand ( consentCommandName , ( ) => this . askForTracingConsent ( ) )
78
78
if ( this . isTracingEnabled && this . tracingConsent . get ( ) === 'no-answer' ) this . askForTracingConsent ( )
79
79
this . initializeAsyncWorkspaceDump ( )
80
+
80
81
const lspOutputChannel = this . createLspOutputChannel ( )
81
82
const statusBarItem = this . createStatusBarItem ( )
82
83
for ( const disposable of [ consentCommandDisposable , lspOutputChannel , statusBarItem ] ) {
83
84
if ( disposable ) this . ctx . extensionContext . subscriptions . push ( disposable )
84
85
}
85
- return { lspOutputChannel }
86
+ return lspOutputChannel
86
87
}
87
88
88
89
private askForTracingConsent ( ) : void {
@@ -97,13 +98,12 @@ export class Tracer {
97
98
}
98
99
99
100
private initializeAsyncWorkspaceDump ( ) {
100
- if ( this . remoteWorkspaceDumpUrl === undefined ) return
101
- // convince TS that this is a string
102
- const definedUrl : string = this . remoteWorkspaceDumpUrl
101
+ const url = this . remoteWorkspaceDumpUrl
102
+ if ( url === undefined ) return
103
103
104
104
const doInitialize = ( ) => {
105
105
try {
106
- this . asyncUploadWorkspaceDump ( definedUrl )
106
+ this . asyncUploadWorkspaceDump ( url )
107
107
} catch ( err ) {
108
108
this . logError ( 'error during workspace dump' , safeError ( err ) )
109
109
}
@@ -144,14 +144,20 @@ export class Tracer {
144
144
}
145
145
146
146
private createLspOutputChannel ( ) : vscode . OutputChannel | undefined {
147
- if ( ! this . remoteTracingUrl ) return undefined
147
+ if ( this . ctx . extensionConfig . get ( 'trace.server' ) === undefined ) {
148
+ if ( this . remoteTracingUrl ) this . ctx . extensionOut . appendLine (
149
+ 'error: tracing URL is set, but trace.server not - no remote tracing possible.'
150
+ )
151
+ return undefined
152
+ }
148
153
149
- const localLspOutputChannel = vscode . window . createOutputChannel ( 'Dotty LSP Communication' )
154
+ const lspOutputChannel = vscode . window . createOutputChannel ( 'Dotty LSP Communication' )
155
+ if ( ! this . remoteTracingUrl ) return lspOutputChannel
150
156
try {
151
- return this . createRemoteLspOutputChannel ( this . remoteTracingUrl , localLspOutputChannel )
157
+ return this . createRemoteLspOutputChannel ( this . remoteTracingUrl , lspOutputChannel )
152
158
} catch ( err ) {
153
159
this . logError ( 'error during remote output channel creation' , safeError ( err ) )
154
- return localLspOutputChannel
160
+ return lspOutputChannel
155
161
}
156
162
}
157
163
@@ -225,7 +231,7 @@ export class Tracer {
225
231
)
226
232
227
233
socket . onerror = ( event ) => {
228
- this . logErrorWithoutNotifying (
234
+ this . logError (
229
235
'socket error' ,
230
236
remoteTracingUrl ,
231
237
new SafeJsonifier ( event , ( event ) => ( {
@@ -238,7 +244,7 @@ export class Tracer {
238
244
}
239
245
240
246
socket . onclose = ( event ) => {
241
- this . logErrorWithoutNotifying (
247
+ this . logError (
242
248
'socket closed' ,
243
249
remoteTracingUrl ,
244
250
new SafeJsonifier ( event , ( event ) => ( {
@@ -319,11 +325,12 @@ export class Tracer {
319
325
}
320
326
}
321
327
322
- private silenceErrors : boolean = false
323
- private logErrorWithoutNotifying ( message : string , ...rest : any [ ] ) {
328
+ private logError ( message : string , ...rest : any [ ] ) {
324
329
const msg = `[Dotty LSP Tracer] ${ message } `
325
- // unwrap SafeJsonifier, for some reason Electron logs the result
326
- // of .toJSON, unlike browsers
330
+ // in a browser, we'd be able to log a SafeJsonifier directly
331
+ // and get an inspectable object in the console
332
+ // unfortunately, Electron apparently uses .toJson if available,
333
+ // so we need to manually unwrap SafeJsonifiers
327
334
console . error ( msg , ...rest . map ( ( a ) => a instanceof SafeJsonifier ? a . value : a ) )
328
335
function cautiousStringify ( a : any ) : string {
329
336
try {
@@ -335,34 +342,22 @@ export class Tracer {
335
342
}
336
343
this . ctx . extensionOut . appendLine ( [ msg ] . concat ( rest . map ( cautiousStringify ) ) . join ( ' ' ) )
337
344
}
338
- private logError ( message : string , ...rest : any [ ] ) {
339
- this . logErrorWithoutNotifying ( message , ...rest )
340
- if ( ! this . silenceErrors ) {
341
- vscode . window . showErrorMessage (
342
- 'An error occured which prevents sending usage data to EPFL. ' +
343
- 'Please copy the text from "Dotty Language Client" output (View > Output) and send it to your TA.' ,
344
- 'Silence further errors'
345
- ) . then ( ( result ) => {
346
- if ( result !== undefined ) {
347
- this . silenceErrors = true
348
- }
349
- } )
350
- }
351
- }
352
345
}
353
346
354
347
function safeError ( e : Error ) : SafeJsonifier < Error > {
355
348
return new SafeJsonifier ( e , ( e ) => e . toString ( ) )
356
349
}
357
350
351
+ /**
352
+ * Wraps a value of type T so it's possible to safely pass it to JSON.stringify.
353
+ *
354
+ * Values with circular references (errors, for example) cause JSON.stringify to throw an exception
355
+ */
358
356
class SafeJsonifier < T > {
359
- value : T
360
- valueToObject : ( t : T ) => { }
361
-
362
- constructor ( value : T , valueToObject : ( t : T ) => { } ) {
363
- this . value = value
364
- this . valueToObject = valueToObject
365
- }
357
+ constructor (
358
+ readonly value : T ,
359
+ readonly valueToObject : ( t : T ) => { }
360
+ ) { }
366
361
367
362
toJSON ( ) {
368
363
return this . valueToObject ( this . value )
0 commit comments