Skip to content

Commit c4e2864

Browse files
authored
Use LogOutputChannel (#1630)
* Use log channel * Polish trace output * Pipe stderr / stdout into the right log level. * Fix compile error
1 parent c02c91c commit c4e2864

4 files changed

Lines changed: 112 additions & 84 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ After cloning the repository, run `npm install` to install dependencies and `npm
4646
- support to control the parallelism of the dispatch requests and notification. This is a breaking change since it allows notification handlers to return a promise to control this.
4747
- make client browser implementation consistent with the node implementation in terms of arguments. This is a breaking change since it re-ordered parameter declarations.
4848
- Added a `CancellationToken` to the show document middleware to make it consistent with the other middleware. This is a breaking change since it added a required parameter.
49+
- Using `LogOutputChannel` for the client's output and trace channel instead of the standard VSCode `OutputChannel` type. This is a breaking change for clients that pass in their own log or trace channel via the `LanguageClientOptions`. Instead of using a normal `OutputChannel` you now need to pass in a `LogOutputChannel`.
4950

5051
## 3.17.5 Protocol, 9.0.1 Client and 9.0.1 Server
5152

client/src/common/client.ts

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
* ------------------------------------------------------------------------------------------ */
55
import {
6-
workspace as Workspace, window as Window, languages as Languages, version as VSCodeVersion, TextDocument, Disposable, OutputChannel,
6+
workspace as Workspace, window as Window, languages as Languages, LogLevel, version as VSCodeVersion, TextDocument, Disposable,
77
FileSystemWatcher as VFileSystemWatcher, DiagnosticCollection, Diagnostic as VDiagnostic, Uri, CancellationToken, WorkspaceEdit as VWorkspaceEdit,
88
MessageItem, WorkspaceFolder as VWorkspaceFolder, env as Env, TextDocumentShowOptions, CancellationError, CancellationTokenSource, FileCreateEvent,
99
FileRenameEvent, FileDeleteEvent, FileWillCreateEvent, FileWillRenameEvent, FileWillDeleteEvent, CompletionItemProvider, HoverProvider, SignatureHelpProvider,
1010
DefinitionProvider, ReferenceProvider, DocumentHighlightProvider, CodeActionProvider, DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider,
1111
OnTypeFormattingEditProvider, RenameProvider, DocumentSymbolProvider, DocumentLinkProvider, DeclarationProvider, ImplementationProvider,
1212
DocumentColorProvider, SelectionRangeProvider, TypeDefinitionProvider, CallHierarchyProvider, LinkedEditingRangeProvider, TypeHierarchyProvider, WorkspaceSymbolProvider,
1313
ProviderResult, TextEdit as VTextEdit, InlineCompletionItemProvider, EventEmitter, type TabChangeEvent, TabInputText, TabInputTextDiff, TabInputCustom,
14-
TabInputNotebook
15-
} from 'vscode';
14+
TabInputNotebook, type LogOutputChannel} from 'vscode';
1615

1716
import {
1817
RAL, Message, MessageSignature, Logger, ResponseError, RequestType0, RequestType, NotificationType0, NotificationType,
@@ -348,9 +347,9 @@ InlineCompletionMiddleware & TextDocumentContentMiddleware & GeneralMiddleware;
348347
export type LanguageClientOptions = {
349348
documentSelector?: DocumentSelector | string[];
350349
diagnosticCollectionName?: string;
351-
outputChannel?: OutputChannel;
350+
outputChannel?: LogOutputChannel;
352351
outputChannelName?: string;
353-
traceOutputChannel?: OutputChannel;
352+
traceOutputChannel?: LogOutputChannel;
354353
revealOutputChannelOn?: RevealOutputChannelOn;
355354
/**
356355
* The encoding use to read stdout and stderr. Defaults
@@ -642,9 +641,10 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
642641
private readonly _progressDisposables: Map<string | number, Disposable>;
643642

644643
private _initializeResult: InitializeResult | undefined;
645-
private _outputChannel: OutputChannel | undefined;
644+
private _outputChannel: LogOutputChannel | undefined;
646645
private _disposeOutputChannel: boolean;
647-
private _traceOutputChannel: OutputChannel | undefined;
646+
private _traceOutputChannel: LogOutputChannel | undefined;
647+
private _logLevel: LogLevel;
648648
private _capabilities!: ServerCapabilities & ResolvedTextDocumentSyncCapabilities;
649649

650650
private _diagnostics: DiagnosticCollection | undefined;
@@ -741,6 +741,7 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
741741
this._disposeOutputChannel = true;
742742
}
743743
this._traceOutputChannel = clientOptions.traceOutputChannel;
744+
this._logLevel = LogLevel.Info;
744745
this._diagnostics = undefined;
745746

746747
this._inFlightOpenNotifications = new Set();
@@ -756,9 +757,9 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
756757
this._tracer = {
757758
log: (messageOrDataObject: string | any, data?: string) => {
758759
if (Is.string(messageOrDataObject)) {
759-
this.logTrace(messageOrDataObject, data);
760+
this.trace(messageOrDataObject, data);
760761
} else {
761-
this.logObjectTrace(messageOrDataObject);
762+
this.traceObject(messageOrDataObject);
762763
}
763764
},
764765
};
@@ -817,18 +818,15 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
817818
return this._stateChangeEmitter.event;
818819
}
819820

820-
public get outputChannel(): OutputChannel {
821+
public get outputChannel(): LogOutputChannel {
821822
if (!this._outputChannel) {
822-
this._outputChannel = Window.createOutputChannel(this._clientOptions.outputChannelName ? this._clientOptions.outputChannelName : this._name);
823+
this._outputChannel = Window.createOutputChannel(this._clientOptions.outputChannelName ? this._clientOptions.outputChannelName : this._name, { log: true });
823824
}
824825
return this._outputChannel;
825826
}
826827

827-
public get traceOutputChannel(): OutputChannel {
828-
if (this._traceOutputChannel) {
829-
return this._traceOutputChannel;
830-
}
831-
return this.outputChannel;
828+
public get traceOutputChannel(): LogOutputChannel {
829+
return this._traceOutputChannel ? this._traceOutputChannel : this.outputChannel;
832830
}
833831

834832
public get diagnostics(): DiagnosticCollection | undefined {
@@ -1160,30 +1158,40 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
11601158
return data.toString();
11611159
}
11621160

1163-
public debug(message: string, data?: any, showNotification: boolean = true): void {
1164-
this.logOutputMessage(MessageType.Debug, RevealOutputChannelOn.Debug, 'Debug', message, data, showNotification);
1161+
public error(message: string, data?: any, showNotification: boolean | 'force' = true): void {
1162+
this.outputChannel.error(this.getLogMessage(message, data));
1163+
if (showNotification === 'force' || (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Error)) {
1164+
this.showNotificationMessage(MessageType.Error, message, data);
1165+
}
1166+
}
1167+
1168+
public warn(message: string, data?: any, showNotification: boolean = true): void {
1169+
this.outputChannel.warn(this.getLogMessage(message, data));
1170+
if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Warn) {
1171+
this.showNotificationMessage(MessageType.Warning, message, data);
1172+
}
11651173
}
11661174

11671175
public info(message: string, data?: any, showNotification: boolean = true): void {
1168-
this.logOutputMessage(MessageType.Info, RevealOutputChannelOn.Info, 'Info', message, data, showNotification);
1176+
this.outputChannel.info(this.getLogMessage(message, data));
1177+
if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Info) {
1178+
this.showNotificationMessage(MessageType.Info, message, data);
1179+
}
11691180
}
11701181

1171-
public warn(message: string, data?: any, showNotification: boolean = true): void {
1172-
this.logOutputMessage(MessageType.Warning, RevealOutputChannelOn.Warn, 'Warn', message, data, showNotification);
1182+
public debug(message: string, data?: any, showNotification: boolean = true): void {
1183+
this.outputChannel.debug(this.getLogMessage(message, data));
1184+
if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Debug) {
1185+
this.showNotificationMessage(MessageType.Debug, message, data);
1186+
}
11731187
}
11741188

1175-
public error(message: string, data?: any, showNotification: boolean | 'force' = true): void {
1176-
this.logOutputMessage(MessageType.Error, RevealOutputChannelOn.Error, 'Error', message, data, showNotification);
1189+
public trace(message: string, data?: any): void {
1190+
this.traceOutputChannel.trace(this.getLogMessage(message, data));
11771191
}
11781192

1179-
private logOutputMessage(type: MessageType, reveal: RevealOutputChannelOn, name: string, message: string, data: any | undefined, showNotification: boolean | 'force'): void {
1180-
this.outputChannel.appendLine(`[${name.padEnd(5)} - ${(new Date().toLocaleTimeString())}] ${message}`);
1181-
if (data !== null && data !== undefined) {
1182-
this.outputChannel.appendLine(this.data2String(data));
1183-
}
1184-
if (showNotification === 'force' || (showNotification && this._clientOptions.revealOutputChannelOn <= reveal)) {
1185-
this.showNotificationMessage(type, message, data);
1186-
}
1193+
private traceObject(data: any): void {
1194+
this.traceOutputChannel.trace(JSON.stringify(data));
11871195
}
11881196

11891197
private showNotificationMessage(type: MessageType, message?: string, data? : any ) {
@@ -1203,22 +1211,8 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
12031211
});
12041212
}
12051213

1206-
private logTrace(message: string, data?: any): void {
1207-
this.traceOutputChannel.appendLine(`[Trace - ${(new Date().toLocaleTimeString())}] ${message}`);
1208-
if (data) {
1209-
this.traceOutputChannel.appendLine(this.data2String(data));
1210-
}
1211-
}
1212-
1213-
private logObjectTrace(data: any): void {
1214-
if (data.isLSPMessage && data.type) {
1215-
this.traceOutputChannel.append(`[LSP - ${(new Date().toLocaleTimeString())}] `);
1216-
} else {
1217-
this.traceOutputChannel.append(`[Trace - ${(new Date().toLocaleTimeString())}] `);
1218-
}
1219-
if (data) {
1220-
this.traceOutputChannel.appendLine(`${JSON.stringify(data)}`);
1221-
}
1214+
private getLogMessage(message: string, data?: any | undefined): string {
1215+
return data !== null && data !== undefined ? `${message}\n${this.data2String(data)}` : message;
12221216
}
12231217

12241218
public needsStart(): boolean {
@@ -1486,6 +1480,7 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
14861480
await connection.sendNotification(InitializedNotification.type, {});
14871481

14881482
this.hookFileEvents(connection);
1483+
this.hookLogLevelChanged(connection);
14891484
this.hookConfigurationChanged(connection);
14901485
this.initializeFeatures(connection);
14911486

@@ -1838,17 +1833,29 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
18381833
}));
18391834
}
18401835

1836+
private hookLogLevelChanged(connection: Connection): void {
1837+
this._listeners.push(this.traceOutputChannel.onDidChangeLogLevel((level) => {
1838+
this._logLevel = level;
1839+
this.refreshTrace(connection, true);
1840+
}));
1841+
}
1842+
18411843
private refreshTrace(connection: Connection, sendNotification: boolean = false): void {
18421844
const config = Workspace.getConfiguration(this._id);
1843-
let trace: Trace = Trace.Off;
1845+
let trace: Trace = this._logLevel !== LogLevel.Trace ? Trace.Off : Trace.Messages;
18441846
let traceFormat: TraceFormat = TraceFormat.Text;
1845-
if (config) {
1846-
const traceConfig = config.get('trace.server', 'off');
1847-
1847+
if (config && trace !== Trace.Off) {
1848+
const traceConfig = config.get('trace.server', 'messages');
18481849
if (typeof traceConfig === 'string') {
18491850
trace = Trace.fromString(traceConfig);
1851+
if (trace === Trace.Off) {
1852+
trace = Trace.Messages;
1853+
}
18501854
} else {
1851-
trace = Trace.fromString(config.get('trace.server.verbosity', 'off'));
1855+
trace = Trace.fromString(config.get('trace.server.verbosity', 'messages'));
1856+
if (trace === Trace.Off) {
1857+
trace = Trace.Messages;
1858+
}
18521859
traceFormat = TraceFormat.fromString(config.get('trace.server.format', 'text'));
18531860
}
18541861
}

0 commit comments

Comments
 (0)