aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-07-06 08:36:49 +0100
committerGitHub <[email protected]>2020-07-06 08:36:49 +0100
commit816a39cb54766c1dc8960620142659e716f485dc (patch)
treed821b907d1aae6b5a222454a2d56b07a9b87204d
parent6546a684704fa90d3611c75b4167f63ff1851ee5 (diff)
parent46163acf62a94ec603be444294e119933c953a84 (diff)
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: https://github.com/rust-analyzer/rust-analyzer/issues/5009#issuecomment-651361137 * 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]>
-rw-r--r--editors/code/src/config.ts8
-rw-r--r--editors/code/src/main.ts6
-rw-r--r--editors/code/src/persistent_state.ts2
-rw-r--r--editors/code/src/util.ts51
4 files changed, 49 insertions, 18 deletions
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 23975c726..033b04b60 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -39,10 +39,10 @@ export class Config {
39 39
40 private refreshLogging() { 40 private refreshLogging() {
41 log.setEnabled(this.traceExtension); 41 log.setEnabled(this.traceExtension);
42 log.debug( 42 log.info("Extension version:", this.package.version);
43 "Extension version:", this.package.version, 43
44 "using configuration:", this.cfg 44 const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function));
45 ); 45 log.info("Using configuration", Object.fromEntries(cfg));
46 } 46 }
47 47
48 private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) { 48 private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index a1521a93b..5877be8b2 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -59,8 +59,8 @@ async function tryActivate(context: vscode.ExtensionContext) {
59 message += "you should close them and reload this window to retry. "; 59 message += "you should close them and reload this window to retry. ";
60 } 60 }
61 61
62 message += 'Open "Help > Toggle Developer Tools > Console" to see the logs '; 62 message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
63 message += '(enable verbose logs with "rust-analyzer.trace.extension")'; 63 message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
64 64
65 log.error("Bootstrap error", err); 65 log.error("Bootstrap error", err);
66 throw new Error(message); 66 throw new Error(message);
@@ -214,7 +214,7 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
214 ); 214 );
215 } 215 }
216 216
217 log.debug("Using server binary at", path); 217 log.info("Using server binary at", path);
218 218
219 if (!isValidExecutable(path)) { 219 if (!isValidExecutable(path)) {
220 throw new Error(`Failed to execute ${path} --version`); 220 throw new Error(`Failed to execute ${path} --version`);
diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts
index 138d11b89..5705eed81 100644
--- a/editors/code/src/persistent_state.ts
+++ b/editors/code/src/persistent_state.ts
@@ -4,7 +4,7 @@ import { log } from './util';
4export class PersistentState { 4export class PersistentState {
5 constructor(private readonly globalState: vscode.Memento) { 5 constructor(private readonly globalState: vscode.Memento) {
6 const { lastCheck, releaseId, serverVersion } = this; 6 const { lastCheck, releaseId, serverVersion } = this;
7 log.debug("PersistentState: ", { lastCheck, releaseId, serverVersion }); 7 log.info("PersistentState:", { lastCheck, releaseId, serverVersion });
8 } 8 }
9 9
10 /** 10 /**
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index fec4c3295..78fe6f5da 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -1,7 +1,9 @@
1import * as lc from "vscode-languageclient"; 1import * as lc from "vscode-languageclient";
2import * as fs from "fs";
2import * as vscode from "vscode"; 3import * as vscode from "vscode";
3import { strict as nativeAssert } from "assert"; 4import { strict as nativeAssert } from "assert";
4import { spawnSync } from "child_process"; 5import { spawnSync } from "child_process";
6import { inspect } from "util";
5 7
6export function assert(condition: boolean, explanation: string): asserts condition { 8export function assert(condition: boolean, explanation: string): asserts condition {
7 try { 9 try {
@@ -14,21 +16,46 @@ export function assert(condition: boolean, explanation: string): asserts conditi
14 16
15export const log = new class { 17export const log = new class {
16 private enabled = true; 18 private enabled = true;
19 private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client");
17 20
18 setEnabled(yes: boolean): void { 21 setEnabled(yes: boolean): void {
19 log.enabled = yes; 22 log.enabled = yes;
20 } 23 }
21 24
22 debug(message?: any, ...optionalParams: any[]): void { 25 // Hint: the type [T, ...T[]] means a non-empty array
26 debug(...msg: [unknown, ...unknown[]]): void {
23 if (!log.enabled) return; 27 if (!log.enabled) return;
24 // eslint-disable-next-line no-console 28 log.write("DEBUG", ...msg);
25 console.log(message, ...optionalParams); 29 log.output.toString();
26 } 30 }
27 31
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 {
29 debugger; 42 debugger;
30 // eslint-disable-next-line no-console 43 log.write("ERROR", ...msg);
31 console.error(message, ...optionalParams); 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 });
32 } 59 }
33}; 60};
34 61
@@ -46,7 +73,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
46 ); 73 );
47 } catch (error) { 74 } catch (error) {
48 if (delay === null) { 75 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 });
50 throw error; 77 throw error;
51 } 78 }
52 79
@@ -55,7 +82,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
55 } 82 }
56 83
57 if (error.code !== lc.ErrorCodes.ContentModified) { 84 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 });
59 throw error; 86 throw error;
60 } 87 }
61 88
@@ -87,11 +114,15 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
87export function isValidExecutable(path: string): boolean { 114export function isValidExecutable(path: string): boolean {
88 log.debug("Checking availability of a binary at", path); 115 log.debug("Checking availability of a binary at", path);
89 116
117 if (!fs.existsSync(path)) return false;
118
90 const res = spawnSync(path, ["--version"], { encoding: 'utf8' }); 119 const res = spawnSync(path, ["--version"], { encoding: 'utf8' });
91 120
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);
93 124
94 return res.status === 0; 125 return isSuccess;
95} 126}
96 127
97/** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */ 128/** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */