2022-05-02 19:31:47 +02:00
|
|
|
const conversion = require("./conversion");
|
|
|
|
|
|
|
|
class Logger {
|
|
|
|
/** Logger
|
|
|
|
*
|
|
|
|
* @param {{
|
2022-05-08 02:34:16 +02:00
|
|
|
* output: NodeJS.WritableStream | {exclusivity: [level: string], stream: NodeJS.WritableStream, noColors: boolean},
|
|
|
|
* outputs: NodeJS.WritableStream[] | Array<{exclusivity: [level: string], stream: NodeJS.WritableStream, noColors: boolean}>,
|
2022-05-07 16:07:00 +02:00
|
|
|
* template: string,
|
|
|
|
* levelsColors: {[level: string]: string},
|
|
|
|
* historySize: number,
|
|
|
|
* onHistoryFull: () => void,
|
|
|
|
* argsPlaceholder: string,
|
2022-05-08 00:23:38 +02:00
|
|
|
* defaultLevel: string,
|
2022-05-08 02:34:16 +02:00
|
|
|
* dict: Map<string, string>
|
2022-05-02 19:31:47 +02:00
|
|
|
* }} options
|
|
|
|
*/
|
|
|
|
constructor(options = {})
|
|
|
|
{
|
|
|
|
this.output = options.output || process.stdout;
|
2022-05-08 02:34:16 +02:00
|
|
|
this.outputs = options.outputs || [];
|
2022-05-02 19:31:47 +02:00
|
|
|
this.template = options.template || "[{level} {timestamp}] {message}";
|
2022-05-07 16:07:00 +02:00
|
|
|
this.levelsColors = options.levelsColors || { // no same colors
|
2022-05-02 19:31:47 +02:00
|
|
|
debug: "\x1b[32m",
|
|
|
|
info: "\x1b[36m",
|
|
|
|
warn: "\x1b[33m",
|
2022-05-02 19:31:57 +02:00
|
|
|
"warn;": "\x1b[33m",
|
2022-05-02 19:31:47 +02:00
|
|
|
error: "\x1b[31m",
|
|
|
|
fatal: "\x1b[35m"
|
|
|
|
};
|
|
|
|
this.dict = options.dict || null;
|
|
|
|
this.argsPlaceholder = options.argsPlaceholder || "{}";
|
|
|
|
this.defaultLevel = options.defaultLevel || "info";
|
|
|
|
this.history = [];
|
|
|
|
this.historySize = options.historySize || 100;
|
|
|
|
this.onHistoryFull = options.onHistoryFull || function() {
|
2022-05-02 19:31:57 +02:00
|
|
|
this.alog("warn;", "History is full, dropping 25 oldest entries.");
|
|
|
|
this.history = this.history.slice(25);
|
2022-05-02 19:31:47 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/** log
|
|
|
|
*
|
|
|
|
* @param {string} message
|
|
|
|
* @param {any} ...args
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
log (message, ...args)
|
2022-05-07 16:07:00 +02:00
|
|
|
{this.alog(this.defaultLevel, message, ...args);}
|
2022-05-02 19:31:47 +02:00
|
|
|
|
|
|
|
/** alog
|
|
|
|
*
|
2022-05-07 16:07:00 +02:00
|
|
|
* @param {'debug' | 'info' | 'warn' | 'error' | 'fatal'} level
|
2022-05-02 19:31:47 +02:00
|
|
|
* @param {string} message
|
|
|
|
* @param {any} ...args
|
|
|
|
*
|
|
|
|
*/
|
2022-05-07 16:07:00 +02:00
|
|
|
async alog(level, message, ...args)
|
2022-05-02 19:31:47 +02:00
|
|
|
{
|
|
|
|
//replace placeholders with args
|
|
|
|
let msg = this.template;
|
|
|
|
|
|
|
|
msg = msg.replace(/\{level\}/g, level.charAt(0).toUpperCase());
|
2022-05-02 19:31:57 +02:00
|
|
|
// [I {timestamp}] {message}
|
|
|
|
msg = msg.replace(/\{timestamp\}/g, new Date().toISOString());
|
|
|
|
// [I 1/1/1970 00:00:00] {message}
|
2022-05-02 19:31:47 +02:00
|
|
|
msg = msg.replace(/\{message\}/g, message);
|
2022-05-02 19:31:57 +02:00
|
|
|
// [I 1/1/1970 00:00:00] spul {} {}
|
2022-05-02 19:31:47 +02:00
|
|
|
|
|
|
|
//replace placeholders with args
|
2022-05-07 16:07:00 +02:00
|
|
|
if (args.length > 0)
|
|
|
|
{
|
|
|
|
let argPH = this.argsPlaceholder;
|
|
|
|
for (let arg of args)
|
|
|
|
{
|
|
|
|
// detect if arg is an object and convert it to string if it is
|
|
|
|
if (typeof arg === "object" || Array.isArray(arg) || arg.constructor === Object)
|
|
|
|
arg = JSON.stringify(arg, null, 2);
|
2022-05-02 19:31:57 +02:00
|
|
|
|
2022-05-07 16:07:00 +02:00
|
|
|
msg = msg.replace(argPH, arg);
|
|
|
|
}
|
|
|
|
}
|
2022-05-02 19:31:47 +02:00
|
|
|
|
|
|
|
//replace dictionary keys
|
|
|
|
if (this.dict)
|
2022-05-07 16:07:00 +02:00
|
|
|
msg = conversion.dictionaryConversion(msg, this.dict);
|
2022-05-02 19:31:47 +02:00
|
|
|
|
|
|
|
// add color
|
2022-05-07 16:07:00 +02:00
|
|
|
let msgNoColors = msg;
|
|
|
|
if (this.levelsColors && this.levelsColors[level])
|
|
|
|
msg = this.levelsColors[level] + msg + "\x1b[0m";
|
2022-05-02 19:31:47 +02:00
|
|
|
|
2022-05-08 02:34:16 +02:00
|
|
|
//log to output
|
|
|
|
if (this.output.stream)
|
|
|
|
{
|
|
|
|
if (this.output.exclusivity)
|
|
|
|
{
|
|
|
|
if (this.output.exclusivity.includes(level))
|
|
|
|
this.output.stream.write(this.output.noColors ? msgNoColors : msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
this.output.stream.write(this.output.noColors ? msgNoColors : msg);
|
|
|
|
} else this.output.write(msg + "\n");
|
|
|
|
|
|
|
|
//log to outputs
|
|
|
|
for (let output of this.outputs)
|
|
|
|
{
|
|
|
|
if (output.stream) {
|
|
|
|
if (output.exclusivity)
|
|
|
|
{
|
|
|
|
if (output.exclusivity.includes(level))
|
|
|
|
output.stream.write(output.noColors ? msgNoColors : msg);
|
|
|
|
} else
|
|
|
|
output.stream.write(output.noColors ? msgNoColors : msg);
|
|
|
|
} else output.write(msg + "\n");
|
|
|
|
}
|
2022-05-02 19:31:47 +02:00
|
|
|
|
|
|
|
//save to history
|
|
|
|
this.history.push({
|
|
|
|
level: level,
|
|
|
|
message: message,
|
|
|
|
args: args
|
|
|
|
});
|
2022-05-02 19:31:57 +02:00
|
|
|
if (this.history.length >= this.historySize && level !== "warn;")
|
2022-05-02 19:31:47 +02:00
|
|
|
this.onHistoryFull();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Logger;
|