import * as util from "util"; import * as fs from "fs"; import { EventEmitter } from "events"; import * as path from "path"; const Reset = "\x1b[0m" const Bright = "\x1b[1m" const Dim = "\x1b[2m" const Underscore = "\x1b[4m" const Blink = "\x1b[5m" const Reverse = "\x1b[7m" const Hidden = "\x1b[8m" const FgBlack = "\x1b[30m" const FgRed = "\x1b[31m" const FgGreen = "\x1b[32m" const FgYellow = "\x1b[33m" const FgBlue = "\x1b[34m" const FgMagenta = "\x1b[35m" const FgCyan = "\x1b[36m" const FgWhite = "\x1b[37m" const BgBlack = "\x1b[40m" const BgRed = "\x1b[41m" const BgGreen = "\x1b[42m" const BgYellow = "\x1b[43m" const BgBlue = "\x1b[44m" const BgMagenta = "\x1b[45m" const BgCyan = "\x1b[46m" const BgWhite = "\x1b[47m" export class Logging { private static logFileLocation: string = "./logs/"; private static stdout: boolean = true; private static fileStream: fs.WriteStream; private static errorStream: fs.WriteStream; private static writing = false; private static queue = new Array<{ message: string, error: boolean }>(); static events: EventEmitter = new EventEmitter(); static config(logfolder: string, stdout: boolean) { this.logFileLocation = logfolder; this.stdout = stdout; } static debug(...message: any[]) { Logging.message(LoggingTypes.Debug, message); } static log(...message: any[]) { Logging.message(LoggingTypes.Log, message); } static warning(...message: any[]) { Logging.message(LoggingTypes.Log, message); } static logWithCustomColors(type: LoggingTypes, colors: string, ...message: any[]) { Logging.message(type, message, colors); } static error(error: Error | string) { if (typeof error === "string") { Logging.errorMessage(error); return; } let m = ""; (error.stack).forEach(e => { m += e.toString() + "\n"; }) var message = error.name + " " + error.message + "\n" + m; Logging.message(LoggingTypes.Error, [message]); } static errorMessage(...message: string[]) { Logging.message(LoggingTypes.Error, message); } private static async message(type: LoggingTypes, message: any[] | string, customColors?: string) { var consoleLogFormat = Reset; if (!customColors) { switch (type) { case LoggingTypes.Log: //m += FgWhite + BgBlack; break; case LoggingTypes.Error: consoleLogFormat += FgRed;//FgWhite + BgRed + FgWhite; break; case LoggingTypes.Debug: consoleLogFormat += FgCyan; break; case LoggingTypes.Warning: consoleLogFormat += FgYellow; break; } } else { consoleLogFormat += customColors; } var mb = ""; if (typeof message === "string") { mb = message; } else { message.forEach(e => { if (typeof e !== "string") e = util.inspect(e, false, null); if (e.endsWith("\n")) { mb += e; } else { mb += e + " "; } }); } var m = "[" + LoggingTypes[type] + "][" + _getCallerFile() + "][" + new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '') + "]: " + mb; if (this.logFileLocation) { if (!this.fileStream || !this.errorStream) { await Logging.initializeFile(); } Logging.writeMessageToFile(m, type === LoggingTypes.Error); } Logging.events.emit("message", { type: type, message: mb }); if (this.stdout) console.log(consoleLogFormat + m + Reset); } private static writeMessageToFile(message: string, error?: boolean) { Logging.queue.push({ message: message.replace("\n", " "), error: error }); Logging.checkQueue(); } private static checkQueue() { if (Logging.writing) return; if (Logging.queue.length <= 0) return; Logging.writing = true; var message = Logging.queue[0]; Logging.fileStream.write(message.message + "\n", () => { if (message.error) { Logging.errorStream.write(message.message + "\n", () => { Logging.queue.splice(Logging.queue.indexOf(message), 1); Logging.writing = false; Logging.checkQueue(); }); } else { Logging.queue.splice(Logging.queue.indexOf(message), 1); Logging.writing = false; Logging.checkQueue(); } }); } private static async initializeFile() { if (this.fileStream && this.errorStream) return; if (!this.logFileLocation) return; try { var exists = util.promisify(fs.exists); await new Promise((resolve, reject) => { fs.exists(this.logFileLocation, (exists) => { if (!exists) { fs.mkdir(this.logFileLocation, (err) => { if (err) { reject(err); } else { resolve(); } }); } else resolve(); }); }); Logging.fileStream = fs.createWriteStream(this.logFileLocation + "all.log", { flags: "a" }); Logging.fileStream.write("\n"); Logging.errorStream = fs.createWriteStream(this.logFileLocation + "error.log", { flags: "a" }); Logging.errorStream.write("\n"); } catch (e) { console.log(e); } } } function _getCallerFile() { try { var err = new Error(); var caller_file: string; var current_file: string; (Error).prepareStackTrace = function (err, stack) { return stack; }; current_file = (err.stack).shift().getFileName(); while (err.stack.length) { caller_file = (err.stack).shift().getFileName(); if (current_file !== caller_file) return path.basename(caller_file); } } catch (err) { } return undefined; } export enum LoggingTypes { Log, Warning, Error, Debug }