swaf/src/Logger.ts

137 lines
4.4 KiB
TypeScript

import config from "config";
import {v4 as uuid} from "uuid";
import Log from "./models/Log";
import {bufferToUUID} from "./Utils";
export default class Logger {
private static logLevel: LogLevelKeys = <LogLevelKeys>config.get<string>('log_level');
private static dbLogLevel: LogLevelKeys = <LogLevelKeys>config.get<string>('db_log_level');
private static verboseMode: boolean = false;
public static verbose() {
this.verboseMode = true;
this.logLevel = <LogLevelKeys>LogLevel[LogLevel[this.logLevel] + 1] || this.logLevel;
this.dbLogLevel = <LogLevelKeys>LogLevel[LogLevel[this.dbLogLevel] + 1] || this.dbLogLevel;
Logger.info('Verbose mode');
}
public static isVerboseMode(): boolean {
return this.verboseMode;
}
public static silentError(error: Error, ...message: any[]): string {
return this.log('ERROR', message, error, true) || '';
}
public static error(error: Error, ...message: any[]): string {
return this.log('ERROR', message, error) || '';
}
public static warn(...message: any[]) {
this.log('WARN', message);
}
public static info(...message: any[]) {
this.log('INFO', message);
}
public static debug(...message: any[]) {
this.log('DEBUG', message);
}
public static dev(...message: any[]) {
this.log('DEV', message);
}
private static log(level: LogLevelKeys, message: any[], error?: Error, silent: boolean = false): string | null {
const levelIndex = LogLevel[level];
if (levelIndex <= LogLevel[this.logLevel]) {
if (error) {
if (levelIndex > LogLevel.ERROR) this.warn(`Wrong log level ${level} with attached error.`);
} else {
if (levelIndex <= LogLevel.ERROR) this.warn(`No error attached with log level ${level}.`);
}
const computedMsg = message.map(v => {
if (typeof v === 'string') {
return v;
} else {
return JSON.stringify(v, (key: string, value: any) => {
if (value instanceof Object) {
if (value.type === 'Buffer') {
return `Buffer<${Buffer.from(value.data).toString('hex')}>`;
} else if (value !== v) {
return `[object Object]`;
}
}
if (typeof value === 'string' && value.length > 96) {
return value.substr(0, 96) + '...';
}
return value;
}, 4);
}
}).join(' ');
const shouldSaveToDB = levelIndex <= LogLevel[this.dbLogLevel];
let output = `[${level}] `;
const pad = output.length;
const logID = Buffer.alloc(16);
uuid({}, logID);
let strLogID = bufferToUUID(logID);
if (shouldSaveToDB) output += `${strLogID} - `;
output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad));
switch (level) {
case "ERROR":
if (silent || !error) {
console.error(output);
} else {
console.error(output, error);
}
break;
case "WARN":
console.warn(output);
break;
case "INFO":
console.info(output);
break;
case "DEBUG":
case "DEV":
console.debug(output);
break;
}
if (shouldSaveToDB) {
const log = Log.create({});
log.setLevel(level);
log.message = computedMsg;
log.setError(error);
log.setLogID(logID);
log.save().catch(err => {
if (!silent && err.message.indexOf('ECONNREFUSED') < 0) {
console.error({save_err: err, error});
}
});
}
return strLogID;
}
return null;
}
private constructor() {
}
}
export enum LogLevel {
ERROR,
WARN,
INFO,
DEBUG,
DEV,
}
export type LogLevelKeys = keyof typeof LogLevel;