Skip to content

Commit b111560

Browse files
committed
Add initial logger
1 parent a21c7d8 commit b111560

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,12 @@
233233
"type": "boolean",
234234
"default": true,
235235
"description": "Show compile status in the status bar (compiling/errors/warnings/success)."
236+
},
237+
"rescript.settings.logLevel": {
238+
"type": "string",
239+
"enum": ["error", "warn", "info", "log", "debug"],
240+
"default": "info",
241+
"description": "Verbosity of ReScript language server logs sent to the Output channel."
236242
}
237243
}
238244
},

server/src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export type send = (msg: Message) => void;
44

55
export interface extensionConfiguration {
66
askToStartBuild?: boolean;
7+
logLevel?: "error" | "warn" | "info" | "log";
78
inlayHints?: {
89
enable?: boolean;
910
maxLength?: number | null;
@@ -33,6 +34,7 @@ export interface extensionConfiguration {
3334
let config: { extensionConfiguration: extensionConfiguration } = {
3435
extensionConfiguration: {
3536
askToStartBuild: true,
37+
logLevel: "info",
3638
inlayHints: {
3739
enable: false,
3840
maxLength: 25,

server/src/logger.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import * as p from "vscode-languageserver-protocol";
2+
import * as c from "./constants";
3+
4+
export type LogLevel = "error" | "warn" | "info" | "log";
5+
6+
const levelOrder: Record<LogLevel, number> = {
7+
log: 1,
8+
info: 2,
9+
warn: 3,
10+
error: 4,
11+
};
12+
13+
export interface Logger {
14+
error(message: string): void;
15+
warn(message: string): void;
16+
info(message: string): void;
17+
log(message: string): void;
18+
}
19+
20+
class NoOpLogger implements Logger {
21+
error(_message: string): void {}
22+
warn(_message: string): void {}
23+
info(_message: string): void {}
24+
log(_message: string): void {}
25+
}
26+
27+
class LSPLogger implements Logger {
28+
private logLevel: LogLevel = "info";
29+
30+
constructor(private send: (msg: p.Message) => void) {}
31+
32+
setLogLevel(level: LogLevel): void {
33+
this.logLevel = level;
34+
}
35+
36+
private shouldLog(level: LogLevel): boolean {
37+
return levelOrder[level] >= levelOrder[this.logLevel];
38+
}
39+
40+
error(message: string): void {
41+
if (this.shouldLog("error")) {
42+
this.sendLogMessage(message, p.MessageType.Error);
43+
}
44+
}
45+
46+
warn(message: string): void {
47+
if (this.shouldLog("warn")) {
48+
this.sendLogMessage(message, p.MessageType.Warning);
49+
}
50+
}
51+
52+
info(message: string): void {
53+
if (this.shouldLog("info")) {
54+
this.sendLogMessage(message, p.MessageType.Info);
55+
}
56+
}
57+
58+
log(message: string): void {
59+
if (this.shouldLog("log")) {
60+
this.sendLogMessage(message, p.MessageType.Log);
61+
}
62+
}
63+
64+
private sendLogMessage(message: string, type: p.MessageType): void {
65+
const notification: p.NotificationMessage = {
66+
jsonrpc: c.jsonrpcVersion,
67+
method: "window/logMessage",
68+
params: { type, message },
69+
};
70+
this.send(notification);
71+
}
72+
}
73+
74+
// Default no-op instance
75+
let instance: Logger = new NoOpLogger();
76+
77+
export function initializeLogger(send: (msg: p.Message) => void): void {
78+
instance = new LSPLogger(send);
79+
}
80+
81+
export function setLogLevel(level: LogLevel): void {
82+
if (instance instanceof LSPLogger) {
83+
instance.setLogLevel(level);
84+
}
85+
}
86+
87+
export function getLogger(): Logger {
88+
return instance;
89+
}

server/src/server.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import * as ic from "./incrementalCompilation";
2929
import config, { extensionConfiguration } from "./config";
3030
import { projectsFiles } from "./projectFiles";
3131
import { NormalizedPath } from "./utils";
32+
import { initializeLogger, getLogger, setLogLevel, LogLevel } from "./logger";
3233

3334
// Absolute paths to all the workspace folders
3435
// Configured during the initialize request
@@ -548,10 +549,12 @@ export default function listen(useStdio = false) {
548549
let reader = new rpc.StreamMessageReader(process.stdin);
549550
// proper `this` scope for writer
550551
send = (msg: p.Message) => writer.write(msg);
552+
initializeLogger(send);
551553
reader.listen(onMessage);
552554
} else {
553555
// proper `this` scope for process
554556
send = (msg: p.Message) => process.send!(msg);
557+
initializeLogger(send);
555558
process.on("message", onMessage);
556559
}
557560
}
@@ -1453,6 +1456,7 @@ async function onMessage(msg: p.Message) {
14531456
};
14541457
send(response);
14551458
} else if (msg.method === "initialize") {
1459+
getLogger().info("Received initialize request from client.");
14561460
// Save initial configuration, if present
14571461
let initParams = msg.params as InitializeParams;
14581462
for (const workspaceFolder of initParams.workspaceFolders || []) {
@@ -1465,6 +1469,19 @@ async function onMessage(msg: p.Message) {
14651469

14661470
if (initialConfiguration != null) {
14671471
config.extensionConfiguration = initialConfiguration;
1472+
1473+
let initialLogLevel = initialConfiguration.logLevel as
1474+
| LogLevel
1475+
| undefined;
1476+
1477+
if (
1478+
initialLogLevel === "error" ||
1479+
initialLogLevel === "warn" ||
1480+
initialLogLevel === "info" ||
1481+
initialLogLevel === "log"
1482+
) {
1483+
setLogLevel(initialLogLevel);
1484+
}
14681485
}
14691486

14701487
// These are static configuration options the client can set to enable certain

0 commit comments

Comments
 (0)