From 631cbd128039a847a3400a9e8d8e13ce9991fe24 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 22 Jun 2018 02:35:22 -0700 Subject: [PATCH 1/6] Introduce Traceformat to allow JSON format log --- client/src/client.ts | 39 +++++++-- jsonrpc/src/main.ts | 182 ++++++++++++++++++++++++++++------------ jsonrpc/src/messages.ts | 17 ++++ protocol/src/main.ts | 6 +- 4 files changed, 183 insertions(+), 61 deletions(-) diff --git a/client/src/client.ts b/client/src/client.ts index fcf55a91e..528982b99 100644 --- a/client/src/client.ts +++ b/client/src/client.ts @@ -22,7 +22,7 @@ import { RequestType, RequestType0, RequestHandler, RequestHandler0, GenericRequestHandler, NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, - MessageReader, MessageWriter, Trace, Tracer, Event, Emitter, + MessageReader, MessageWriter, Trace, TraceFormat, Tracer, Event, Emitter, createProtocolConnection, ClientCapabilities, WorkspaceEdit, RegistrationRequest, RegistrationParams, UnregistrationRequest, UnregistrationParams, TextDocumentRegistrationOptions, @@ -100,7 +100,7 @@ interface IConnection { onNotification(method: string, handler: GenericNotificationHandler): void; onNotification(method: string | RPCMessageType, handler: GenericNotificationHandler): void; - trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, format: TraceFormat, tracer: Tracer, sendNotification?: boolean): void; initialize(params: InitializeParams): Thenable; shutdown(): Thenable; @@ -161,7 +161,7 @@ function createConnection(input: any, output: any, errorHandler: ConnectionError sendNotification: (type: string | RPCMessageType, params?: any): void => connection.sendNotification(Is.string(type) ? type : type.method, params), onNotification: (type: string | RPCMessageType, handler: GenericNotificationHandler): void => connection.onNotification(Is.string(type) ? type : type.method, handler), - trace: (value: Trace, tracer: Tracer, sendNotification: boolean = false): void => connection.trace(value, tracer, sendNotification), + trace: (value: Trace, format: TraceFormat, tracer: Tracer, sendNotification: boolean = false): void => connection.trace(value, format, tracer, sendNotification), initialize: (params: InitializeParams) => connection.sendRequest(InitializeRequest.type, params), shutdown: () => connection.sendRequest(ShutdownRequest.type, undefined), @@ -2249,6 +2249,7 @@ export abstract class BaseLanguageClient { private _stateChangeEmitter: Emitter; private _trace: Trace; + private _traceFormat: TraceFormat; private _tracer: Tracer; private _c2p: c2p.Converter; @@ -2302,6 +2303,9 @@ export abstract class BaseLanguageClient { this._tracer = { log: (message: string, data?: string) => { this.logTrace(message, data); + }, + logLSP: (message: string) => { + this.logLSPTrace(message); } }; this._c2p = c2p.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.code2Protocol : undefined); @@ -2438,7 +2442,17 @@ export abstract class BaseLanguageClient { this._trace = value; this.onReady().then(() => { this.resolveConnection().then((connection) => { - connection.trace(value, this._tracer); + connection.trace(value, this._traceFormat, this._tracer); + }) + }, () => { + }); + } + + public set traceFormat(value: TraceFormat) { + this._traceFormat = value; + this.onReady().then(() => { + this.resolveConnection().then((connection) => { + connection.trace(this._trace, value, this._tracer); }) }, () => { }); @@ -2498,6 +2512,10 @@ export abstract class BaseLanguageClient { } } + private logLSPTrace(message: string): void { + this.outputChannel.appendLine(`[LSP - ${(new Date().toLocaleTimeString())}] ${message}`); + } + public needsStart(): boolean { return this.state === ClientState.Initial || this.state === ClientState.Stopping || this.state === ClientState.Stopped; } @@ -2846,11 +2864,20 @@ export abstract class BaseLanguageClient { private refreshTrace(connection: IConnection, sendNotification: boolean = false): void { let config = Workspace.getConfiguration(this._id); let trace: Trace = Trace.Off; + let traceFormat: TraceFormat = TraceFormat.Text; if (config) { - trace = Trace.fromString(config.get('trace.server', 'off')); + const traceConfig = config.get('trace.server', 'off'); + + if (typeof traceConfig === 'string') { + trace = Trace.fromString(traceConfig); + } else { + trace = Trace.fromString(config.get('trace.server.verbosity', 'off')); + traceFormat = TraceFormat.fromString(config.get('trace.server.format', 'text')); + } } this._trace = trace; - connection.trace(this._trace, this._tracer, sendNotification); + this._traceFormat = traceFormat; + connection.trace(this._trace, this._traceFormat, this._tracer, sendNotification); } diff --git a/jsonrpc/src/main.ts b/jsonrpc/src/main.ts index 2ff4c298b..8210bf76b 100644 --- a/jsonrpc/src/main.ts +++ b/jsonrpc/src/main.ts @@ -15,7 +15,8 @@ import { ResponseMessage, isResponseMessage, ResponseError, ErrorCodes, NotificationMessage, isNotificationMessage, NotificationType, NotificationType0, NotificationType1, NotificationType2, NotificationType3, NotificationType4, - NotificationType5, NotificationType6, NotificationType7, NotificationType8, NotificationType9 + NotificationType5, NotificationType6, NotificationType7, NotificationType8, NotificationType9, + LSPMessageType } from './messages'; import { MessageReader, DataCallback, StreamMessageReader, IPCMessageReader, SocketMessageReader } from './messageReader'; @@ -205,6 +206,36 @@ export namespace Trace { } } +export enum TraceFormat { + Text, JSON +} + +export type TraceFormatValues = 'text' | 'json' +export namespace TraceFormat { + export function fromString(value: string): TraceFormat { + value = value.toLowerCase(); + switch (value) { + case 'text': + return TraceFormat.Text; + case 'json': + return TraceFormat.JSON; + default: + return TraceFormat.Text; + } + } + + export function toString(value: TraceFormat): TraceFormatValues { + switch (value) { + case TraceFormat.Text: + return 'text'; + case TraceFormat.JSON: + return 'json'; + default: + return 'text'; + } + } +} + export interface SetTraceParams { value: TraceValues; } @@ -224,6 +255,7 @@ export namespace LogTraceNotification { export interface Tracer { log(message: string, data?: string): void; + logLSP(message: string): void; } export enum ConnectionErrors { @@ -320,7 +352,7 @@ export interface MessageConnection { onNotification(method: string, handler: GenericNotificationHandler): void; onNotification(handler: StarNotificationHandler): void; - trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, traceFormat: TraceFormat, tracer: Tracer, sendNotification?: boolean): void; onError: Event<[Error, Message | undefined, number | undefined]>; onClose: Event; @@ -365,12 +397,13 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M let starNotificationHandler: StarNotificationHandler | undefined = undefined; let notificationHandlers: { [name: string]: NotificationHandlerElement | undefined } = Object.create(null); - let timer: NodeJS.Timer | undefined; + let timer: NodeJS.Timer | undefined; let messageQueue: MessageQueue = new LinkedMap(); let responsePromises: { [name: string]: ResponsePromise } = Object.create(null); let requestTokens: { [id: string]: CancellationTokenSource } = Object.create(null); let trace: Trace = Trace.Off; + let traceFormat: TraceFormat = TraceFormat.Text; let tracer: Tracer | undefined; let state: ConnectionState = ConnectionState.New; @@ -713,97 +746,141 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M if (trace === Trace.Off || !tracer) { return; } - let data: string | undefined = undefined; - if (trace === Trace.Verbose && message.params) { - data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + + if (traceFormat === TraceFormat.Text) { + let data: string | undefined = undefined; + if (trace === Trace.Verbose && message.params) { + data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + } + tracer.log(`Sending request '${message.method} - (${message.id})'.`, data); + } else { + logLSPMessage('send-request', message); } - tracer.log(`Sending request '${message.method} - (${message.id})'.`, data); } - function traceSendNotification(message: NotificationMessage): void { + function traceSendingNotification(message: NotificationMessage): void { if (trace === Trace.Off || !tracer) { return; } - let data: string | undefined = undefined; - if (trace === Trace.Verbose) { - if (message.params) { - data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; - } else { - data = 'No parameters provided.\n\n'; + + if (traceFormat === TraceFormat.Text) { + let data: string | undefined = undefined; + if (trace === Trace.Verbose) { + if (message.params) { + data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + } else { + data = 'No parameters provided.\n\n'; + } } + tracer.log(`Sending notification '${message.method}'.`, data); + } else { + logLSPMessage('send-notification', message); } - tracer.log(`Sending notification '${message.method}'.`, data); } function traceSendingResponse(message: ResponseMessage, method: string, startTime: number): void { if (trace === Trace.Off || !tracer) { return; } - let data: string | undefined = undefined; - if (trace === Trace.Verbose) { - if (message.error && message.error.data) { - data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`; - } else { - if (message.result) { - data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`; - } else if (message.error === void 0) { - data = 'No result returned.\n\n'; + + if (traceFormat === TraceFormat.Text) { + let data: string | undefined = undefined; + if (trace === Trace.Verbose) { + if (message.error && message.error.data) { + data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`; + } else { + if (message.result) { + data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`; + } else if (message.error === void 0) { + data = 'No result returned.\n\n'; + } } } + tracer.log(`Sending response '${method} - (${message.id})'. Processing request took ${Date.now() - startTime}ms`, data) + } else { + logLSPMessage('send-response', message); } - tracer.log(`Sending response '${method} - (${message.id})'. Processing request took ${Date.now() - startTime}ms`, data) } function traceReceivedRequest(message: RequestMessage): void { if (trace === Trace.Off || !tracer) { return; } - let data: string | undefined = undefined; - if (trace === Trace.Verbose && message.params) { - data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + + if (traceFormat === TraceFormat.Text) { + let data: string | undefined = undefined; + if (trace === Trace.Verbose && message.params) { + data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + } + tracer.log(`Received request '${message.method} - (${message.id})'.`, data); + } else { + logLSPMessage('receive-request', message); } - tracer.log(`Received request '${message.method} - (${message.id})'.`, data); } function traceReceivedNotification(message: NotificationMessage): void { if (trace === Trace.Off || !tracer || message.method === LogTraceNotification.type.method) { return; } - let data: string | undefined = undefined; - if (trace === Trace.Verbose) { - if (message.params) { - data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; - } else { - data = 'No parameters provided.\n\n'; + + if (traceFormat === TraceFormat.Text) { + let data: string | undefined = undefined; + if (trace === Trace.Verbose) { + if (message.params) { + data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + } else { + data = 'No parameters provided.\n\n'; + } } + tracer.log(`Received notification '${message.method}'.`, data); + } else { + logLSPMessage('receive-notification', message); } - tracer.log(`Received notification '${message.method}'.`, data); } function traceReceivedResponse(message: ResponseMessage, responsePromise: ResponsePromise): void { if (trace === Trace.Off || !tracer) { return; } - let data: string | undefined = undefined; - if (trace === Trace.Verbose) { - if (message.error && message.error.data) { - data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`; - } else { - if (message.result) { - data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`; - } else if (message.error === void 0) { - data = 'No result returned.\n\n'; + + if (traceFormat === TraceFormat.Text) { + let data: string | undefined = undefined; + if (trace === Trace.Verbose) { + if (message.error && message.error.data) { + data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`; + } else { + if (message.result) { + data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`; + } else if (message.error === void 0) { + data = 'No result returned.\n\n'; + } } } - } - if (responsePromise) { - let error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : ''; - tracer.log(`Received response '${responsePromise.method} - (${message.id})' in ${Date.now() - responsePromise.timerStart}ms.${error}`, data); + if (responsePromise) { + let error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : ''; + tracer.log(`Received response '${responsePromise.method} - (${message.id})' in ${Date.now() - responsePromise.timerStart}ms.${error}`, data); + } else { + tracer.log(`Received response ${message.id} without active response promise.`, data); + } } else { - tracer.log(`Received response ${message.id} without active response promise.`, data); + logLSPMessage('receive-response', message); } } + function logLSPMessage(type: LSPMessageType, message: RequestMessage | ResponseMessage | NotificationMessage): void { + if (!tracer || trace === Trace.Off) { + return; + } + + const lspMessage = { + type, + message, + timestamp: Date.now() + } + + tracer.logLSP(JSON.stringify(lspMessage)); + } + function throwIfClosedOrDisposed() { if (isClosed()) { throw new ConnectionError(ConnectionErrors.Closed, 'Connection is closed.'); @@ -886,7 +963,7 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M method: method, params: messageParams } - traceSendNotification(notificationMessage); + traceSendingNotification(notificationMessage); messageWriter.write(notificationMessage); }, onNotification: (type: string | MessageType | StarNotificationHandler, handler?: GenericNotificationHandler): void => { @@ -985,8 +1062,9 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M } } }, - trace: (_value: Trace, _tracer: Tracer, sendNotification: boolean = false) => { + trace: (_value: Trace, _traceFormat: TraceFormat, _tracer: Tracer, sendNotification: boolean = false) => { trace = _value; + traceFormat = _traceFormat; if (trace === Trace.Off) { tracer = undefined; } else { diff --git a/jsonrpc/src/messages.ts b/jsonrpc/src/messages.ts index e79ee5ab0..5ed8cc3bb 100644 --- a/jsonrpc/src/messages.ts +++ b/jsonrpc/src/messages.ts @@ -121,6 +121,23 @@ export interface ResponseMessage extends Message { error?: ResponseErrorLiteral; } +/** + * A LSP Log Entry. + */ +export type LSPMessageType = + | 'send-request' + | 'receive-request' + | 'send-response' + | 'receive-response' + | 'send-notification' + | 'receive-notification'; + +export interface LSPLogMessage { + type: LSPMessageType; + message: RequestMessage | ResponseMessage | NotificationMessage; + timestamp: number; +} + /** * An interface to type messages. */ diff --git a/protocol/src/main.ts b/protocol/src/main.ts index 637c4102c..c64c5be19 100644 --- a/protocol/src/main.ts +++ b/protocol/src/main.ts @@ -6,7 +6,7 @@ import { ErrorCodes, ResponseError, CancellationToken, CancellationTokenSource, - Disposable, Event, Emitter, Trace, SetTraceNotification, LogTraceNotification, + Disposable, Event, Emitter, Trace, TraceFormat, SetTraceNotification, LogTraceNotification, Message, NotificationMessage, RequestMessage, MessageType as RPCMessageType, RequestType, RequestType0, RequestHandler, RequestHandler0, GenericRequestHandler, StarRequestHandler, NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, StarNotificationHandler, @@ -19,7 +19,7 @@ import { export { ErrorCodes, ResponseError, CancellationToken, CancellationTokenSource, - Disposable, Event, Emitter, Trace, SetTraceNotification, LogTraceNotification, + Disposable, Event, Emitter, Trace, TraceFormat, SetTraceNotification, LogTraceNotification, Message, NotificationMessage, RequestMessage, RPCMessageType, RequestType, RequestType0, RequestHandler, RequestHandler0, GenericRequestHandler, StarRequestHandler, NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, StarNotificationHandler, @@ -157,7 +157,7 @@ export interface ProtocolConnection { /** * Enables tracing mode for the connection. */ - trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, traceFormat: TraceFormat, tracer: Tracer, sendNotification?: boolean): void; /** * An event emitter firing when an error occurs on the connection. From fa968d78f3ce1d382ef2bddb7033cba23eb4b533 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 23 Aug 2018 15:18:10 -0700 Subject: [PATCH 2/6] Address feedback --- jsonrpc/src/main.ts | 27 ++++++--------------------- jsonrpc/src/messages.ts | 12 ++++++------ 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/jsonrpc/src/main.ts b/jsonrpc/src/main.ts index 8210bf76b..5f1887792 100644 --- a/jsonrpc/src/main.ts +++ b/jsonrpc/src/main.ts @@ -207,31 +207,16 @@ export namespace Trace { } export enum TraceFormat { - Text, JSON + Text = 'text', + JSON = 'json' } - -export type TraceFormatValues = 'text' | 'json' export namespace TraceFormat { export function fromString(value: string): TraceFormat { value = value.toLowerCase(); - switch (value) { - case 'text': - return TraceFormat.Text; - case 'json': - return TraceFormat.JSON; - default: - return TraceFormat.Text; - } - } - - export function toString(value: TraceFormat): TraceFormatValues { - switch (value) { - case TraceFormat.Text: - return 'text'; - case TraceFormat.JSON: - return 'json'; - default: - return 'text'; + if (value === 'json') { + return TraceFormat.JSON; + } else { + return TraceFormat.Text; } } } diff --git a/jsonrpc/src/messages.ts b/jsonrpc/src/messages.ts index 5ed8cc3bb..54d75c2b4 100644 --- a/jsonrpc/src/messages.ts +++ b/jsonrpc/src/messages.ts @@ -125,12 +125,12 @@ export interface ResponseMessage extends Message { * A LSP Log Entry. */ export type LSPMessageType = - | 'send-request' - | 'receive-request' - | 'send-response' - | 'receive-response' - | 'send-notification' - | 'receive-notification'; + | 'send-request' + | 'receive-request' + | 'send-response' + | 'receive-response' + | 'send-notification' + | 'receive-notification'; export interface LSPLogMessage { type: LSPMessageType; From 299f72574e5c8d5f61fe3ea5facf4d5a5cb22bb1 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 23 Aug 2018 23:46:07 -0700 Subject: [PATCH 3/6] Don't break existing API --- client/src/client.ts | 44 ++++++++++++++++++++++---------------------- jsonrpc/src/main.ts | 13 ++++++++----- protocol/src/main.ts | 3 ++- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/client/src/client.ts b/client/src/client.ts index 528982b99..a0bafa7a5 100644 --- a/client/src/client.ts +++ b/client/src/client.ts @@ -100,7 +100,7 @@ interface IConnection { onNotification(method: string, handler: GenericNotificationHandler): void; onNotification(method: string | RPCMessageType, handler: GenericNotificationHandler): void; - trace(value: Trace, format: TraceFormat, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean, traceFormat?: TraceFormat): void; initialize(params: InitializeParams): Thenable; shutdown(): Thenable; @@ -161,7 +161,7 @@ function createConnection(input: any, output: any, errorHandler: ConnectionError sendNotification: (type: string | RPCMessageType, params?: any): void => connection.sendNotification(Is.string(type) ? type : type.method, params), onNotification: (type: string | RPCMessageType, handler: GenericNotificationHandler): void => connection.onNotification(Is.string(type) ? type : type.method, handler), - trace: (value: Trace, format: TraceFormat, tracer: Tracer, sendNotification: boolean = false): void => connection.trace(value, format, tracer, sendNotification), + trace: (value: Trace, tracer: Tracer, sendNotification: boolean = false, traceFormat: TraceFormat = TraceFormat.Text): void => connection.trace(value, tracer, sendNotification, traceFormat), initialize: (params: InitializeParams) => connection.sendRequest(InitializeRequest.type, params), shutdown: () => connection.sendRequest(ShutdownRequest.type, undefined), @@ -2249,7 +2249,7 @@ export abstract class BaseLanguageClient { private _stateChangeEmitter: Emitter; private _trace: Trace; - private _traceFormat: TraceFormat; + private _traceFormat: TraceFormat = TraceFormat.Text; private _tracer: Tracer; private _c2p: c2p.Converter; @@ -2301,12 +2301,15 @@ export abstract class BaseLanguageClient { this._telemetryEmitter = new Emitter(); this._stateChangeEmitter = new Emitter(); this._tracer = { - log: (message: string, data?: string) => { - this.logTrace(message, data); + log: (...params: any[]) => { + if (typeof params[0] === 'string') { + const [message, data] = params; + this.logTrace(message, data); + } else { + const [data] = params; + this.logObjectTrace(data); + } }, - logLSP: (message: string) => { - this.logLSPTrace(message); - } }; this._c2p = c2p.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.code2Protocol : undefined); this._p2c = p2c.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.protocol2Code : undefined); @@ -2442,17 +2445,7 @@ export abstract class BaseLanguageClient { this._trace = value; this.onReady().then(() => { this.resolveConnection().then((connection) => { - connection.trace(value, this._traceFormat, this._tracer); - }) - }, () => { - }); - } - - public set traceFormat(value: TraceFormat) { - this._traceFormat = value; - this.onReady().then(() => { - this.resolveConnection().then((connection) => { - connection.trace(this._trace, value, this._tracer); + connection.trace(this._trace, this._tracer, false, this._traceFormat); }) }, () => { }); @@ -2512,8 +2505,15 @@ export abstract class BaseLanguageClient { } } - private logLSPTrace(message: string): void { - this.outputChannel.appendLine(`[LSP - ${(new Date().toLocaleTimeString())}] ${message}`); + private logObjectTrace(data: any): void { + if (data.isLSPMessage && data.type) { + this.outputChannel.append(`[LSP - ${(new Date().toLocaleTimeString())}] `); + } else { + this.outputChannel.append(`[Trace - ${(new Date().toLocaleTimeString())}] `); + } + if (data) { + this.outputChannel.appendLine(`${JSON.stringify(data)}`); + } } public needsStart(): boolean { @@ -2877,7 +2877,7 @@ export abstract class BaseLanguageClient { } this._trace = trace; this._traceFormat = traceFormat; - connection.trace(this._trace, this._traceFormat, this._tracer, sendNotification); + connection.trace(this._trace, this._tracer, sendNotification, this._traceFormat); } diff --git a/jsonrpc/src/main.ts b/jsonrpc/src/main.ts index 5f1887792..e780efbfa 100644 --- a/jsonrpc/src/main.ts +++ b/jsonrpc/src/main.ts @@ -239,8 +239,8 @@ export namespace LogTraceNotification { } export interface Tracer { + log(data: Object): void; log(message: string, data?: string): void; - logLSP(message: string): void; } export enum ConnectionErrors { @@ -337,7 +337,8 @@ export interface MessageConnection { onNotification(method: string, handler: GenericNotificationHandler): void; onNotification(handler: StarNotificationHandler): void; - trace(value: Trace, traceFormat: TraceFormat, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean, traceFormat?: TraceFormat): void; onError: Event<[Error, Message | undefined, number | undefined]>; onClose: Event; @@ -858,12 +859,13 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M } const lspMessage = { + isLSPMessage: true, type, message, timestamp: Date.now() } - tracer.logLSP(JSON.stringify(lspMessage)); + tracer.log(lspMessage); } function throwIfClosedOrDisposed() { @@ -1047,15 +1049,16 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M } } }, - trace: (_value: Trace, _traceFormat: TraceFormat, _tracer: Tracer, sendNotification: boolean = false) => { + trace: (_value: Trace, _tracer: Tracer, _sendNotification: boolean = false, _traceFormat: TraceFormat = TraceFormat.Text) => { trace = _value; + traceFormat = _traceFormat; if (trace === Trace.Off) { tracer = undefined; } else { tracer = _tracer; } - if (sendNotification && !isClosed() && !isDisposed()) { + if (_sendNotification && !isClosed() && !isDisposed()) { connection.sendNotification(SetTraceNotification.type, { value: Trace.toString(_value) }); } }, diff --git a/protocol/src/main.ts b/protocol/src/main.ts index c64c5be19..e0a28e133 100644 --- a/protocol/src/main.ts +++ b/protocol/src/main.ts @@ -157,7 +157,8 @@ export interface ProtocolConnection { /** * Enables tracing mode for the connection. */ - trace(value: Trace, traceFormat: TraceFormat, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean, traceFormat?: TraceFormat): void; /** * An event emitter firing when an error occurs on the connection. From 8e3a1c89ada26f2d583c29603183e3a070cd93d2 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 23 Aug 2018 23:48:37 -0700 Subject: [PATCH 4/6] Fix whitespace --- jsonrpc/src/messages.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jsonrpc/src/messages.ts b/jsonrpc/src/messages.ts index 54d75c2b4..7866169cc 100644 --- a/jsonrpc/src/messages.ts +++ b/jsonrpc/src/messages.ts @@ -133,9 +133,9 @@ export type LSPMessageType = | 'receive-notification'; export interface LSPLogMessage { - type: LSPMessageType; - message: RequestMessage | ResponseMessage | NotificationMessage; - timestamp: number; + type: LSPMessageType; + message: RequestMessage | ResponseMessage | NotificationMessage; + timestamp: number; } /** From 78cfde65dcb7c62bd6b241a7841a321fd908b764 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 24 Aug 2018 00:02:39 -0700 Subject: [PATCH 5/6] Minor type fix --- jsonrpc/src/main.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jsonrpc/src/main.ts b/jsonrpc/src/main.ts index e780efbfa..2d7ea5fa3 100644 --- a/jsonrpc/src/main.ts +++ b/jsonrpc/src/main.ts @@ -239,7 +239,7 @@ export namespace LogTraceNotification { } export interface Tracer { - log(data: Object): void; + log(data: any): void; log(message: string, data?: string): void; } @@ -1051,7 +1051,6 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M }, trace: (_value: Trace, _tracer: Tracer, _sendNotification: boolean = false, _traceFormat: TraceFormat = TraceFormat.Text) => { trace = _value; - traceFormat = _traceFormat; if (trace === Trace.Off) { tracer = undefined; From fa28e47d1a0243900831a8715379c5d847a1bbd3 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 24 Aug 2018 10:30:36 -0700 Subject: [PATCH 6/6] Add TraceOptions and address feedback --- client/src/client.ts | 40 +++++++++++++++++++++++++++++----------- jsonrpc/src/main.ts | 23 ++++++++++++++++++++--- protocol/src/main.ts | 10 +++++----- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/client/src/client.ts b/client/src/client.ts index a0bafa7a5..a9be568bc 100644 --- a/client/src/client.ts +++ b/client/src/client.ts @@ -22,7 +22,7 @@ import { RequestType, RequestType0, RequestHandler, RequestHandler0, GenericRequestHandler, NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, - MessageReader, MessageWriter, Trace, TraceFormat, Tracer, Event, Emitter, + MessageReader, MessageWriter, Trace, Tracer, TraceFormat, TraceOptions, Event, Emitter, createProtocolConnection, ClientCapabilities, WorkspaceEdit, RegistrationRequest, RegistrationParams, UnregistrationRequest, UnregistrationParams, TextDocumentRegistrationOptions, @@ -100,7 +100,8 @@ interface IConnection { onNotification(method: string, handler: GenericNotificationHandler): void; onNotification(method: string | RPCMessageType, handler: GenericNotificationHandler): void; - trace(value: Trace, tracer: Tracer, sendNotification?: boolean, traceFormat?: TraceFormat): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + trace(value: Trace, tracer: Tracer, traceOptions?: TraceOptions): void; initialize(params: InitializeParams): Thenable; shutdown(): Thenable; @@ -161,7 +162,20 @@ function createConnection(input: any, output: any, errorHandler: ConnectionError sendNotification: (type: string | RPCMessageType, params?: any): void => connection.sendNotification(Is.string(type) ? type : type.method, params), onNotification: (type: string | RPCMessageType, handler: GenericNotificationHandler): void => connection.onNotification(Is.string(type) ? type : type.method, handler), - trace: (value: Trace, tracer: Tracer, sendNotification: boolean = false, traceFormat: TraceFormat = TraceFormat.Text): void => connection.trace(value, tracer, sendNotification, traceFormat), + trace: (value: Trace, tracer: Tracer, sendNotificationOrTraceOptions?: boolean | TraceOptions): void => { + const defaultTraceOptions: TraceOptions = { + sendNotification: false, + traceFormat: TraceFormat.Text + }; + + if (sendNotificationOrTraceOptions === void 0) { + connection.trace(value, tracer, defaultTraceOptions); + } else if (Is.boolean(sendNotificationOrTraceOptions)) { + connection.trace(value, tracer, sendNotificationOrTraceOptions); + } else { + connection.trace(value, tracer, sendNotificationOrTraceOptions); + } + }, initialize: (params: InitializeParams) => connection.sendRequest(InitializeRequest.type, params), shutdown: () => connection.sendRequest(ShutdownRequest.type, undefined), @@ -2301,13 +2315,11 @@ export abstract class BaseLanguageClient { this._telemetryEmitter = new Emitter(); this._stateChangeEmitter = new Emitter(); this._tracer = { - log: (...params: any[]) => { - if (typeof params[0] === 'string') { - const [message, data] = params; - this.logTrace(message, data); + log: (messageOrDataObject: string | any, data?: string) => { + if (Is.string(messageOrDataObject)) { + this.logTrace(messageOrDataObject, data); } else { - const [data] = params; - this.logObjectTrace(data); + this.logObjectTrace(messageOrDataObject); } }, }; @@ -2445,7 +2457,10 @@ export abstract class BaseLanguageClient { this._trace = value; this.onReady().then(() => { this.resolveConnection().then((connection) => { - connection.trace(this._trace, this._tracer, false, this._traceFormat); + connection.trace(this._trace, this._tracer, { + sendNotification: false, + traceFormat: this._traceFormat + }); }) }, () => { }); @@ -2877,7 +2892,10 @@ export abstract class BaseLanguageClient { } this._trace = trace; this._traceFormat = traceFormat; - connection.trace(this._trace, this._tracer, sendNotification, this._traceFormat); + connection.trace(this._trace, this._tracer, { + sendNotification, + traceFormat: this._traceFormat + }); } diff --git a/jsonrpc/src/main.ts b/jsonrpc/src/main.ts index 2d7ea5fa3..1dcac9349 100644 --- a/jsonrpc/src/main.ts +++ b/jsonrpc/src/main.ts @@ -221,6 +221,11 @@ export namespace TraceFormat { } } +export interface TraceOptions { + sendNotification?: boolean; + traceFormat?: TraceFormat; +} + export interface SetTraceParams { value: TraceValues; } @@ -239,7 +244,7 @@ export namespace LogTraceNotification { } export interface Tracer { - log(data: any): void; + log(dataObject: any): void; log(message: string, data?: string): void; } @@ -338,7 +343,7 @@ export interface MessageConnection { onNotification(handler: StarNotificationHandler): void; trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; - trace(value: Trace, tracer: Tracer, sendNotification?: boolean, traceFormat?: TraceFormat): void; + trace(value: Trace, tracer: Tracer, traceOptions?: TraceOptions): void; onError: Event<[Error, Message | undefined, number | undefined]>; onClose: Event; @@ -1049,7 +1054,19 @@ function _createMessageConnection(messageReader: MessageReader, messageWriter: M } } }, - trace: (_value: Trace, _tracer: Tracer, _sendNotification: boolean = false, _traceFormat: TraceFormat = TraceFormat.Text) => { + trace: (_value: Trace, _tracer: Tracer, sendNotificationOrTraceOptions?: boolean | TraceOptions) => { + let _sendNotification: boolean = false; + let _traceFormat: TraceFormat = TraceFormat.Text; + + if (sendNotificationOrTraceOptions !== void 0) { + if (Is.boolean(sendNotificationOrTraceOptions)) { + _sendNotification = sendNotificationOrTraceOptions; + } else { + _sendNotification = sendNotificationOrTraceOptions.sendNotification || false; + _traceFormat = sendNotificationOrTraceOptions.traceFormat || TraceFormat.Text; + } + } + trace = _value; traceFormat = _traceFormat; if (trace === Trace.Off) { diff --git a/protocol/src/main.ts b/protocol/src/main.ts index e0a28e133..327880579 100644 --- a/protocol/src/main.ts +++ b/protocol/src/main.ts @@ -6,7 +6,7 @@ import { ErrorCodes, ResponseError, CancellationToken, CancellationTokenSource, - Disposable, Event, Emitter, Trace, TraceFormat, SetTraceNotification, LogTraceNotification, + Disposable, Event, Emitter, Trace, Tracer, TraceFormat, TraceOptions, SetTraceNotification, LogTraceNotification, Message, NotificationMessage, RequestMessage, MessageType as RPCMessageType, RequestType, RequestType0, RequestHandler, RequestHandler0, GenericRequestHandler, StarRequestHandler, NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, StarNotificationHandler, @@ -14,12 +14,12 @@ import { StreamMessageReader, StreamMessageWriter, IPCMessageReader, IPCMessageWriter, createClientPipeTransport, createServerPipeTransport, generateRandomPipeName, DataCallback, createClientSocketTransport, createServerSocketTransport, - createMessageConnection, Tracer + createMessageConnection } from 'vscode-jsonrpc'; export { ErrorCodes, ResponseError, CancellationToken, CancellationTokenSource, - Disposable, Event, Emitter, Trace, TraceFormat, SetTraceNotification, LogTraceNotification, + Disposable, Event, Emitter, Trace, Tracer, TraceFormat, TraceOptions, SetTraceNotification, LogTraceNotification, Message, NotificationMessage, RequestMessage, RPCMessageType, RequestType, RequestType0, RequestHandler, RequestHandler0, GenericRequestHandler, StarRequestHandler, NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, StarNotificationHandler, @@ -28,8 +28,8 @@ export { IPCMessageReader, IPCMessageWriter, createClientPipeTransport, createServerPipeTransport, generateRandomPipeName, DataCallback, createClientSocketTransport, createServerSocketTransport, - Tracer } + export * from 'vscode-languageserver-types'; export * from './protocol'; @@ -158,7 +158,7 @@ export interface ProtocolConnection { * Enables tracing mode for the connection. */ trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; - trace(value: Trace, tracer: Tracer, sendNotification?: boolean, traceFormat?: TraceFormat): void; + trace(value: Trace, tracer: Tracer, traceOptions?: TraceOptions): void; /** * An event emitter firing when an error occurs on the connection.