Skip to content

Commit

Permalink
Output + Logger (#138)
Browse files Browse the repository at this point in the history
* use log and output channel

* update testscd

* notify about error on next

* add more logs

* cr fix

* cr fixes

* cr fixes

* update coverage

* update version
  • Loading branch information
slavik-lvovsky authored Feb 10, 2020
1 parent 107f458 commit 0ddcbf2
Show file tree
Hide file tree
Showing 20 changed files with 314 additions and 89 deletions.
9 changes: 5 additions & 4 deletions backend/.nycrc.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"require": ["ts-node/register/transpile-only"],
"include": ["src/**/*.ts"],
"exclude": ["src/logger/*.ts"],
"reporter": ["lcov", "text"],
"extension": [".ts"],
"all": true,
"temp-dir": "./reports/.nyc_output",
"report-dir": "./reports/coverage",
"check-coverage": true,
"branches": 27.9,
"lines": 39.9,
"functions": 31.7,
"statements": 40
"branches": 30.1,
"lines": 43.5,
"functions": 33,
"statements": 43.5
}
40 changes: 34 additions & 6 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"license": "Apache 2.0",
"description": "Provide rich user experience for Yeoman generators using VSCode extension or the browser",
"repository": "https://github.com/SAP/yeoman-ui",
"version": "0.0.35",
"version": "0.0.36",
"engines": {
"vscode": "^1.39.2"
},
Expand All @@ -24,8 +24,8 @@
"title": "Yeoman UI Generators"
},
{
"command": "yeomanUI.toggleLog",
"title": "Toggle Log",
"command": "yeomanUI.toggleOutput",
"title": "Toggle Output",
"icon": {
"light": "./resources/images/icons/console_light.svg",
"dark": "./resources/images/icons/console_dark.svg"
Expand All @@ -35,17 +35,44 @@
"menus": {
"commandPalette": [
{
"command": "yeomanUI.toggleLog",
"command": "yeomanUI.toggleOutput",
"when": "false"
}
],
"editor/title": [
{
"command": "yeomanUI.toggleLog",
"command": "yeomanUI.toggleOutput",
"group": "navigation",
"when": "yeomanUI.Focused"
}
]
},
"configuration": {
"type": "object",
"title": "Yeoman UI",
"properties": {
"logger.loggingLevel": {
"type": "string",
"enum": [
"off",
"fatal",
"error",
"warn",
"info",
"debug",
"trace"
],
"default": "warn",
"description": "The verbosity of logging according to the following order: trace > debug > info > warn > error > fatal > off.",
"scope": "resource"
},
"logger.sourceLocationTracking": {
"type": "boolean",
"default": false,
"description": "If chosen, the location of the source code is added to log entries. Warning – this action may slow your extension. We recommend you use it only for debugging.",
"scope": "resource"
}
}
}
},
"scripts": {
Expand Down Expand Up @@ -75,7 +102,8 @@
"titleize": "^1.0.1",
"humanize-string": "^1.0.2",
"fs-extra": "^8.1.0",
"chalk": "^3.0.0"
"chalk": "^3.0.0",
"@vscode-logging/logger": "^0.1.1"
},
"devDependencies": {
"@types/chai": "^4.2.5",
Expand Down
20 changes: 16 additions & 4 deletions backend/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,31 @@ import { OutputChannelLog } from './output-channel-log';
import { GeneratorFilter } from './filter';
import backendMessages from "./messages";
import { Theia } from './theia';
import { createExtensionLoggerAndSubscribeToLogSettingsChanges } from "./logger/logger-wrapper";
import { getClassLogger } from "./logger/logger-wrapper";
import { IChildLogger } from "@vscode-logging/logger";

const ERROR_ACTIVATION_FAILED_LOGGER_CONFIG = 'Extension activation failed due to Logger configuration failure:';

export function activate(context: vscode.ExtensionContext) {
try {
createExtensionLoggerAndSubscribeToLogSettingsChanges(context);
} catch (error) {
console.error(ERROR_ACTIVATION_FAILED_LOGGER_CONFIG, error.message);
return;
}

context.subscriptions.push(
vscode.commands.registerCommand('loadYeomanUI', (options?: any) => {
const genFilter = _.get(options, "filter");
const messages = _.get(options, "messages");
YeomanUIPanel.createOrShow(context.extensionPath, GeneratorFilter.create(genFilter), messages);
}));
context.subscriptions.push(
vscode.commands.registerCommand('yeomanUI.toggleLog', () => {
vscode.commands.registerCommand('yeomanUI.toggleOutput', () => {
const yeomanUi = _.get(YeomanUIPanel, "currentPanel.yeomanui");
if (yeomanUi) {
yeomanUi.toggleLog();
yeomanUi.toggleOutput();
}
}));

Expand All @@ -42,6 +53,7 @@ export function activate(context: vscode.ExtensionContext) {
* Manages webview panels
*/
export class YeomanUIPanel {
private readonly logger: IChildLogger = getClassLogger(YeomanUI.name);
/**
* Track the currently panel. Only allow a single panel to exist at a time.
*/
Expand Down Expand Up @@ -97,10 +109,10 @@ export class YeomanUIPanel {
this.panel = panel;
this.extensionPath = extensionPath;
this.rpc = new RpcExtension(this.panel.webview);
const logger: YouiLog = new OutputChannelLog();
const outputChannel: YouiLog = new OutputChannelLog();
this.theia = new Theia();

this.yeomanui = new YeomanUI(this.rpc, logger, YeomanUIPanel.genFilter);
this.yeomanui = new YeomanUI(this.rpc, outputChannel, this.logger, YeomanUIPanel.genFilter);

// Set the webview's initial html content
this._update();
Expand Down
91 changes: 91 additions & 0 deletions backend/src/logger/logger-wrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as vscode from "vscode"; // NOSONAR
import { getExtensionLogger, getExtensionLoggerOpts, IChildLogger, IVSCodeExtLogger } from "@vscode-logging/logger";
import { listenToLogSettingsChanges, logLoggerDetails } from "./settings-changes-handler";
// import {resolve} from "path";
import { getLoggingLevelSetting, getSourceLocationTrackingSetting} from "./settings";

// const PACKAGE_JSON = "package.json";
const YEOMAN_UI_LOGGER_NAME = "yeomanui";

/**
* A Simple Wrapper to hold the state of our "singleton" (per extension) IVSCodeExtLogger
* implementation.
*/

export const ERROR_LOGGER_NOT_INITIALIZED = 'Logger has not yet been initialized!';

/**
* @type {IVSCodeExtLogger}
*/
let logger: any;

function isInitialized() :boolean {
return (logger !== undefined ) ? true : false;
}

/**
* Note the use of a getter function so the value would be lazy resolved on each use.
* This enables concise and simple consumption of the Logger throughout our Extension.
*
* @returns { IVSCodeExtLogger }
*/
export function getLogger() : IVSCodeExtLogger {
if (isInitialized() === false) {
throw Error(ERROR_LOGGER_NOT_INITIALIZED);
}
return logger;
}

export function getClassLogger(className: string) : IChildLogger {
return getLogger().getChildLogger({label:className});
}

export function getYeomanUILibraryLogger() : IChildLogger {
return getLibraryLogger(YEOMAN_UI_LOGGER_NAME);
}

function getLibraryLogger(libraryName: string) : IChildLogger {
return getLogger().getChildLogger({label:libraryName});
}

export function createExtensionLoggerAndSubscribeToLogSettingsChanges(context: vscode.ExtensionContext) {
createExtensionLogger(context);
// Subscribe to Logger settings changes.
listenToLogSettingsChanges(context);
}

/**
* This function should be invoked after the Logger has been initialized in the Extension's `activate` function.
* @param {IVSCodeExtLogger} newLogger
*/
function initLoggerWrapper(newLogger: any) {
logger = newLogger;
}

function createExtensionLogger(context: vscode.ExtensionContext) {
const contextLogPath = context.logPath;
const logLevelSetting: string = getLoggingLevelSetting();
const sourceLocationTrackingSettings: boolean = getSourceLocationTrackingSetting();

//TODO: const meta = require(resolve(context.extensionPath, PACKAGE_JSON));
const extensionLoggerOpts: getExtensionLoggerOpts = {
extName: "yeoman-ui.logger",
level: logLevelSetting,
logPath: contextLogPath,
sourceLocationTracking: sourceLocationTrackingSettings
};

// The Logger must first be initialized before any logging commands may be invoked.
const extensionLogger = getExtensionLogger(extensionLoggerOpts);
// Update the logger-wrapper with a reference to the extLogger.
initLoggerWrapper(extensionLogger);
logLoggerDetails(context, logLevelSetting);
}

module.exports = {
getLogger,
createExtensionLoggerAndSubscribeToLogSettingsChanges,
getClassLogger,
getYeomanUILibraryLogger,
ERROR_LOGGER_NOT_INITIALIZED
};
46 changes: 46 additions & 0 deletions backend/src/logger/settings-changes-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as vscode from "vscode"; // NOSONAR
import {getLogger} from "./logger-wrapper";
import {LOGGING_LEVEL_CONFIG_PROP, SOURCE_TRACKING_CONFIG_PROP} from "./settings";

export function logLoggerDetails(context: vscode.ExtensionContext, configLogLevel: string): void {
getLogger().info(`Start Logging in Log Level: <${configLogLevel}>`);
getLogger().info(`Full Logs can be found in the <${context.logPath}> folder.`);
}

/**
* @param {vscode.ExtensionContext} context
*/
export function listenToLogSettingsChanges(context: vscode.ExtensionContext) {
// To enable dynamic logging level we must listen to VSCode configuration changes
// on our `loggingLevelConfigProp` configuration setting.
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(LOGGING_LEVEL_CONFIG_PROP)) {
const logLevel: string = vscode.workspace
.getConfiguration()
.get(LOGGING_LEVEL_CONFIG_PROP);

getLogger().changeLevel(logLevel);
logLoggerDetails(context, logLevel);
}
})
);

// Enable responding to changes in the sourceLocationTracking setting
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(SOURCE_TRACKING_CONFIG_PROP)) {
const newSourceLocationTracking = vscode.workspace
.getConfiguration()
.get(SOURCE_TRACKING_CONFIG_PROP);

getLogger().changeSourceLocationTracking(newSourceLocationTracking);
}
})
);
}

module.exports = {
listenToLogSettingsChanges,
logLoggerDetails
};
31 changes: 31 additions & 0 deletions backend/src/logger/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as vscode from "vscode"; // NOSONAR
import { resolve } from "dns";

/**
* Note that the values of these configuration properties must match those defined in the package.json
*/
export const LOGGING_LEVEL_CONFIG_PROP = "logger.loggingLevel";
export const SOURCE_TRACKING_CONFIG_PROP = "logger.sourceLocationTracking";

/**
* @returns {LogLevel}
*/
export function getLoggingLevelSetting(): string {
const config = vscode.workspace.getConfiguration();
return config.get(LOGGING_LEVEL_CONFIG_PROP);
}

/**
* @returns {boolean}
*/
export function getSourceLocationTrackingSetting(): boolean {
const config = vscode.workspace.getConfiguration();
return config.get(SOURCE_TRACKING_CONFIG_PROP);
}

module.exports = {
LOGGING_LEVEL_CONFIG_PROP,
SOURCE_TRACKING_CONFIG_PROP,
getLoggingLevelSetting,
getSourceLocationTrackingSetting
};
2 changes: 1 addition & 1 deletion backend/src/output-channel-log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class OutputChannelLog implements YouiLog {
public skip(value: string): void {
getOutputChannel().appendLine(stripAnsi(value));
}
public showLog():boolean {
public showOutput():boolean {
getOutputChannel().show();
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion backend/src/theia.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// TODO: remove this class when those vscode commands are implemented in theia.
import * as vscode from "vscode";
import * as vscode from "vscode"; // NOSONAR

export class Theia {
private isInTheiaCached: boolean;
Expand Down
3 changes: 2 additions & 1 deletion backend/src/webSocketServer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { YeomanUI } from '../yeomanui';
import { YouiLog } from "../youi-log";
import { ServerLog } from './server-log';
import backendMessages from "../messages";
import { IChildLogger } from "@vscode-logging/logger";

class YeomanUIWebSocketServer {
private rpc: RpcExtensionWebSockets | undefined;
Expand All @@ -28,7 +29,7 @@ class YeomanUIWebSocketServer {
this.rpc = new RpcExtensionWebSockets(ws);
//TODO: Use RPC to send it to the browser log (as a collapsed pannel in Vue)
const logger: YouiLog = new ServerLog(this.rpc);
this.yeomanui = new YeomanUI(this.rpc, logger);
this.yeomanui = new YeomanUI(this.rpc, logger, {debug: () => {}, error: () => {}} as IChildLogger);
this.yeomanui.setMessages(backendMessages);
});
}
Expand Down
8 changes: 4 additions & 4 deletions backend/src/webSocketServer/server-log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const stripAnsi = require("strip-ansi");

export class ServerLog implements YouiLog {
private rpc: RpcCommon;
private isLogVisible: boolean = false;
private isOutputVisible: boolean = false;
/**
*
*/
Expand Down Expand Up @@ -32,8 +32,8 @@ export class ServerLog implements YouiLog {
public skip(str: string): void {
this.rpc.invoke("log", [stripAnsi(str) + '\n']);
}
public showLog(): boolean {
this.isLogVisible = !this.isLogVisible;
return !this.isLogVisible;
public showOutput(): boolean {
this.isOutputVisible = !this.isOutputVisible;
return !this.isOutputVisible;
}
}
Loading

0 comments on commit 0ddcbf2

Please sign in to comment.