Skip to content

Commit cd8aea9

Browse files
JustinGroteandyleejordan
authored andcommitted
Rework multiple classes into a parser function injection
1 parent db3aefb commit cd8aea9

File tree

2 files changed

+55
-77
lines changed

2 files changed

+55
-77
lines changed

src/logging.ts

Lines changed: 52 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,16 @@ export class Logger implements ILogger {
140140
export class LanguageClientOutputChannelAdapter implements LogOutputChannel {
141141
private channel: LogOutputChannel;
142142

143-
constructor(public channelName: string) {
143+
/**
144+
* Creates an instance of the logging class.
145+
*
146+
* @param channelName - The name of the output channel.
147+
* @param parser - A function that parses a log message and returns a tuple containing the parsed message and its log level, or undefined if the log should be filtered.
148+
*/
149+
constructor(
150+
channelName: string,
151+
private parser: (message: string) => [string, LogLevel] | undefined = LanguageClientOutputChannelAdapter.omnisharpLspParser.bind(this)
152+
) {
144153
this.channel = window.createOutputChannel(channelName, {log: true});
145154
}
146155

@@ -149,41 +158,19 @@ export class LanguageClientOutputChannelAdapter implements LogOutputChannel {
149158
}
150159

151160
public append(message: string): void {
152-
const [parsedMessage, level] = this.parse(message);
153-
this.sendLogMessage(parsedMessage, level);
161+
const parseResult = this.parser(message);
162+
if (parseResult !== undefined) {this.sendLogMessage(...parseResult);}
154163
}
155164

156-
// We include the log level inline from PSES for VSCode because our LanguageClient doesn't support middleware for logMessages yet.
157-
// BUG:
158-
protected parse(message: string): [string, LogLevel] {
159-
const logLevelMatch = /^<(?<level>Trace|Debug|Info|Warning|Error)>(?<message>.+)/.exec(message);
160-
if (logLevelMatch) {
161-
const { level, message } = logLevelMatch.groups!;
162-
let logLevel: LogLevel;
163-
switch (level) {
164-
case "Trace":
165-
logLevel = LogLevel.Trace;
166-
break;
167-
case "Debug":
168-
logLevel = LogLevel.Debug;
169-
break;
170-
case "Info":
171-
logLevel = LogLevel.Info;
172-
break;
173-
case "Warning":
174-
logLevel = LogLevel.Warning;
175-
break;
176-
case "Error":
177-
logLevel = LogLevel.Error;
178-
break;
179-
default:
180-
logLevel = LogLevel.Info;
181-
break;
182-
}
183-
return [message, logLevel];
184-
} else {
185-
return [message, LogLevel.Info];
186-
}
165+
/** Converts from Omnisharp logs since middleware for LogMessage does not currently exist **/
166+
public static omnisharpLspParser(message: string): [string, LogLevel] {
167+
const logLevelMatch = /^\[(?<level>Trace|Debug|Info|Warn|Error) +- \d+:\d+:\d+ [AP]M\] (?<message>.+)/.exec(message);
168+
const logLevel: LogLevel = logLevelMatch?.groups?.level
169+
? LogLevel[logLevelMatch.groups.level as keyof typeof LogLevel]
170+
: LogLevel.Info;
171+
const logMessage = logLevelMatch?.groups?.message ?? message;
172+
173+
return [logMessage, logLevel];
187174
}
188175

189176
protected sendLogMessage(message: string, level: LogLevel): void {
@@ -257,49 +244,40 @@ export class LanguageClientOutputChannelAdapter implements LogOutputChannel {
257244
// #endregion
258245
}
259246

260-
/** Appends additional */
261-
export class PsesMergedOutputChannel extends LanguageClientOutputChannelAdapter {
262-
public override appendLine(message: string): void {
263-
this.append(message);
264-
}
265-
266-
public override append(message: string): void {
267-
const [parsedMessage, level] = this.parse(message);
268-
269-
// Append PSES prefix to log messages to differentiate them from Client messages
270-
this.sendLogMessage("[PSES] " + parsedMessage, level);
271-
}
247+
/** Special parsing for PowerShell Editor Services LSP messages since the LogLevel cannot be read due to vscode
248+
* LanguageClient Limitations (https://github.com/microsoft/vscode-languageserver-node/issues/1116)
249+
*/
250+
export function PsesParser(message: string): [string, LogLevel] {
251+
const logLevelMatch = /^<(?<level>Trace|Debug|Info|Warning|Error)>(?<message>.+)/.exec(message);
252+
const logLevel: LogLevel = logLevelMatch?.groups?.level
253+
? LogLevel[logLevelMatch.groups.level as keyof typeof LogLevel]
254+
: LogLevel.Info;
255+
const logMessage = logLevelMatch?.groups?.message ?? message;
256+
257+
return ["[PSES] " + logMessage, logLevel];
272258
}
273259

274-
/** Overrides the severity of some LSP traces to be more logical */
275-
export class LanguageClientTraceFormatter extends LanguageClientOutputChannelAdapter {
276-
public override appendLine(message: string): void {
277-
this.append(message);
260+
/** Lsp Trace Parser that does some additional parsing and formatting to make it look nicer */
261+
export function LspTraceParser(message: string): [string, LogLevel] {
262+
let [parsedMessage, level] = LanguageClientOutputChannelAdapter.omnisharpLspParser(message);
263+
if (parsedMessage.startsWith("Sending ")) {
264+
parsedMessage = parsedMessage.replace("Sending", "➡️");
265+
level = LogLevel.Debug;
266+
}
267+
if (parsedMessage.startsWith("Received ")) {
268+
parsedMessage = parsedMessage.replace("Received", "⬅️");
269+
level = LogLevel.Debug;
270+
}
271+
if (parsedMessage.startsWith("Params:")
272+
|| parsedMessage.startsWith("Result:")
273+
) {
274+
level = LogLevel.Trace;
278275
}
279276

280-
public override append(message: string): void {
281-
// eslint-disable-next-line prefer-const
282-
let [parsedMessage, level] = this.parse(message);
283-
284-
if (parsedMessage.startsWith("Sending ")) {
285-
parsedMessage = parsedMessage.replace("Sending", "▶️");
286-
level = LogLevel.Debug;
287-
}
288-
if (parsedMessage.startsWith("Received ")) {
289-
parsedMessage = parsedMessage.replace("Received", "◀️");
290-
level = LogLevel.Debug;
291-
}
292-
if (parsedMessage.startsWith("Params:")
293-
|| parsedMessage.startsWith("Result:")
294-
) {
295-
level = LogLevel.Trace;
296-
}
297-
298-
// These are PSES messages we don't really need to see so we drop these to trace
299-
if (parsedMessage.startsWith("◀️ notification 'window/logMessage'")) {
300-
level = LogLevel.Trace;
301-
}
302-
303-
this.sendLogMessage(parsedMessage.trimEnd(), level);
277+
// These are PSES messages we don't really need to see so we drop these to trace
278+
if (parsedMessage.startsWith("⬅️ notification 'window/logMessage'")) {
279+
level = LogLevel.Trace;
304280
}
281+
282+
return [parsedMessage.trimEnd(), level];
305283
}

src/session.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import path = require("path");
66
import vscode = require("vscode");
77
import TelemetryReporter, { TelemetryEventProperties, TelemetryEventMeasurements } from "@vscode/extension-telemetry";
88
import { Message, Trace } from "vscode-jsonrpc";
9-
import { ILogger, LanguageClientTraceFormatter, PsesMergedOutputChannel } from "./logging";
9+
import { ILogger, LanguageClientOutputChannelAdapter, LspTraceParser, PsesParser } from "./logging";
1010
import { PowerShellProcess } from "./process";
1111
import { Settings, changeSetting, getSettings, getEffectiveConfigurationTarget, validateCwdSetting } from "./settings";
1212
import utils = require("./utils");
@@ -688,9 +688,9 @@ export class SessionManager implements Middleware {
688688
},
689689
},
690690
middleware: this,
691-
traceOutputChannel: new LanguageClientTraceFormatter("PowerShell: Trace LSP"),
691+
traceOutputChannel: new LanguageClientOutputChannelAdapter("PowerShell: Trace LSP", LspTraceParser),
692692
// This is named the same as the Client log to merge the logs, but will be handled and disposed separately.
693-
outputChannel: new PsesMergedOutputChannel("PowerShell"),
693+
outputChannel: new LanguageClientOutputChannelAdapter("PowerShell", PsesParser),
694694
revealOutputChannelOn: RevealOutputChannelOn.Never
695695
};
696696

0 commit comments

Comments
 (0)