Compare commits

..

18 Commits

Author SHA1 Message Date
Rainer Killinger
aac8e584a9 1.1.1 2022-11-08 15:06:51 +01:00
Rainer Killinger
8d6ea040c1 fix: removing transformations in production 2022-11-08 15:04:53 +01:00
Rainer Killinger
e0f4ce134d docs: update changelog 2022-11-01 19:32:43 +01:00
Rainer Killinger
276e6d3b40 1.1.0 2022-11-01 19:32:42 +01:00
Rainer Killinger
ae0612c6d5 refactor: update dependencies 2022-11-01 19:19:10 +01:00
Rainer Killinger
8aef5b8d5b fix: compatibility with log aggregators 2022-11-01 19:15:32 +01:00
openstappsbot
107d94d499 refactor: update all 2022-10-24 07:16:13 +00:00
Rainer Killinger
7eb727ea27 docs: update changelog 2022-10-12 12:16:22 +02:00
Rainer Killinger
134c2e4c84 1.0.1 2022-10-12 12:16:21 +02:00
openstappsbot
60bc460841 refactor: update typescript-eslint monorepo to v5.40.0 2022-10-11 15:43:41 +00:00
openstappsbot
c8be14f9d8 refactor: update all 2022-10-11 07:22:17 +00:00
Rainer Killinger
e14b1248d5 ci: add cobertura coverage report 2022-08-17 11:32:18 +02:00
Rainer Killinger
734c6ec262 docs: update changelog 2022-08-17 10:17:40 +02:00
Rainer Killinger
6c51f777dd 1.0.0 2022-08-17 10:17:39 +02:00
Rainer Killinger
82a3651fb3 test: move to @testdeck/mocha 2022-08-17 10:13:26 +02:00
Rainer Killinger
e6e75db3e8 refactor: update to typescript 4.4.4 2022-08-17 10:01:47 +02:00
openstappsbot
eeda6ef26c refactor: update all 2022-08-16 07:14:31 +00:00
Rainer Killinger
73e331cd94 docs: update changelog 2022-05-27 16:07:21 +02:00
22 changed files with 1690 additions and 1115 deletions

2
.eslintignore Normal file
View File

@@ -0,0 +1,2 @@
resources
openapi

3
.eslintrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "@openstapps"
}

View File

@@ -6,7 +6,7 @@ cache:
- node_modules
before_script:
- npm install
- npm ci
stages:
- build
@@ -27,9 +27,12 @@ test:
stage: test
script:
- npm test
coverage: '/Statements[^:]*\:[^:]*\s+([\d\.]+)%/'
artifacts:
paths:
- coverage
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
audit:
stage: test

View File

@@ -1,3 +1,24 @@
# [1.1.0](https://gitlab.com/openstapps/logger/compare/v1.0.1...v1.1.0) (2022-11-01)
### Bug Fixes
* compatibility with log aggregators ([8aef5b8](https://gitlab.com/openstapps/logger/commit/8aef5b8d5b5fe4ed4ff7f17fd679ebdf83381001))
## [1.0.1](https://gitlab.com/openstapps/logger/compare/v1.0.0...v1.0.1) (2022-10-12)
# [1.0.0](https://gitlab.com/openstapps/logger/compare/v0.8.1...v1.0.0) (2022-08-17)
## [0.8.1](https://gitlab.com/openstapps/logger/compare/v0.8.0...v0.8.1) (2022-05-27)
# [0.8.0](https://gitlab.com/openstapps/logger/compare/v0.7.0...v0.8.0) (2021-12-14)

View File

@@ -22,8 +22,7 @@ To select your desired log levels add the corresponding numbers and set the valu
For example `STAPPS_LOG_LEVEL=17` is 16 + 1 and would log everything that is `OK` or `INFO`.
If you want to use logger in production (`NODE_ENV=production`) and allow all transports to fail set
`ALLOW_NO_TRANSPORT` to `true`.
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.
@@ -52,7 +51,7 @@ Environment variables are:
## Transformations
By default the logger will only add the log level to the message.
By default the logger will only add the log level to the message. It will replace newlines with spaces and might skip some of your choosen Transformers when in production (`NODE_ENV=production`) for compatibility reasons with existing log aggregators and analyzers.
You can change this behavior by setting other Transformers via `Logger.setTransformations`. If you do so, mind the order of the transformers.

2384
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@openstapps/logger",
"version": "0.8.1",
"version": "1.1.1",
"description": "A cli logger with colors, loglevels and the possibility to use a transport system for errors",
"repository": {
"type": "git",
@@ -8,7 +8,7 @@
},
"license": "GPL-3.0-only",
"scripts": {
"build": "npm run tslint && npm run compile",
"build": "npm run lint && npm run compile",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md && git commit -m 'docs: update changelog'",
"check-configuration": "openstapps-configuration",
"compile": "rimraf lib && tsc && prepend lib/cli.js '#!/usr/bin/env node\n'",
@@ -17,8 +17,8 @@
"prepublishOnly": "npm ci && npm run build",
"preversion": "npm run prepublishOnly",
"push": "git push && git push origin \"v$npm_package_version\"",
"test": "nyc mocha --require ts-node/register --ui mocha-typescript 'test/**/*.spec.ts'",
"tslint": "tslint -p tsconfig.json -c tslint.json 'src/**/*.ts'"
"test": "nyc mocha 'test/**/*.spec.ts'",
"lint": "eslint --ext .ts src/"
},
"author": "Karl-Philipp Wulfert <krlwlfrt@gmail.com>",
"contributors": [
@@ -28,6 +28,43 @@
],
"typings": "./lib/logger.d.ts",
"main": "./lib/logger.js",
"dependencies": {
"@types/node": "14.18.32",
"@types/nodemailer": "6.4.6",
"chalk": "4.1.2",
"flatted": "3.2.7",
"moment": "2.29.4",
"nodemailer": "6.8.0"
},
"devDependencies": {
"@openstapps/configuration": "0.33.0",
"@openstapps/eslint-config": "1.1.0",
"@testdeck/mocha": "0.3.0",
"@types/chai": "4.3.3",
"@types/chai-as-promised": "7.1.5",
"@types/chai-spies": "1.0.3",
"@types/mocha": "10.0.0",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"chai": "4.3.6",
"chai-as-promised": "7.1.1",
"chai-spies": "1.0.0",
"conventional-changelog-cli": "2.2.2",
"eslint": "8.26.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-jsdoc": "39.4.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-unicorn": "43.0.2",
"mocha": "10.1.0",
"nyc": "15.1.0",
"prepend-file-cli": "1.0.6",
"prettier": "2.7.1",
"rimraf": "3.0.2",
"ts-node": "10.9.1",
"tslint": "6.1.3",
"typedoc": "0.22.18",
"typescript": "4.4.4"
},
"nyc": {
"all": true,
"branches": 95,
@@ -46,6 +83,7 @@
"lines": 95,
"per-file": true,
"reporter": [
"cobertura",
"html",
"text-summary"
],
@@ -53,33 +91,5 @@
"ts-node/register"
],
"statements": 95
},
"devDependencies": {
"@openstapps/configuration": "0.29.0",
"@types/chai": "4.3.1",
"@types/chai-as-promised": "7.1.5",
"@types/chai-spies": "1.0.3",
"@types/mocha": "9.1.1",
"chai": "4.3.6",
"chai-as-promised": "7.1.1",
"chai-spies": "1.0.0",
"conventional-changelog-cli": "2.2.2",
"mocha": "9.1.3",
"mocha-typescript": "1.1.17",
"nyc": "15.1.0",
"prepend-file-cli": "1.0.6",
"rimraf": "3.0.2",
"ts-node": "10.8.0",
"tslint": "6.1.3",
"typedoc": "0.22.15",
"typescript": "4.4.4"
},
"dependencies": {
"@types/node": "14.18.18",
"@types/nodemailer": "6.4.4",
"chalk": "4.1.2",
"flatted": "3.2.5",
"moment": "2.29.3",
"nodemailer": "6.7.5"
}
}

View File

@@ -20,41 +20,43 @@ import {Transport, VerifiableTransport} from './transport';
* Copied from https://stackoverflow.com/a/51365037
*/
export type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends Array<infer U> ?
Array<RecursivePartial<U>> :
T[P] extends object ? RecursivePartial<T[P]> : T[P];
[P in keyof T]?: T[P] extends Array<infer U>
? Array<RecursivePartial<U>>
: T[P] extends object
? RecursivePartial<T[P]>
: T[P];
};
/**
* Deletes all properties that are undefined from an object
*
* @param obj Object to delete undefined properties from
* @param object Object to delete undefined properties from
*/
export function deleteUndefinedProperties(obj: unknown): unknown {
export function deleteUndefinedProperties(object: unknown): unknown {
// return atomic data types and arrays (recursion anchor)
if (typeof obj !== 'object' || Array.isArray(obj)) {
return obj;
if (typeof object !== 'object' || Array.isArray(object)) {
return object;
}
// check each key
for (const key in obj) {
for (const key in object) {
/* istanbul ignore if */
if (!obj.hasOwnProperty(key)) {
if (!object.hasOwnProperty(key)) {
continue;
}
const indexedObj = obj as { [k: string]: unknown; };
const indexedObject = object as {[k: string]: unknown};
if (typeof indexedObj[key] === 'undefined') {
if (typeof indexedObject[key] === 'undefined') {
// delete undefined keys
delete indexedObj[key];
delete indexedObject[key];
} else {
// check recursive
indexedObj[key] = deleteUndefinedProperties(indexedObj[key]);
indexedObject[key] = deleteUndefinedProperties(indexedObject[key]);
}
}
return obj;
return object;
}
/**
@@ -68,9 +70,11 @@ export function isNodeEnvironment(): boolean {
* Checks if environment is productive
*/
export function isProductiveEnvironment(): boolean {
return typeof process.env === 'object'
&& typeof process.env.NODE_ENV !== 'undefined'
&& process.env.NODE_ENV === 'production';
return (
typeof process.env === 'object' &&
typeof process.env.NODE_ENV !== 'undefined' &&
process.env.NODE_ENV === 'production'
);
}
/**

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {stringify} from 'flatted';
import {isNodeEnvironment, isProductiveNodeEnvironment} from './common';
import {isNodeEnvironment, isProductiveEnvironment, isProductiveNodeEnvironment} from './common';
import {Transformation} from './transformation';
import {AddLogLevel} from './transformations/add-log-level';
import {Transport} from './transport';
@@ -24,7 +24,7 @@ import {Transport} from './transport';
* @param something Something to check
*/
// tslint:disable-next-line:completed-docs
function hasStAppsLogLevel(something: object): something is { STAPPS_LOG_LEVEL: number; } {
function hasStAppsLogLevel(something: object): something is {STAPPS_LOG_LEVEL: number} {
return 'STAPPS_LOG_LEVEL' in something;
}
@@ -34,7 +34,7 @@ function hasStAppsLogLevel(something: object): something is { STAPPS_LOG_LEVEL:
* @param something Something to check
*/
// tslint:disable-next-line:completed-docs
function hasStAppsExitLevel(something: object): something is { STAPPS_EXIT_LEVEL: number; } {
function hasStAppsExitLevel(something: object): something is {STAPPS_EXIT_LEVEL: number} {
return 'STAPPS_EXIT_LEVEL' in something;
}
@@ -72,13 +72,7 @@ export class Logger {
/**
* Log levels
*/
private static readonly logLevels: LogLevel[] = [
'INFO',
'LOG',
'WARN',
'ERROR',
'OK',
];
private static readonly logLevels: LogLevel[] = ['INFO', 'LOG', 'WARN', 'ERROR', 'OK'];
/**
* Log level sum, equivalent to all log levels enabled
@@ -88,9 +82,7 @@ export class Logger {
/**
* Transformers for log output
*/
private static transformations?: Transformation[] = [
new AddLogLevel(),
];
private static transformations?: Transformation[] = [new AddLogLevel()];
/**
* Transport for errors
@@ -99,11 +91,16 @@ export class Logger {
/**
* Apply transformations to an output
* Will strip newlines in production environment
*
* @param logLevel Log level of the output
* @param output Output to apply transformations to
*/
private static applyTransformers(logLevel: LogLevel, output: string): string {
if (isProductiveEnvironment()) {
output = output.replace(/[\n\r]/g, ' ');
}
if (!Array.isArray(Logger.transformations) || Logger.transformations.length === 0) {
return output;
}
@@ -147,8 +144,10 @@ export class Logger {
if (isProductiveNodeEnvironment()) {
return;
}
// tslint:disable-next-line: no-console
console.error(Logger.applyTransformers('ERROR', `exiting as of used exit level ${Logger.getLevel('EXIT')} !`));
// eslint-disable-next-line no-console
console.error(
Logger.applyTransformers('ERROR', `exiting as of used exit level ${Logger.getLevel('EXIT')} !`),
);
process.exit(-1);
}
@@ -171,7 +170,7 @@ export class Logger {
if (isNodeEnvironment() && typeof environmentLevel !== 'undefined') {
// Node.js environment exists
return parseInt(environmentLevel, 10);
return Number.parseInt(environmentLevel, 10);
}
// Fallback to log everything, or not exiting
@@ -195,23 +194,25 @@ export class Logger {
/**
* Log an error
*
* @param args Arguments to log
* @param arguments_ Arguments to log
*/
public static async error(...args: unknown[]): Promise<string | void> {
public static async error(...arguments_: unknown[]): Promise<string | void> {
if (!Logger.checkLogLevel('ERROR')) {
return;
}
/* tslint:disable-next-line:no-console */
console.error(Logger.applyTransformers('ERROR', Logger.stringifyArguments(...args)));
// eslint-disable-next-line no-console
console.error(Logger.applyTransformers('ERROR', Logger.stringifyArguments(...arguments_)));
if (isProductiveNodeEnvironment()) {
if (typeof Logger.transport !== 'undefined') {
return Logger.transport.send('Error', Logger.stringifyArguments(...args));
return Logger.transport.send('Error', Logger.stringifyArguments(...arguments_));
}
if (process.env.ALLOW_NO_TRANSPORT !== 'true') {
throw new Error(`Error couldn't be transported! Please set a transport or set ALLOW_NO_TRANSPORT='true'.`);
throw new Error(
`Error couldn't be transported! Please set a transport or set ALLOW_NO_TRANSPORT='true'.`,
);
}
}
if (Logger.checkExitLevel('ERROR')) {
@@ -222,15 +223,15 @@ export class Logger {
/**
* Log an information
*
* @param args Arguments to log
* @param arguments_ Arguments to log
*/
public static info(...args: unknown[]): void {
public static info(...arguments_: unknown[]): void {
if (!Logger.checkLogLevel('INFO')) {
return;
}
/* tslint:disable-next-line:no-console */
console.info(Logger.applyTransformers('INFO', Logger.stringifyArguments(...args)));
// eslint-disable-next-line no-console
console.info(Logger.applyTransformers('INFO', Logger.stringifyArguments(...arguments_)));
if (Logger.checkExitLevel('INFO')) {
Logger.exit();
}
@@ -252,15 +253,15 @@ export class Logger {
/**
* Log something
*
* @param args Arguments to log
* @param arguments_ Arguments to log
*/
public static log(...args: unknown[]): void {
public static log(...arguments_: unknown[]): void {
if (!Logger.checkLogLevel('LOG')) {
return;
}
/* tslint:disable-next-line:no-console */
console.log(Logger.applyTransformers('LOG', Logger.stringifyArguments(...args)));
// eslint-disable-next-line no-console
console.log(Logger.applyTransformers('LOG', Logger.stringifyArguments(...arguments_)));
if (Logger.checkExitLevel('LOG')) {
Logger.exit();
}
@@ -269,15 +270,15 @@ export class Logger {
/**
* Log something successful
*
* @param args Arguments to log
* @param arguments_ Arguments to log
*/
public static ok(...args: unknown[]): void {
public static ok(...arguments_: unknown[]): void {
if (!Logger.checkLogLevel('OK')) {
return;
}
/* tslint:disable-next-line:no-console */
console.log(Logger.applyTransformers('OK', Logger.stringifyArguments(...args)));
// eslint-disable-next-line no-console
console.log(Logger.applyTransformers('OK', Logger.stringifyArguments(...arguments_)));
if (Logger.checkExitLevel('OK')) {
Logger.exit();
}
@@ -289,7 +290,10 @@ export class Logger {
* @param transformations List of transformations
*/
public static setTransformations(transformations: Transformation[]) {
Logger.transformations = transformations;
const transforms = transformations.filter(transform =>
isProductiveEnvironment() ? transform.useInProduction === true : true,
);
Logger.transformations = transforms;
}
/**
@@ -304,12 +308,12 @@ export class Logger {
/**
* Stringify a list of arguments
*
* @param args Arguments to stringify
* @param arguments_ Arguments to stringify
*/
public static stringifyArguments(...args: unknown[]): string {
public static stringifyArguments(...arguments_: unknown[]): string {
const result: string[] = [];
args.forEach((argument) => {
for (const argument of arguments_) {
if (typeof argument === 'string' || typeof argument === 'number') {
result.push(argument.toString());
} else if (argument instanceof Error) {
@@ -318,10 +322,9 @@ export class Logger {
result.push(argument.stack);
}
} else {
// tslint:disable-next-line:no-magic-numbers
result.push(stringify(argument, null, 2));
result.push(stringify(argument, undefined, 2));
}
});
}
return result.join(', ');
}
@@ -329,15 +332,15 @@ export class Logger {
/**
* Log a warning
*
* @param args Arguments to log
* @param arguments_ Arguments to log
*/
public static warn(...args: unknown[]): void {
public static warn(...arguments_: unknown[]): void {
if (!Logger.checkLogLevel('WARN')) {
return;
}
/* tslint:disable-next-line:no-console */
console.warn(Logger.applyTransformers('WARN', Logger.stringifyArguments(...args)));
// eslint-disable-next-line no-console
console.warn(Logger.applyTransformers('WARN', Logger.stringifyArguments(...arguments_)));
if (Logger.checkExitLevel('WARN')) {
Logger.exit();
}

View File

@@ -138,8 +138,8 @@ export class SMTP extends VerifiableTransport {
if (!isProductiveEnvironment() || process.env.ALLOW_NO_TRANSPORT === 'true') {
try {
SMTP._instance = new SMTP(config);
} catch (err) {
/* tslint:disable-next-line:no-console */
} catch {
// eslint-disable-next-line no-console
console.warn('SMTP config failed.');
return;
@@ -163,7 +163,9 @@ export class SMTP extends VerifiableTransport {
*/
public static isValidEmailAddress(address: string): boolean {
// tslint:disable-next-line:max-line-length
return /^(([^<>()\[\].,;:\s@"]+(\.[^<>()\[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i.test(address);
return /^(([^<>()\[\].,;:\s@"]+(\.[^<>()\[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i.test(
address,
);
}
/**
@@ -184,18 +186,18 @@ export class SMTP extends VerifiableTransport {
*/
private constructor(smtpConfig?: SMTPConfig) {
// create a partial config from environment variables that can overwrite the given config
const envConfig: RecursivePartial<SMTPConfig> = {
const environmentConfig: RecursivePartial<SMTPConfig> = {
auth: {
password: process.env.SMTP_AUTH_PASSWORD,
user: process.env.SMTP_AUTH_USER,
},
cc: ((typeof process.env.SMTP_CC !== 'undefined') ? (process.env.SMTP_CC as string).split(',') : []),
cc: typeof process.env.SMTP_CC !== 'undefined' ? (process.env.SMTP_CC as string).split(',') : [],
host: process.env.SMTP_HOST,
port: (typeof process.env.SMTP_PORT !== 'undefined') ? parseInt(process.env.SMTP_PORT, 10) : undefined,
recipients: (typeof process.env.SMTP_RECIPIENTS !== 'undefined') ?
(process.env.SMTP_RECIPIENTS).split(',') :
[],
secure: (typeof process.env.SMTP_SECURE !== 'undefined') ? (process.env.SMTP_SECURE === 'true') : false,
port:
typeof process.env.SMTP_PORT !== 'undefined' ? Number.parseInt(process.env.SMTP_PORT, 10) : undefined,
recipients:
typeof process.env.SMTP_RECIPIENTS !== 'undefined' ? process.env.SMTP_RECIPIENTS.split(',') : [],
secure: typeof process.env.SMTP_SECURE !== 'undefined' ? process.env.SMTP_SECURE === 'true' : false,
sender: {
mail: process.env.SMTP_SENDER_MAIL,
name: process.env.SMTP_SENDER_NAME,
@@ -205,49 +207,49 @@ export class SMTP extends VerifiableTransport {
const config = {
...smtpConfig,
// deleting undefined properties so the actual config doesn't get overwritten by undefined values
...(deleteUndefinedProperties(envConfig) as object),
...(deleteUndefinedProperties(environmentConfig) as object),
} as SMTPConfig;
if (typeof config.host === 'undefined') {
throw new Error(
throw new TypeError(
'SMTP configuration needs a host. Add it to the config or use environment variables (SMTP_HOST).',
);
}
if (typeof config.port === 'undefined' || isNaN(config.port)) {
throw new Error(
if (typeof config.port === 'undefined' || Number.isNaN(config.port)) {
throw new TypeError(
'SMTP configuration needs a port. Add it to the config or use environment variables (SMTP_PORT).',
);
}
if (typeof config.auth !== 'object') {
throw new Error(
throw new TypeError(
'SMTP configuration needs an auth object.' +
'Add it to the config or use environment variables (SMTP_AUTH_USER, SMTP_AUTH_PASSWORD).',
'Add it to the config or use environment variables (SMTP_AUTH_USER, SMTP_AUTH_PASSWORD).',
);
}
if (typeof config.auth.user === 'undefined') {
throw new Error(
throw new TypeError(
'SMTP auth configuration needs a user. Add it to the config or use environment variables (SMTP_AUTH_USER).',
);
}
if (typeof config.auth.password === 'undefined') {
throw new Error(
throw new TypeError(
'SMTP auth configuration needs a password.' +
'Add it to the config or use environment variables (SMTP_AUTH_PASSWORD).',
'Add it to the config or use environment variables (SMTP_AUTH_PASSWORD).',
);
}
if (Array.isArray(config.recipients) && config.recipients.length < 1) {
if (Array.isArray(config.recipients) && config.recipients.length === 0) {
throw new Error(
'SMTP configuration needs recipients. Add it to the config or use environment variables (SMTP_RECIPIENTS).',
);
}
if (typeof config.sender.mail === 'undefined') {
throw new Error(
throw new TypeError(
'SMTP configuration needs a sender. Add it to the config or use environment variables (SMTP_SENDER_MAIL).',
);
}
@@ -304,7 +306,7 @@ export class SMTP extends VerifiableTransport {
return this.sendMail({
cc: this.cc,
// use an address block if name is available, mail otherwise
from: (typeof this.from.name !== 'string') ? `${this.from.name} <${this.from.mail}>` : this.from.mail,
from: typeof this.from.name !== 'string' ? `${this.from.name} <${this.from.mail}>` : this.from.mail,
subject: subject,
text: message,
to: this.recipients,
@@ -341,20 +343,19 @@ export class SMTP extends VerifiableTransport {
* @returns true if the transport is valid
*/
public async verify(): Promise<boolean> {
let verificationSuccessfull = false;
try {
verificationSuccessfull = await this.transportAgent.verify();
} catch (err) {
} catch (error) {
if (!isProductiveEnvironment() || process.env.ALLOW_NO_TRANSPORT !== 'true') {
throw err;
throw error;
}
/* tslint:disable-next-line:no-console */
// eslint-disable-next-line no-console
console.warn(
'SMTP verification error was ignored, because tranport failures are allowed: ',
(err as Error).message,
'SMTP verification error was ignored, because tranport failures are allowed:',
(error as Error).message,
);
}
@@ -362,12 +363,12 @@ export class SMTP extends VerifiableTransport {
if (!isProductiveEnvironment() || process.env.ALLOW_NO_TRANSPORT !== 'true') {
throw new Error(
'Verification of SMTP transport failed.' +
'If you want to ignore this error set' +
'`NODE_ENV=dev` or `ALLOW_NO_TRANSPORT=true`',
'If you want to ignore this error set' +
'`NODE_ENV=dev` or `ALLOW_NO_TRANSPORT=true`',
);
}
/* tslint:disable-next-line:no-console */
// eslint-disable-next-line no-console
console.warn('SMTP verification error was ignored, because tranport failures are allowed.');
}
this.verified = verificationSuccessfull;

View File

@@ -18,6 +18,11 @@ import {LogLevel} from './logger';
* A transformer for log output
*/
export interface Transformation {
/**
* Indicates if this transformation is stripped in production environments
*/
useInProduction: boolean;
/**
* Transform an output
*

View File

@@ -19,6 +19,11 @@ import {Transformation} from '../transformation';
* Transformation that adds the log level to output
*/
export class AddLogLevel implements Transformation {
/**
* Keep this transformation in production environments
*/
useInProduction = true;
/**
* Add log level to output
*

View File

@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import chalk, {Chalk} from 'chalk';
import chalk from 'chalk';
import {LogLevel} from '../logger';
import {Transformation} from '../transformation';
@@ -20,18 +20,25 @@ import {Transformation} from '../transformation';
* Transformation that colorizes log output
*/
export class Colorize implements Transformation {
/**
* Skip this transformation in production environments
*/
useInProduction = false;
/**
* Instantiate a new colorize transformation
*
* @param logLevelToColor Map from log level to color transformation to apply
*/
constructor(private readonly logLevelToColor: { [k in LogLevel]: Chalk; } = {
ERROR: chalk.bold.red,
INFO: chalk.cyan,
LOG: chalk.white,
OK: chalk.bold.green,
WARN: chalk.yellow,
}) {
constructor(
private readonly logLevelToColor: {[k in LogLevel]: chalk.Chalk} = {
ERROR: chalk.bold.red,
INFO: chalk.cyan,
LOG: chalk.white,
OK: chalk.bold.green,
WARN: chalk.yellow,
},
) {
// noop
}

View File

@@ -14,20 +14,15 @@
*/
import {LogLevel} from '../logger';
import {Transformation} from '../transformation';
/**
* Transformation that adds a timestamp to output
*/
export class Timestamp implements Transformation {
/**
* Instantiate a new timestamp transformation
*
* @see https://momentjs.com/docs/#/displaying/format/
*
* @param format Format for timestamps
* Keep this transformation in production environments
*/
constructor(private readonly format = 'LLLL') {
// noop
}
useInProduction = true;
/**
* Add timestamp to output
@@ -36,9 +31,6 @@ export class Timestamp implements Transformation {
* @param output Output to add timestamp to
*/
transform(_logLevel: LogLevel, output: string): string {
const moment = require('moment');
const now = moment();
return `[${now.format(this.format)}] ${output}`;
return `[${new Date().toISOString()}] ${output}`;
}
}

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {suite, test} from 'mocha-typescript';
import {suite, test} from '@testdeck/mocha';
import {
deleteUndefinedProperties,
isNodeEnvironment,

View File

@@ -16,9 +16,10 @@ import chai from 'chai';
import {expect} from 'chai';
import chaiAsPromised from 'chai-as-promised';
import chaiSpies from 'chai-spies';
import {suite} from 'mocha-typescript';
import {suite, test} from '@testdeck/mocha';
import {Logger} from '../src/logger';
import {AddLogLevel} from '../src/transformations/add-log-level';
import {Colorize} from '../src/transformations/colorize';
import {DummyTransport} from './dummyTransport';
chai.should();
@@ -236,6 +237,34 @@ export class LoggerSpec {
process.env.NODE_ENV = nodeEnv;
}
@test
'is compatible with log aggregation in productive environment'() {
Logger.setTransformations([new AddLogLevel(), new Colorize()]);
let spy = LoggerSpec.sandbox.on(console, 'log', () => {
// noop
});
Logger.log('Foo\nbar');
expect(spy).to.have.been.called.once;
expect(spy.__spy.calls[0][0]).to.equal('\u001B[37m[LOG] Foo\u001B[39m\n\u001B[37mbar\u001B[39m');
const nodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'production';
process.env.ALLOW_NO_TRANSPORT = 'true';
Logger.setTransformations([new AddLogLevel(), new Colorize()]);
Logger.log('Foo\nbar');
expect(spy).to.have.been.called.twice;
expect(spy.__spy.calls[1][0]).to.equal('[LOG] Foo bar');
process.env.NODE_ENV = nodeEnv;
delete process.env.ALLOW_NO_TRANSPORT;
}
@test
log() {
const spy = LoggerSpec.sandbox.on(console, 'log', () => {
@@ -443,7 +472,7 @@ export class LoggerSpec {
const stub = LoggerSpec.sandbox.on(console, 'log', () => {
// noop
});
const applyTransformationsSpy = LoggerSpec.sandbox.on(Logger, 'applyTransformations');
const applyTransformationsSpy = LoggerSpec.sandbox.on(new Logger(), 'applyTransformations');
Logger.log('Foobar');

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {suite, test} from 'mocha-typescript';
import {suite, test} from '@testdeck/mocha';
import {SMTP} from '../src/smtp';
@suite()

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {suite, test} from 'mocha-typescript';
import {suite, test} from '@testdeck/mocha';
import {AddLogLevel} from '../../src/transformations/add-log-level';
@suite()

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {suite, test} from 'mocha-typescript';
import {suite, test} from '@testdeck/mocha';
import {Colorize} from '../../src/transformations/colorize';
@suite()

View File

@@ -13,23 +13,16 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {suite, test} from 'mocha-typescript';
import {suite, test} from '@testdeck/mocha';
import {Timestamp} from '../../src/transformations/timestamp';
import moment = require('moment');
@suite()
export class ColorizeSpec {
export class TimeStampSpec {
@test
'default'() {
const transformation = new Timestamp();
expect(transformation.transform('ERROR', 'Foobar')).to.be.equal(`[${moment().format('LLLL')}] Foobar`);
}
@test
'different format'() {
const transformation = new Timestamp('DD.MM.YYYY');
expect(transformation.transform('ERROR', 'Foobar')).to.be.equal(`[${moment().format('DD.MM.YYYY')}] Foobar`);
expect(transformation.transform('ERROR', 'Foobar')).to.be.contain(`Z`);
}
}

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {suite, test} from 'mocha-typescript';
import {suite, test} from '@testdeck/mocha';
import {isTransportWithVerification} from '../src/common';
import {DummyTransport, VerifiableDummyTransport} from './dummyTransport';

View File

@@ -1,6 +0,0 @@
{
"extends": "./node_modules/@openstapps/configuration/tslint.json",
"rules": {
"no-redundant-jsdoc": false
}
}