Skip to content

Commit

Permalink
feat: logger wrapper package (#163)
Browse files Browse the repository at this point in the history
  • Loading branch information
bd82 authored Jan 31, 2021
1 parent 33b09d7 commit 0820834
Show file tree
Hide file tree
Showing 30 changed files with 927 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ package-lock.json
test/.log-out
test/.log-out/*

# compiled sources
dist
tsconfig.tsbuildinfo

2 changes: 2 additions & 0 deletions examples/extension-wrapper/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
*.vsix
17 changes: 17 additions & 0 deletions examples/extension-wrapper/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// 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",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/src/**/*.js"]
}
]
}
3 changes: 3 additions & 0 deletions examples/extension-wrapper/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"editor.insertSpaces": false
}
20 changes: 20 additions & 0 deletions examples/extension-wrapper/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
35 changes: 35 additions & 0 deletions examples/extension-wrapper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# @vscode-logging Extension-Wrapper Example

This folder contains a sample VS code extension that demonstrates
how to integrate @vscode-logging/**wrapper** in a VSCode extension.

## Running the Sample

### Initial setup (once)

- `yarn` in this repository's **root**.

### Run/Debug the Example Extension in VSCode

- Open this example folder in VSCode.
- Press F5 in VSCode to start the example Extension.

### Basic logging flow

- Activate the **Hello World Command**: `View Menu -> Command Palette -> Hello World`
- Open the **Output Panel**: `View Menu -> Output`
- Switch to the `logging-wrapper-example` output Channel using the dropdown.
- Inspect the output channel log and note that the location of the log **Files** was written.
- Inspect the contents of the log files using your favorite file system explorer.

### Changing logging Configuration.

- Open the **Settings Page**: `File -> Preferences -> Settings`
- Locate the **Example_Logging: Logging Level** configuration.
- Play with these settings and inspect how the logging output changes.

## Points of Interest in this Example:

- [extension.ts](./src/extension.ts) - `configureLogger` API invocation (inside `activate` function).
- [logger.ts](./src/logger.ts) - State management for the logger instance.
- [commands.ts](./src/commands.ts) - The implementation of the `Hello World` Command.
63 changes: 63 additions & 0 deletions examples/extension-wrapper/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"name": "vscode-logging-extension-wrapper-example",
"private": true,
"displayName": "logging-wrapper-example",
"description": "Example using @vscode-logging/logger and @vscode-logging/wrapper in a VSCode Extension",
"version": "0.1.0",
"publisher": "SAP",
"engines": {
"vscode": "^1.52.0"
},
"activationEvents": [
"onCommand:extension.helloWorld"
],
"main": "./dist/src/extension.js",
"scripts": {
"ci": "npm-run-all clean compile",
"clean": "rimraf dist",
"compile": "tsc"
},
"contributes": {
"commands": [
{
"command": "extension.helloWorld",
"title": "Hello World"
}
],
"configuration": {
"type": "object",
"title": "Example_Logging",
"properties": {
"Example_Logging.loggingLevel": {
"type": "string",
"enum": [
"off",
"fatal",
"error",
"warn",
"info",
"debug",
"trace"
],
"default": "error",
"description": "The verbosity of logging. The Order is None < fatal < error < warn < info < debug < trace.",
"scope": "window"
},
"Example_Logging.sourceLocationTracking": {
"type": "boolean",
"default": false,
"description": "Should Source Code Location Info be added to log entries, DANGER - May be very slow, only use in debugging scenarios",
"scope": "window"
}
}
}
},
"dependencies": {
"@vscode-logging/wrapper": "^0.1.0"
},
"devDependencies": {
"@types/vscode": "^1.52.0",
"@vscode-logging/types": "^0.1.3"
},
"peerDependencies": {}
}
20 changes: 20 additions & 0 deletions examples/extension-wrapper/src/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ExtensionContext, commands, window } from "vscode";
import { getLogger } from "./logger";

export function registerCommands(
subscriptions: ExtensionContext["subscriptions"]
): void {
let logMessagesCounter = 1;
const commandSubscription = commands.registerCommand(
"extension.helloWorld",
// By providing a real function name rather then a `fat arrow` ( ()=>{} )
// The `sourceLocationTracking` can provide a meaningful output.
function registerCallback() {
window.showInformationMessage("Hello Cruel World!");
getLogger().error(
`Hip Hip Hurray, the <Hello World> Command was executed! counter: <${logMessagesCounter++}>`
);
}
);
subscriptions.push(commandSubscription);
}
9 changes: 9 additions & 0 deletions examples/extension-wrapper/src/extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ExtensionContext } from "vscode";
import { getLogger, initLogger } from "./logger";
import { registerCommands } from "./commands";

export async function activate(context: ExtensionContext): Promise<void> {
await initLogger(context);
registerCommands(context.subscriptions);
getLogger().info("extension is active, hip hip hurray!");
}
56 changes: 56 additions & 0 deletions examples/extension-wrapper/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* This file manages the logger's state.
*/
import { readFile as readFileCallback } from "fs";
import { promisify } from "util";
import { resolve } from "path";
import { ok } from "assert";
import { ExtensionContext, window, workspace } from "vscode";
import { IChildLogger, IVSCodeExtLogger } from "@vscode-logging/types";
import { configureLogger, NOOP_LOGGER } from "@vscode-logging/wrapper";

const readFile = promisify(readFileCallback);

// On file load we initialize our logger to `NOOP_LOGGER`
// this is done because the "real" logger cannot be initialized during file load.
// only once the `activate` function has been called in extension.ts
// as the `ExtensionContext` argument to `activate` contains the required `logPath`
let loggerImpel: IVSCodeExtLogger = NOOP_LOGGER;

export function getLogger(): IChildLogger {
return loggerImpel;
}

function setLogger(newLogger: IVSCodeExtLogger): void {
loggerImpel = newLogger;
}

const LOGGING_LEVEL_PROP = "Example_Logging.loggingLevel";
const SOURCE_LOCATION_PROP = "Example_Logging.sourceLocationTracking";

export async function initLogger(context: ExtensionContext): Promise<void> {
const meta = JSON.parse(
await readFile(resolve(context.extensionPath, "package.json"), "utf8")
);

// By asserting the existence of the properties in the package.json
// at runtime, we avoid many copy-pasta mistakes...
const configProps = meta?.contributes?.configuration?.properties;
ok(configProps?.[LOGGING_LEVEL_PROP]);
ok(configProps?.[SOURCE_LOCATION_PROP]);

const extLogger = configureLogger({
extName: meta.displayName,
logPath: context.logPath,
logOutputChannel: window.createOutputChannel(meta.displayName),
// set to `true` if you also want your VSCode extension to log to the console.
logConsole: false,
loggingLevelProp: LOGGING_LEVEL_PROP,
sourceLocationProp: SOURCE_LOCATION_PROP,
subscriptions: context.subscriptions,
onDidChangeConfiguration: workspace.onDidChangeConfiguration,
getConfiguration: workspace.getConfiguration
});

setLogger(extLogger);
}
16 changes: 16 additions & 0 deletions examples/extension-wrapper/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compileOnSave": true,
"compilerOptions": {
"rootDir": ".",
"outDir": "dist",
"baseUrl": ".",
"module": "commonjs",
"lib": ["es7"],
"target": "es2017",
"declaration": true,
"sourceMap": true,
"forceConsistentCasingInFileNames": true,
"strict": true
},
"include": ["./src/**/*.ts", "./api.d.ts"]
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"nyc": "15.0.0",
"prettier": "1.19.1",
"shx": "0.3.2",
"typescript": "4.1.2"
"typescript": "4.1.2",
"rimraf": "^3.0.2"
},
"husky": {
"hooks": {
Expand Down
13 changes: 13 additions & 0 deletions packages/wrapper/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# TypeScript
tsconfig.json

# NYC
.nyc_output
nyc.config.js
coverage

# tests
test

# Dev Docs
CONTRIBUTING.md
Empty file added packages/wrapper/CHANGELOG.md
Empty file.
3 changes: 3 additions & 0 deletions packages/wrapper/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contribution Guide

Please see the top level [Contribution Guide](../../CONTRIBUTING.md).
34 changes: 34 additions & 0 deletions packages/wrapper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# @vscode-logging/wrapper

A **optional** and **opinionated** wrapper utilities for @vscode-logging/logger.

## Installation

With npm:

- `npm install @vscode-logging/wrapper --save`

With Yarn:

- `yarn add @vscode-logging/wrapper`

## Usage

Please see the [TypeScript Definitions](./api.d.ts) for full API details.

## Example

An example VSCode extension is available in the [examples' folder](https://github.com/SAP/vscode-logging/tree/master/examples/extension-wrapper).

## Support

Please open [issues](https://github.com/SAP/vscode-logging/issues) on github.

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md).

## License

Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved.
This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the [LICENSE file](../../LICENSE).
64 changes: 64 additions & 0 deletions packages/wrapper/api.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { workspace, ExtensionContext } from "vscode";
import { IVSCodeExtLogger } from "@vscode-logging/types";
import { BasicOutputChannel } from "@vscode-logging/logger";

/**
* An "empty" Logger implementation.
* This value should be used to initialize an extension's logger
* before the `activate` function has been called.
*/
export declare const NOOP_LOGGER: IVSCodeExtLogger;

export interface ConfigureLoggerOpts {
/**
* @see {GetExtensionLoggerOpts.extName}
*/
extName: string;
/**
* @see {GetExtensionLoggerOpts.logPath}
*/
logPath: string;
loggingLevelProp: string;
sourceLocationProp: string;
/**
* @see {GetExtensionLoggerOpts.logOutputChannel}
*/
logOutputChannel?: BasicOutputChannel;
/**
* @see {GetExtensionLoggerOpts.logConsole}
*/
logConsole?: boolean;
/**
* The vscode's extension subscriptions
* This is normally available via the `activate` function's `context`
* parameter.
*/
subscriptions: ExtensionContext["subscriptions"];
/**
* The `vscode.workspace.getConfiguration` method.
* Note this is the method itself, not the returned value from executing it.
*/
getConfiguration: typeof workspace.getConfiguration;
/**
* The `vscode.workspace.onDidChangeConfiguration` method.
* Note this is the method itself, not the returned value from executing it.
*/
onDidChangeConfiguration: typeof workspace.onDidChangeConfiguration;
}

/**
* The main opinionated wrapper utility.
* This will do the following:
*
* 1. Initialize an @vscode-logging/logger instance.
* 2. Log the initial file `logPath` and `logLevel`.
* 3. Register a listener for VSCode workspace configuration changes
* for the `logLevel` and `sourceLocationTracking`
*
* - Note that this utility is slightly opinionated and has more more restrictive
* than the @vscode-logging/logger APIs, e.g:
* 1. `logPath` param is mandatory.
* 2. default logLevel (if none is found in the workspace configuration) is `error`.
* 3. ...
*/
export function configureLogger(opts: ConfigureLoggerOpts): IVSCodeExtLogger;
Loading

0 comments on commit 0820834

Please sign in to comment.