From 87b8402b5940e92cfcd5b5bc34b6524984f8a89c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 20 Jun 2019 17:04:04 -0700 Subject: [PATCH] Add experimental dual TS server Fixes #75866 --- .../typescript-language-features/package.json | 6 ++ .../package.nls.json | 1 + .../src/test/server.test.ts | 2 +- .../src/tsServer/server.ts | 84 +++++++++++++++---- .../src/tsServer/spanwer.ts | 39 +++++++-- .../src/typescriptService.ts | 36 +++++--- .../src/typescriptServiceClient.ts | 15 ++-- .../src/utils/tracer.ts | 20 ++--- 8 files changed, 152 insertions(+), 51 deletions(-) diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 86f996d0649..00c0445e730 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -591,6 +591,12 @@ "default": true, "description": "%configuration.surveys.enabled%", "scope": "window" + }, + "typescript.experimental.useSeparateSyntaxServer": { + "type": "boolean", + "default": false, + "description": "%configuration.experimental.useSeparateSyntaxServer%", + "scope": "window" } } }, diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index 7e31edca479..569685dec0d 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -49,6 +49,7 @@ "typescript.problemMatchers.tsc.label": "TypeScript problems", "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)", "configuration.suggest.paths": "Enable/disable suggestions for paths in import statements and require calls.", + "configuration.experimental.useSeparateSyntaxServer": "Enable/disable spawning a separate TypeScript server that can more quickly respond to syntax related operations, such as calculating folding or computing document symbols. Note that you must restart the TypeScript server after changing this setting. Requires using TypeScript 3.4.0 or newer in the workspace.", "typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Requires using TypeScript 2.6.0 or newer in the workspace. Default of `null` uses VS Code's locale.", "javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable `experimentalDecorators` for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.", "configuration.suggest.autoImports": "Enable/disable auto import suggestions. Requires using TypeScript 2.6.1 or newer in the workspace.", diff --git a/extensions/typescript-language-features/src/test/server.test.ts b/extensions/typescript-language-features/src/test/server.test.ts index 00a4ff6a254..651967fc12c 100644 --- a/extensions/typescript-language-features/src/test/server.test.ts +++ b/extensions/typescript-language-features/src/test/server.test.ts @@ -62,7 +62,7 @@ suite('Server', () => { test('should send requests with increasing sequence numbers', async () => { const process = new FakeServerProcess(); - const server = new ProcessBasedTsServer(process, undefined, new PipeRequestCanceller(undefined, tracer), undefined!, NoopTelemetryReporter, tracer); + const server = new ProcessBasedTsServer('semantic', process, undefined, new PipeRequestCanceller('semantic', undefined, tracer), undefined!, NoopTelemetryReporter, tracer); const onWrite1 = process.onWrite(); server.executeImpl('geterr', {}, { isAsync: false, token: nulToken, expectsResult: true }); diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index 906da1aa09a..9a2132fa27e 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -7,7 +7,7 @@ import * as fs from 'fs'; import * as stream from 'stream'; import * as vscode from 'vscode'; import * as Proto from '../protocol'; -import { ServerResponse } from '../typescriptService'; +import { ServerResponse, TypeScriptRequests } from '../typescriptService'; import { Disposable } from '../utils/dispose'; import TelemetryReporter from '../utils/telemetry'; import Tracer from '../utils/tracer'; @@ -23,6 +23,7 @@ export interface OngoingRequestCanceller { export class PipeRequestCanceller implements OngoingRequestCanceller { public constructor( + private readonly _serverId: string, private readonly _cancellationPipeName: string | undefined, private readonly _tracer: Tracer, ) { } @@ -31,7 +32,7 @@ export class PipeRequestCanceller implements OngoingRequestCanceller { if (!this._cancellationPipeName) { return false; } - this._tracer.logTrace(`TypeScript Server: trying to cancel ongoing request with sequence number ${seq}`); + this._tracer.logTrace(this._serverId, `TypeScript Server: trying to cancel ongoing request with sequence number ${seq}`); try { fs.writeFileSync(this._cancellationPipeName + seq, ''); } catch { @@ -51,9 +52,9 @@ export interface ITypeScriptServer { kill(): void; - executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined; dispose(): void; } @@ -75,6 +76,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe private readonly _pendingResponses = new Set(); constructor( + private readonly _serverId: string, private readonly _process: TsServerProcess, private readonly _tsServerLogFile: string | undefined, private readonly _requestCanceller: OngoingRequestCanceller, @@ -136,11 +138,11 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe const seq = (event as Proto.RequestCompletedEvent).body.request_seq; const p = this._callbacks.fetch(seq); if (p) { - this._tracer.traceRequestCompleted('requestCompleted', seq, p.startTime); + this._tracer.traceRequestCompleted(this._serverId, 'requestCompleted', seq, p.startTime); p.onSuccess(undefined); } } else { - this._tracer.traceEvent(event); + this._tracer.traceEvent(this._serverId, event); this._onEvent.fire(event); } break; @@ -156,7 +158,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe private tryCancelRequest(seq: number, command: string): boolean { try { if (this._requestQueue.tryDeletePendingRequest(seq)) { - this._tracer.logTrace(`TypeScript Server: canceled request with sequence number ${seq}`); + this.logTrace(`Canceled request with sequence number ${seq}`); return true; } @@ -164,7 +166,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe return true; } - this._tracer.logTrace(`TypeScript Server: tried to cancel request with sequence number ${seq}. But request got already delivered.`); + this.logTrace(`Tried to cancel request with sequence number ${seq}. But request got already delivered.`); return false; } finally { const callback = this.fetchCallback(seq); @@ -180,7 +182,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe return; } - this._tracer.traceResponse(response, callback.startTime); + this._tracer.traceResponse(this._serverId, response, callback.startTime); if (response.success) { callback.onSuccess(response); } else if (response.message === 'No content available.') { @@ -191,9 +193,9 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe } } - public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { const request = this._requestQueue.createRequest(command, args); const requestInfo: RequestItem = { request, @@ -255,7 +257,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe private sendRequest(requestItem: RequestItem): void { const serverRequest = requestItem.request; - this._tracer.traceRequest(serverRequest, requestItem.expectsResponse, this._requestQueue.length); + this._tracer.traceRequest(this._serverId, serverRequest, requestItem.expectsResponse, this._requestQueue.length); if (requestItem.expectsResponse && !requestItem.isAsync) { this._pendingResponses.add(requestItem.request.seq); @@ -281,6 +283,10 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe return callback; } + private logTrace(message: string) { + this._tracer.logTrace(this._serverId, message); + } + private static readonly fenceCommands = new Set(['change', 'close', 'open', 'updateOpen']); private static getQueueingType( @@ -294,3 +300,53 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe } } + +export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServer { + public constructor( + private readonly syntaxServer: ITypeScriptServer, + private readonly semanticServer: ITypeScriptServer, + ) { + super(); + + this._register(syntaxServer.onEvent(e => this._onEvent.fire(e))); + this._register(semanticServer.onEvent(e => this._onEvent.fire(e))); + + this._register(semanticServer.onExit(e => this._onExit.fire(e))); + this._register(semanticServer.onError(e => this._onError.fire(e))); + } + + private readonly _onEvent = this._register(new vscode.EventEmitter()); + public readonly onEvent = this._onEvent.event; + + private readonly _onExit = this._register(new vscode.EventEmitter()); + public readonly onExit = this._onExit.event; + + private readonly _onError = this._register(new vscode.EventEmitter()); + public readonly onError = this._onError.event; + + public get onReaderError() { return this.semanticServer.onReaderError; } + + public get tsServerLogFile() { return this.semanticServer.tsServerLogFile; } + + public kill(): void { + this.syntaxServer.kill(); + this.semanticServer.kill(); + } + + private static readonly syntaxCommands = new Set(['navtree', 'getOutliningSpans', 'jsxClosingTag', 'selectionRange']); + private static readonly sharedCommands = new Set(['change', 'close', 'open', 'updateOpen', 'configure', 'configurePlugin']); + + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + + if (SyntaxRoutingTsServer.syntaxCommands.has(command)) { + return this.syntaxServer.executeImpl(command, args, executeInfo); + } else if (SyntaxRoutingTsServer.sharedCommands.has(command)) { + this.syntaxServer.executeImpl(command, args, executeInfo); + return this.semanticServer.executeImpl(command, args, executeInfo); + } else { + return this.semanticServer.executeImpl(command, args, executeInfo); + } + } +} diff --git a/extensions/typescript-language-features/src/tsServer/spanwer.ts b/extensions/typescript-language-features/src/tsServer/spanwer.ts index 7f6589c5635..1c78d71c87e 100644 --- a/extensions/typescript-language-features/src/tsServer/spanwer.ts +++ b/extensions/typescript-language-features/src/tsServer/spanwer.ts @@ -18,7 +18,7 @@ import { PluginManager } from '../utils/plugins'; import TelemetryReporter from '../utils/telemetry'; import Tracer from '../utils/tracer'; import { TypeScriptVersion, TypeScriptVersionProvider } from '../utils/versionProvider'; -import { ITypeScriptServer, TsServerProcess, ProcessBasedTsServer, PipeRequestCanceller } from './server'; +import { ITypeScriptServer, PipeRequestCanceller, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerProcess } from './server'; export class TypeScriptServerSpawner { public constructor( @@ -34,6 +34,30 @@ export class TypeScriptServerSpawner { version: TypeScriptVersion, configuration: TypeScriptServiceConfiguration, pluginManager: PluginManager + ): ITypeScriptServer { + if (this.shouldUserSeparateSyntaxServer(version)) { + const syntaxServer = this.spawnProcessBasedTsServer('syntax', version, configuration, pluginManager, ['--syntaxOnly', '--disableAutomaticTypingAcquisition']); + const semanticServer = this.spawnProcessBasedTsServer('semantic', version, configuration, pluginManager, []); + return new SyntaxRoutingTsServer(syntaxServer, semanticServer); + } + + return this.spawnProcessBasedTsServer('main', version, configuration, pluginManager, []); + } + + private shouldUserSeparateSyntaxServer(version: TypeScriptVersion): boolean { + if (!version.version || version.version.lt(API.v340)) { + return false; + } + return vscode.workspace.getConfiguration('typescript') + .get('experimental.useSeparateSyntaxServer', false); + } + + private spawnProcessBasedTsServer( + serverId: string, + version: TypeScriptVersion, + configuration: TypeScriptServiceConfiguration, + pluginManager: PluginManager, + extraForkArgs: readonly string[], ): ITypeScriptServer { const apiVersion = version.version || API.defaultVersion; @@ -41,20 +65,21 @@ export class TypeScriptServerSpawner { if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { if (tsServerLogFile) { - this._logger.info(`TSServer log file: ${tsServerLogFile}`); + this._logger.info(`<${serverId}> Log file: ${tsServerLogFile}`); } else { - this._logger.error('Could not create TSServer log directory'); + this._logger.error(`<${serverId}> Could not create log directory`); } } - this._logger.info('Forking TSServer'); - const childProcess = electron.fork(version.tsServerPath, args, this.getForkOptions()); - this._logger.info('Started TSServer'); + this._logger.info(`<${serverId}> Forking...`); + const childProcess = electron.fork(version.tsServerPath, [...args, ...extraForkArgs], this.getForkOptions()); + this._logger.info(`<${serverId}> Starting...`); return new ProcessBasedTsServer( + serverId, new ChildServerProcess(childProcess), tsServerLogFile, - new PipeRequestCanceller(cancellationPipeName, this._tracer), + new PipeRequestCanceller(serverId, cancellationPipeName, this._tracer), version, this._telemetryReporter, this._tracer); diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 1156b79d268..537cb2a0e2e 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -26,7 +26,7 @@ export namespace ServerResponse { export type Response = T | Cancelled | typeof NoContent; } -export interface TypeScriptRequestTypes { +interface StandardTsServerRequests { 'applyCodeActionCommand': [Proto.ApplyCodeActionCommandRequestArgs, Proto.ApplyCodeActionCommandResponse]; 'completionEntryDetails': [Proto.CompletionDetailsRequestArgs, Proto.CompletionDetailsResponse]; 'completionInfo': [Proto.CompletionsRequestArgs, Proto.CompletionInfoResponse]; @@ -59,6 +59,22 @@ export interface TypeScriptRequestTypes { 'typeDefinition': [Proto.FileLocationRequestArgs, Proto.TypeDefinitionResponse]; } +interface NoResponseTsServerRequests { + 'open': [Proto.OpenRequestArgs, null]; + 'close': [Proto.FileRequestArgs]; + 'change': [Proto.ChangeRequestArgs, null]; + 'updateOpen': [Proto.UpdateOpenRequestArgs, null]; + 'compilerOptionsForInferredProjects': [Proto.SetCompilerOptionsForInferredProjectsArgs, null]; + 'reloadProjects': [null, null]; + 'configurePlugin': [Proto.ConfigurePluginRequest, Proto.ConfigurePluginResponse]; +} + +interface AsyncTsServerRequests { + 'geterr': [Proto.GeterrRequestArgs, Proto.Response]; +} + +export type TypeScriptRequests = StandardTsServerRequests & NoResponseTsServerRequests & AsyncTsServerRequests; + export interface ITypeScriptServiceClient { /** * Convert a resource (VS Code) to a normalized path (TypeScript). @@ -100,19 +116,17 @@ export interface ITypeScriptServiceClient { readonly logger: Logger; readonly bufferSyncSupport: BufferSyncSupport; - execute( + execute( command: K, - args: TypeScriptRequestTypes[K][0], + args: StandardTsServerRequests[K][0], token: vscode.CancellationToken, lowPriority?: boolean - ): Promise>; - - executeWithoutWaitingForResponse(command: 'open', args: Proto.OpenRequestArgs): void; - executeWithoutWaitingForResponse(command: 'close', args: Proto.FileRequestArgs): void; - executeWithoutWaitingForResponse(command: 'change', args: Proto.ChangeRequestArgs): void; - executeWithoutWaitingForResponse(command: 'updateOpen', args: Proto.UpdateOpenRequestArgs): void; - executeWithoutWaitingForResponse(command: 'compilerOptionsForInferredProjects', args: Proto.SetCompilerOptionsForInferredProjectsArgs): void; - executeWithoutWaitingForResponse(command: 'reloadProjects', args: null): void; + ): Promise>; + + executeWithoutWaitingForResponse( + command: K, + args: NoResponseTsServerRequests[K][0] + ): void; executeAsync(command: 'geterr', args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise>; diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index bccddbf16f9..07de35b4ba3 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -11,7 +11,7 @@ import BufferSyncSupport from './features/bufferSyncSupport'; import { DiagnosticKind, DiagnosticsManager } from './features/diagnostics'; import * as Proto from './protocol'; import { ITypeScriptServer } from './tsServer/server'; -import { ITypeScriptServiceClient, ServerResponse } from './typescriptService'; +import { ITypeScriptServiceClient, ServerResponse, TypeScriptRequests } from './typescriptService'; import API from './utils/api'; import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'; import { Disposable } from './utils/dispose'; @@ -607,7 +607,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType return undefined; } - public execute(command: string, args: any, token: vscode.CancellationToken, lowPriority?: boolean): Promise> { + public execute(command: keyof TypeScriptRequests, args: any, token: vscode.CancellationToken, lowPriority?: boolean): Promise> { return this.executeImpl(command, args, { isAsync: false, token, @@ -616,7 +616,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - public executeWithoutWaitingForResponse(command: string, args: any): void { + public executeWithoutWaitingForResponse(command: keyof TypeScriptRequests, args: any): void { this.executeImpl(command, args, { isAsync: false, token: undefined, @@ -624,7 +624,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - public executeAsync(command: string, args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise> { + public executeAsync(command: keyof TypeScriptRequests, args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise> { return this.executeImpl(command, args, { isAsync: true, token, @@ -632,9 +632,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { this.bufferSyncSupport.beforeCommand(command); const runningServerState = this.service(); return runningServerState.server.executeImpl(command, args, executeInfo); @@ -769,7 +769,6 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.logTelemetry(telemetryData.telemetryEventName, properties); } - private configurePlugin(pluginName: string, configuration: {}): any { if (this.apiVersion.gte(API.v314)) { this.executeWithoutWaitingForResponse('configurePlugin', { pluginName, configuration }); diff --git a/extensions/typescript-language-features/src/utils/tracer.ts b/extensions/typescript-language-features/src/utils/tracer.ts index c80254c79a0..f7ca0d674e3 100644 --- a/extensions/typescript-language-features/src/utils/tracer.ts +++ b/extensions/typescript-language-features/src/utils/tracer.ts @@ -50,7 +50,7 @@ export default class Tracer { return result; } - public traceRequest(request: Proto.Request, responseExpected: boolean, queueLength: number): void { + public traceRequest(serverId: string, request: Proto.Request, responseExpected: boolean, queueLength: number): void { if (this.trace === Trace.Off) { return; } @@ -58,10 +58,10 @@ export default class Tracer { if (this.trace === Trace.Verbose && request.arguments) { data = `Arguments: ${JSON.stringify(request.arguments, null, 4)}`; } - this.logTrace(`Sending request: ${request.command} (${request.seq}). Response expected: ${responseExpected ? 'yes' : 'no'}. Current queue length: ${queueLength}`, data); + this.logTrace(serverId, `Sending request: ${request.command} (${request.seq}). Response expected: ${responseExpected ? 'yes' : 'no'}. Current queue length: ${queueLength}`, data); } - public traceResponse(response: Proto.Response, startTime: number): void { + public traceResponse(serverId: string, response: Proto.Response, startTime: number): void { if (this.trace === Trace.Off) { return; } @@ -69,17 +69,17 @@ export default class Tracer { if (this.trace === Trace.Verbose && response.body) { data = `Result: ${JSON.stringify(response.body, null, 4)}`; } - this.logTrace(`Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}`, data); + this.logTrace(serverId, `Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}`, data); } - public traceRequestCompleted(command: string, request_seq: number, startTime: number): any { + public traceRequestCompleted(serverId: string, command: string, request_seq: number, startTime: number): any { if (this.trace === Trace.Off) { return; } - this.logTrace(`Async response received: ${command} (${request_seq}). Request took ${Date.now() - startTime} ms.`); + this.logTrace(serverId, `Async response received: ${command} (${request_seq}). Request took ${Date.now() - startTime} ms.`); } - public traceEvent(event: Proto.Event): void { + public traceEvent(serverId: string, event: Proto.Event): void { if (this.trace === Trace.Off) { return; } @@ -87,12 +87,12 @@ export default class Tracer { if (this.trace === Trace.Verbose && event.body) { data = `Data: ${JSON.stringify(event.body, null, 4)}`; } - this.logTrace(`Event received: ${event.event} (${event.seq}).`, data); + this.logTrace(serverId, `Event received: ${event.event} (${event.seq}).`, data); } - public logTrace(message: string, data?: any): void { + public logTrace(serverId: string, message: string, data?: any): void { if (this.trace !== Trace.Off) { - this.logger.logLevel('Trace', message, data); + this.logger.logLevel('Trace', `<${serverId}> ${message}`, data); } } } \ No newline at end of file -- GitLab