feat: add EXIT log level

This commit is contained in:
Rainer Killinger
2020-03-10 10:54:09 +01:00
committed by Rainer Killinger
parent 3fb99ad896
commit edc6e6fad5
6 changed files with 923 additions and 932 deletions

View File

@@ -25,6 +25,8 @@ For example `STAPPS_LOG_LEVEL=17` is 16 + 1 and would log everything that is `OK
If you want to use logger in production (`NODE_ENV=production`) and allow all transports to fail set
`ALLOW_NO_TRANSPORT` to `true`.
Additionally setting the environment variable `STAPPS_EXIT_LEVEL` which works in the same manner as `STAPPS_LOG_LEVEL` will terminate your process after logging at the selected level(s) (usefull for integration tests). It will be ignored in afore mentioned productive environments.
## SMTP
This class also provides a simple implementation of an SMTP transport which can be used as a

1673
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,8 @@
"author": "Karl-Philipp Wulfert <krlwlfrt@gmail.com>",
"contributors": [
"Anselm Stordeur <anselmstordeur@gmail.com>",
"Jovan Krunic <jovan.krunic@gmail.com>"
"Jovan Krunic <jovan.krunic@gmail.com>",
"Rainer Killinger<mail-openstapps@killinger.co>"
],
"typings": "./lib/logger.d.ts",
"main": "./lib/logger.js",

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 StApps
* Copyright (C) 2019-2020 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -28,6 +28,21 @@ function hasStAppsLogLevel(something: object): something is { STAPPS_LOG_LEVEL:
return 'STAPPS_LOG_LEVEL' in something;
}
/**
* Check if something has property STAPPS_EXIT_LEVEL
*
* @param something Something to check
*/
// tslint:disable-next-line:completed-docs
function hasStAppsExitLevel(something: object): something is { STAPPS_EXIT_LEVEL: number; } {
return 'STAPPS_EXIT_LEVEL' in something;
}
/**
* A level descriptor for either log or exit level
*/
export type Level = 'LOG' | 'EXIT';
/**
* A log level
*/
@@ -101,34 +116,80 @@ export class Logger {
return transformedOutput;
}
/**
* Check if intended exit level is allowed in environment exit level
*
* @param exitLevel Log level to check
*/
private static checkExitLevel(exitLevel: LogLevel): boolean {
if (Logger.getLevel('EXIT') === 0) {
return false;
}
// tslint:disable-next-line:no-bitwise
return (Logger.getLevel('EXIT') & Logger.logLevelNumber(exitLevel)) === Logger.logLevelNumber(exitLevel);
}
/**
* Check if intended log level is allowed in environment log level
*
* @param logLevel Log level to check
*/
private static checkLogLevel(logLevel: LogLevel): boolean {
const logLevelNumber = Math.pow(Logger.binaryBase, Logger.logLevels.indexOf(logLevel));
// tslint:disable-next-line:no-bitwise
return (Logger.getLogLevel() & logLevelNumber) === logLevelNumber;
return (Logger.getLevel('LOG') & Logger.logLevelNumber(logLevel)) === Logger.logLevelNumber(logLevel);
}
/**
* Notify about exit and end process
*/
private static exit(): void {
if (isProductiveNodeEnvironment()) {
return;
}
// tslint:disable-next-line: no-console
console.error(Logger.applyTransformers('ERROR', `exiting as of used exit level ${Logger.getLevel('EXIT')} !`));
process.exit(-1);
}
/**
* Return log level from environment
*/
private static getLogLevel(): number {
if (isNodeEnvironment() && typeof process.env.STAPPS_LOG_LEVEL !== 'undefined') {
// Node.js environment exists
return parseInt(process.env.STAPPS_LOG_LEVEL, 10);
}
if (typeof window !== 'undefined' && hasStAppsLogLevel(window)) {
private static getLevel(level: Level): number {
if (typeof window !== 'undefined') {
// browser environment exists
return window.STAPPS_LOG_LEVEL;
if (hasStAppsLogLevel(window)) {
return window.STAPPS_LOG_LEVEL;
}
if (hasStAppsExitLevel(window)) {
return window.STAPPS_EXIT_LEVEL;
}
}
// Log everything
return Logger.logLevelSum;
const environmentLevel = level === 'LOG' ? process.env.STAPPS_LOG_LEVEL : process.env.STAPPS_EXIT_LEVEL;
if (isNodeEnvironment() && typeof environmentLevel !== 'undefined') {
// Node.js environment exists
return parseInt(environmentLevel, 10);
}
// Fallback to log everything, or not exiting
switch (level) {
case 'LOG':
return Logger.logLevelSum;
case 'EXIT':
return 0;
}
}
/**
* Get number of specific log level
*
* @param logLevel Log level to check
*/
private static logLevelNumber(logLevel: LogLevel): number {
return Math.pow(Logger.binaryBase, Logger.logLevels.indexOf(logLevel));
}
/**
@@ -153,6 +214,9 @@ export class Logger {
throw new Error(`Error couldn't be transported! Please set a transport or set ALLOW_NO_TRANSPORT='true'.`);
}
}
if (Logger.checkExitLevel('ERROR')) {
Logger.exit();
}
}
/**
@@ -167,6 +231,9 @@ export class Logger {
/* tslint:disable-next-line:no-console */
console.info(Logger.applyTransformers('INFO', Logger.stringifyArguments(...args)));
if (Logger.checkExitLevel('INFO')) {
Logger.exit();
}
}
/**
@@ -194,6 +261,9 @@ export class Logger {
/* tslint:disable-next-line:no-console */
console.log(Logger.applyTransformers('LOG', Logger.stringifyArguments(...args)));
if (Logger.checkExitLevel('LOG')) {
Logger.exit();
}
}
/**
@@ -208,6 +278,9 @@ export class Logger {
/* tslint:disable-next-line:no-console */
console.log(Logger.applyTransformers('OK', Logger.stringifyArguments(...args)));
if (Logger.checkExitLevel('OK')) {
Logger.exit();
}
}
/**
@@ -265,5 +338,8 @@ export class Logger {
/* tslint:disable-next-line:no-console */
console.warn(Logger.applyTransformers('WARN', Logger.stringifyArguments(...args)));
if (Logger.checkExitLevel('WARN')) {
Logger.exit();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 StApps
* Copyright (C) 2019-2020 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.

View File

@@ -45,7 +45,8 @@ export class LoggerSpec {
@test
async 'default log level'() {
expect((Logger as any).getLogLevel()).to.be.equal(31);
expect((Logger as any).getLevel('LOG')).to.be.equal(31);
expect((Logger as any).getLevel('EXIT')).to.be.equal(0);
}
@test
@@ -131,6 +132,50 @@ export class LoggerSpec {
expect(spy.__spy.calls[0][0]).to.contain('Foobar');
}
@test
async exits() {
const infoSpy = LoggerSpec.sandbox.on(console, 'info', () => {
// noop
});
const logSpy = LoggerSpec.sandbox.on(console, 'log', () => {
// noop
});
const warnSpy = LoggerSpec.sandbox.on(console, 'warn', () => {
// noop
});
const errorSpy = LoggerSpec.sandbox.on(console, 'error', () => {
// noop
});
const processSpy = LoggerSpec.sandbox.on(process, 'exit', () => {
// noop
});
const exitLevel = process.env.STAPPS_EXIT_LEVEL;
process.env.STAPPS_EXIT_LEVEL = '31';
Logger.info('Foobar');
Logger.log('Foobar');
Logger.warn('Foobar');
Logger.ok('Foobar');
await Logger.error('Foobar');
expect(infoSpy).to.have.been.called.once;
expect(infoSpy.__spy.calls[0][0]).to.contain('[INFO]');
expect(infoSpy.__spy.calls[0][0]).to.contain('Foobar');
expect(logSpy).to.have.been.called.twice;
expect(warnSpy).to.have.been.called.once;
expect(warnSpy.__spy.calls[0][0]).to.contain('[WARN]');
expect(warnSpy.__spy.calls[0][0]).to.contain('Foobar');
expect(errorSpy).to.have.been.called.exactly(6);
expect(processSpy).to.have.been.called.exactly(5);
process.env.STAPPS_EXIT_LEVEL = exitLevel;
}
@test
'info without output'() {
const spy = LoggerSpec.sandbox.on(console, 'info', () => {
@@ -343,6 +388,30 @@ export class LoggerSpec {
delete process.env.STAPPS_LOG_LEVEL;
}
@test
getExitLevel() {
const savedProcess = process;
// @ts-ignore
process = undefined;
(global as any).window = {
STAPPS_EXIT_LEVEL: 0,
};
const stub = LoggerSpec.sandbox.on(console, 'info', () => {
// noop
});
Logger.info('Foobar');
process = savedProcess;
delete (global as any).window;
expect(stub).not.to.have.been.called();
}
@test
getLogLevel() {
const savedProcess = process;