Add Logger

This commit is contained in:
quanzhuo 2022-09-03 11:03:41 +08:00
parent 4c48cc52de
commit 8005b3dce5
4 changed files with 203 additions and 61 deletions

56
.vscode/launch.json vendored
View File

@ -3,32 +3,32 @@
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
},
{
"name": "Extension Tests",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
],
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
},
{
"name": "Extension Tests",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
],
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

View File

@ -64,10 +64,30 @@
"title": "CMake IntelliSence",
"properties": {
"cmakeIntelliSence.languageServerPath": {
"scope": "resource",
"type": "string",
"default": "cmakels",
"description": "Path to CMake Language Server"
},
"cmakeIntelliSence.loggingLevel": {
"type": "string",
"enum": [
"Off",
"Error",
"Warnning",
"Info",
"Debug"
],
"default": "Info",
"markdownDescription": "Control the logging level"
},
"cmakeIntelliSence.trace.server": {
"type": "string",
"enum": [
"verbose",
"message",
"off"
],
"default": "verbose"
}
}
}

View File

@ -1,32 +1,24 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as path from 'path';
import * as net from 'net';
import * as vscode from 'vscode';
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind
} from 'vscode-languageclient/node';
import { getConfigLogLevel, Logger } from './logging';
import { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node';
export const SERVER_ID = 'cmakeIntelliSence';
export const SERVER_NAME = 'CMake Language Server';
let client: LanguageClient;
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
const config = vscode.workspace.getConfiguration(SERVER_ID);
const logger = new Logger();
logger.setLogLevel(getConfigLogLevel(config));
const config = vscode.workspace.getConfiguration('cmakeIntelliSence');
let cmakels = config.get<string>('languageServerPath');
if (cmakels === undefined) {
cmakels = 'cmakels';
}
// language server options
// default transport is TransportKind.stdio
const serverOptions: ServerOptions = {
command: cmakels,
// args: [serverEntryPath]
};
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration(`${SERVER_ID}.loggingLevel`)) {
logger.setLogLevel(getConfigLogLevel(config));
}
}));
// Options to control the language client
const clientOptions: LanguageClientOptions = {
@ -34,22 +26,44 @@ export function activate(context: vscode.ExtensionContext) {
{ language: 'cmake', scheme: 'file' },
{ language: 'cmake', scheme: 'untitled' }
],
outputChannel: vscode.window.createOutputChannel('CMake IntelliSence')
outputChannel: logger.getOutputChannel()
};
// Create the language client and start the client.
client = new LanguageClient(
'cmakeLanguageServer',
'CMake Language Server',
serverOptions,
clientOptions
);
// language server options
let serverOptions: ServerOptions;
let mode: string;
if (context.extensionMode === vscode.ExtensionMode.Development) {
// Development - communicate using tcp
serverOptions = () => {
return new Promise((resolve) => {
const clientSocket = new net.Socket();
clientSocket.connect(2088, "127.0.0.1", () => {
resolve({
reader: clientSocket,
writer: clientSocket
});
});
clientSocket.on('connect', () => { logger.info('Connected'); });
clientSocket.on('error', (err) => { logger.info('error', err); });
clientSocket.on('close', () => { logger.info('connection closed'); });
});
};
mode = 'Development';
} else {
// Production - communicate using stdio
serverOptions = {
command: 'cmakels'
};
mode = 'Production';
}
client = new LanguageClient(SERVER_ID, SERVER_NAME, serverOptions, clientOptions);
// start the client. This will also launch the server
logger.info(`Start ${SERVER_NAME} in ${mode} mode...`);
client.start();
}
// this method is called when your extension is deactivated
export function deactivate() {
if (!client) {
return undefined;

108
src/logging.ts Normal file
View File

@ -0,0 +1,108 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { OutputChannel, window, workspace, WorkspaceConfiguration } from 'vscode';
import { SERVER_ID } from './extension';
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
OFF = 4,
}
export class Logger {
constructor(
private channel: OutputChannel = window.createOutputChannel('CMake IntelliSence'),
private level: LogLevel = LogLevel.INFO
) { }
public setLogLevel(logLevel: LogLevel) {
this.level = logLevel;
}
public getLogLevel(): LogLevel {
return this.level;
}
public getOutputChannel(): OutputChannel {
return this.channel;
}
public debug(message: string, data?: unknown): void {
if (this.level > LogLevel.DEBUG) {
return;
}
this.log(message, LogLevel.DEBUG);
if (data) {
this.logObject(data);
}
}
public info(message: string, data?: unknown): void {
if (this.level > LogLevel.INFO) {
return;
}
this.log(message, LogLevel.INFO);
if (data) {
this.logObject(data);
}
}
public warn(message: string, data?: unknown): void {
if (this.level > LogLevel.WARN) {
return;
}
this.log(message, LogLevel.WARN);
if (data) {
this.logObject(data);
}
}
public error(message: string, error?: Error | string) {
if (this.level > LogLevel.ERROR) {
return;
}
this.log(message, LogLevel.ERROR);
if (typeof error === 'string') {
// Errors as a string usually only happen with
// plugins that don't return the expected error.
this.channel.appendLine(error);
} else if (error?.message || error?.stack) {
if (error?.message) {
this.log(error.message, LogLevel.ERROR);
}
if (error?.stack) {
this.channel.appendLine(error.stack);
}
} else if (error) {
this.logObject(error);
}
}
public show() {
this.channel.show();
}
private logObject(data: unknown): void {
const message = JSON.stringify(data, null, 2);
this.channel.appendLine(message);
}
private log(message: string, level: LogLevel): void {
const title = new Date().toLocaleTimeString();
this.channel.appendLine(`[${LogLevel[level]} - ${title}] ${message}`);
}
}
/**
* Gets the `loggingLevel` option from the workspace settings and converts
* it a `LogLevel` enum value.
* @param config workspace configuration object
* @returns `LogLevel` enum value
*/
export function getConfigLogLevel(
config: WorkspaceConfiguration = workspace.getConfiguration(SERVER_ID)
): LogLevel {
return LogLevel[(config.get<string>('loggingLevel') as string).toUpperCase() as keyof typeof LogLevel];
}