feat: use vscode log format for client logs

This change updates the log format to use the vscode log format instead
of the custom log format, by replacing the `OutputChannel` with a
`LogOutputChannel` and using the `debug`, `info`, `warn`, and `error`
methods on it. This has the following benefits:

- Each log level now has its own color and the timestamp is in a more
  standard format
- Inspect output (e.g. the log of the config object) is now colored
- Error stack traces are now shown in the output
- The log level is now controlled on the output tab by clicking the gear
  icon and selecting "Debug" or by passing the `--log` parameter to
  vscode. The `trace.extension` setting has been marked as deprecated.
This commit is contained in:
Josh McKinney 2024-07-27 21:43:35 -07:00
parent a46788318c
commit 45a881313a
No known key found for this signature in database
GPG key ID: 722287396A903BC5
6 changed files with 44 additions and 46 deletions

View file

@ -17,49 +17,44 @@ export type Env = {
[name: string]: string;
};
export const log = new (class {
private enabled = true;
private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client");
class Log {
private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client", {
log: true,
});
setEnabled(yes: boolean): void {
log.enabled = yes;
debug(...messages: [unknown, ...unknown[]]): void {
this.output.debug(this.stringify(messages));
}
// Hint: the type [T, ...T[]] means a non-empty array
debug(...msg: [unknown, ...unknown[]]): void {
if (!log.enabled) return;
log.write("DEBUG", ...msg);
info(...messages: [unknown, ...unknown[]]): void {
this.output.info(this.stringify(messages));
}
info(...msg: [unknown, ...unknown[]]): void {
log.write("INFO", ...msg);
warn(...messages: [unknown, ...unknown[]]): void {
this.output.warn(this.stringify(messages));
}
warn(...msg: [unknown, ...unknown[]]): void {
debugger;
log.write("WARN", ...msg);
error(...messages: [unknown, ...unknown[]]): void {
this.output.error(this.stringify(messages));
this.output.show(true);
}
error(...msg: [unknown, ...unknown[]]): void {
debugger;
log.write("ERROR", ...msg);
log.output.show(true);
private stringify(messages: unknown[]): string {
return messages
.map((message) => {
if (typeof message === "string") {
return message;
}
if (message instanceof Error) {
return message.stack || message.message;
}
return inspect(message, { depth: 6, colors: false });
})
.join(" ");
}
}
private write(label: string, ...messageParts: unknown[]): void {
const message = messageParts.map(log.stringify).join(" ");
const dateTime = new Date().toLocaleString();
log.output.appendLine(`${label} [${dateTime}]: ${message}`);
}
private stringify(val: unknown): string {
if (typeof val === "string") return val;
return inspect(val, {
colors: false,
depth: 6, // heuristic
});
}
})();
export const log = new Log();
export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
@ -135,7 +130,7 @@ export function execute(command: string, options: ExecOptions): Promise<string>
return new Promise((resolve, reject) => {
exec(command, options, (err, stdout, stderr) => {
if (err) {
log.error(err);
log.error("error:", err);
reject(err);
return;
}