Skip to content

Commit 816a39c

Browse files
bors[bot]Veetaha
andauthored
Merge #5229
5229: Improve client logging (use output channel and more log levels) r=matklad a=Veetaha The improvements: * Separate output channel allows viewing the logs belonging to only our extension (without the intervention of other vscode extensions) * All the objects in the output channel are always expanded so users only need to `Ctrl + A and Ctrl + C` to copy the entire output to send us and nothing more (e.g. currently users need to expand the object which is not obvious for them and we may lose the logs this way, see two comments: #5009 (comment) * More log levels allows us to be more granular in disabling only optional verbose debug-level output and leave the logs for us as developers to understand the context of user issues. * For `log.error(...)` invocations we reveal `Rust Analyzer Client` channel automatically so that users don't have to do any additional actions to get the logs output window visible Demo: ![image](https://user-images.githubusercontent.com/36276403/86535275-d7795f80-bee7-11ea-8c30-135c83c1bc7d.png) Co-authored-by: Veetaha <[email protected]>
2 parents 6546a68 + 46163ac commit 816a39c

File tree

4 files changed

+49
-18
lines changed

4 files changed

+49
-18
lines changed

editors/code/src/config.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ export class Config {
3939

4040
private refreshLogging() {
4141
log.setEnabled(this.traceExtension);
42-
log.debug(
43-
"Extension version:", this.package.version,
44-
"using configuration:", this.cfg
45-
);
42+
log.info("Extension version:", this.package.version);
43+
44+
const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function));
45+
log.info("Using configuration", Object.fromEntries(cfg));
4646
}
4747

4848
private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {

editors/code/src/main.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ async function tryActivate(context: vscode.ExtensionContext) {
5959
message += "you should close them and reload this window to retry. ";
6060
}
6161

62-
message += 'Open "Help > Toggle Developer Tools > Console" to see the logs ';
63-
message += '(enable verbose logs with "rust-analyzer.trace.extension")';
62+
message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
63+
message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
6464

6565
log.error("Bootstrap error", err);
6666
throw new Error(message);
@@ -214,7 +214,7 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
214214
);
215215
}
216216

217-
log.debug("Using server binary at", path);
217+
log.info("Using server binary at", path);
218218

219219
if (!isValidExecutable(path)) {
220220
throw new Error(`Failed to execute ${path} --version`);

editors/code/src/persistent_state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { log } from './util';
44
export class PersistentState {
55
constructor(private readonly globalState: vscode.Memento) {
66
const { lastCheck, releaseId, serverVersion } = this;
7-
log.debug("PersistentState: ", { lastCheck, releaseId, serverVersion });
7+
log.info("PersistentState:", { lastCheck, releaseId, serverVersion });
88
}
99

1010
/**

editors/code/src/util.ts

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import * as lc from "vscode-languageclient";
2+
import * as fs from "fs";
23
import * as vscode from "vscode";
34
import { strict as nativeAssert } from "assert";
45
import { spawnSync } from "child_process";
6+
import { inspect } from "util";
57

68
export function assert(condition: boolean, explanation: string): asserts condition {
79
try {
@@ -14,21 +16,46 @@ export function assert(condition: boolean, explanation: string): asserts conditi
1416

1517
export const log = new class {
1618
private enabled = true;
19+
private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client");
1720

1821
setEnabled(yes: boolean): void {
1922
log.enabled = yes;
2023
}
2124

22-
debug(message?: any, ...optionalParams: any[]): void {
25+
// Hint: the type [T, ...T[]] means a non-empty array
26+
debug(...msg: [unknown, ...unknown[]]): void {
2327
if (!log.enabled) return;
24-
// eslint-disable-next-line no-console
25-
console.log(message, ...optionalParams);
28+
log.write("DEBUG", ...msg);
29+
log.output.toString();
2630
}
2731

28-
error(message?: any, ...optionalParams: any[]): void {
32+
info(...msg: [unknown, ...unknown[]]): void {
33+
log.write("INFO", ...msg);
34+
}
35+
36+
warn(...msg: [unknown, ...unknown[]]): void {
37+
debugger;
38+
log.write("WARN", ...msg);
39+
}
40+
41+
error(...msg: [unknown, ...unknown[]]): void {
2942
debugger;
30-
// eslint-disable-next-line no-console
31-
console.error(message, ...optionalParams);
43+
log.write("ERROR", ...msg);
44+
log.output.show(true);
45+
}
46+
47+
private write(label: string, ...messageParts: unknown[]): void {
48+
const message = messageParts.map(log.stringify).join(" ");
49+
const dateTime = new Date().toLocaleString();
50+
log.output.appendLine(`${label} [${dateTime}]: ${message}`);
51+
}
52+
53+
private stringify(val: unknown): string {
54+
if (typeof val === "string") return val;
55+
return inspect(val, {
56+
colors: false,
57+
depth: 6, // heuristic
58+
});
3259
}
3360
};
3461

@@ -46,7 +73,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
4673
);
4774
} catch (error) {
4875
if (delay === null) {
49-
log.error("LSP request timed out", { method: reqType.method, param, error });
76+
log.warn("LSP request timed out", { method: reqType.method, param, error });
5077
throw error;
5178
}
5279

@@ -55,7 +82,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
5582
}
5683

5784
if (error.code !== lc.ErrorCodes.ContentModified) {
58-
log.error("LSP request failed", { method: reqType.method, param, error });
85+
log.warn("LSP request failed", { method: reqType.method, param, error });
5986
throw error;
6087
}
6188

@@ -87,11 +114,15 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
87114
export function isValidExecutable(path: string): boolean {
88115
log.debug("Checking availability of a binary at", path);
89116

117+
if (!fs.existsSync(path)) return false;
118+
90119
const res = spawnSync(path, ["--version"], { encoding: 'utf8' });
91120

92-
log.debug(res, "--version output:", res.output);
121+
const isSuccess = res.status === 0;
122+
const printOutput = isSuccess ? log.debug : log.warn;
123+
printOutput(path, "--version:", res);
93124

94-
return res.status === 0;
125+
return isSuccess;
95126
}
96127

97128
/** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */

0 commit comments

Comments
 (0)