@stoplight/moleculer
Version:
Fast & powerful microservices framework for Node.JS
233 lines (206 loc) • 6.01 kB
JavaScript
/*
* moleculer
* Copyright (c) 2019 MoleculerJS (https://github.com/moleculerjs/moleculer)
* MIT Licensed
*/
/* eslint-disable no-console */
"use strict";
const BaseLogger = require("./base");
const _ = require("lodash");
const kleur = require("kleur");
const util = require("util");
const { isObject, isFunction } = require("../utils");
function getColor(type) {
switch (type) {
case "fatal":
return kleur.red().inverse;
case "error":
return kleur.red;
case "warn":
return kleur.yellow;
case "debug":
return kleur.magenta;
case "trace":
return kleur.gray;
default:
return kleur.green;
}
}
/**
* Formatted abstract logger for Moleculer
*
* @class FormattedLogger
* @extends {BaseLogger}
*/
class FormattedLogger extends BaseLogger {
/**
* Creates an instance of FormattedLogger.
* @param {Object} opts
* @memberof FormattedLogger
*/
constructor(opts) {
super(opts);
this.opts = _.defaultsDeep(this.opts, {
colors: true,
moduleColors: false,
formatter: "full",
objectPrinter: null,
autoPadding: false
});
this.maxPrefixLength = 0;
}
init(loggerFactory) {
super.init(loggerFactory);
if (!this.opts.colors) kleur.enabled = false;
this.objectPrinter = this.opts.objectPrinter
? this.opts.objectPrinter
: o =>
util.inspect(o, {
showHidden: false,
depth: 2,
colors: kleur.enabled,
breakLength: Number.POSITIVE_INFINITY
});
// Generate colorful log level names
this.levelColorStr = BaseLogger.LEVELS.reduce((a, level) => {
a[level] = getColor(level)(_.padEnd(level.toUpperCase(), 5));
return a;
}, {});
if (this.opts.colors && this.opts.moduleColors === true) {
this.opts.moduleColors = [
"yellow",
"bold.yellow",
"cyan",
"bold.cyan",
"green",
"bold.green",
"magenta",
"bold.magenta",
"blue",
"bold.blue"
/*"red",*/
/*"grey",*/
/*"white,"*/
];
}
}
/**
* Get a color for the module name.
*/
getNextColor(mod) {
if (this.opts.colors && Array.isArray(this.opts.moduleColors)) {
// Credits: "visionmedia/debug" https://github.com/visionmedia/debug/blob/master/src/common.js#L45
let hash = 0;
for (let i = 0; i < mod.length; i++) {
hash = (hash << 5) - hash + mod.charCodeAt(i);
hash |= 0; // Convert to 32bit integer
}
return this.opts.moduleColors[Math.abs(hash) % this.opts.moduleColors.length];
}
return "grey";
}
padLeft(len) {
if (this.opts.autoPadding) return " ".repeat(this.maxPrefixLength - len);
return "";
}
/**
*
* @param {object} bindings
*/
getFormatter(bindings) {
const formatter = this.opts.formatter;
const mod = bindings && bindings.mod ? bindings.mod.toUpperCase() : "";
const c = this.getNextColor(mod);
const modColorName = c.split(".").reduce((a, b) => a[b] || a()[b], kleur)(mod);
const moduleColorName = bindings ? kleur.grey(bindings.nodeID + "/") + modColorName : "";
const printArgs = args => {
return args.map(p => {
if (isObject(p) || Array.isArray(p)) return this.objectPrinter(p);
return p;
});
};
if (isFunction(formatter)) {
return (type, args) => formatter.call(this, type, args, bindings, { printArgs });
} else if (formatter == "json") {
// {"ts":1581243299731,"level":"info","msg":"Moleculer v0.14.0-rc2 is starting...","nodeID":"console","ns":"","mod":"broker"}
kleur.enabled = false;
return (type, args) => [
JSON.stringify({
ts: Date.now(),
level: type,
msg: printArgs(args).join(" "),
...bindings
})
];
} else if (formatter == "jsonext") {
// {"time":"2020-02-09T10:44:35.285Z","level":"info","message":"Moleculer v0.14.0-rc2 is starting...","nodeID":"console","ns":"","mod":"broker"}
kleur.enabled = false;
return (type, args) => {
const res = {
time: new Date().toISOString(),
level: type,
message: "",
...bindings
};
if (args.length > 0) {
if (typeof args[0] == "object" /* && !(args[0] instanceof Error)*/) {
Object.assign(res, args[0]);
res.message = printArgs(args.slice(1)).join(" ");
} else {
res.message = printArgs(args).join(" ");
}
}
return [JSON.stringify(res)];
};
} else if (formatter == "simple") {
// INFO - Moleculer v0.14.0-beta3 is starting...
return (type, args) => [this.levelColorStr[type], "-", ...printArgs(args)];
} else if (formatter == "short") {
// [08:42:12.973Z] INFO BROKER: Moleculer v0.14.0-beta3 is starting...
const prefixLen = 23 + bindings.mod.length;
this.maxPrefixLength = Math.max(prefixLen, this.maxPrefixLength);
return (type, args) => [
kleur.grey(`[${new Date().toISOString().substr(11)}]`),
this.levelColorStr[type],
modColorName + this.padLeft(prefixLen) + kleur.grey(":"),
...printArgs(args)
];
} else if (formatter == "full") {
// [2019-08-31T08:40:53.481Z] INFO bobcsi-pc-7100/BROKER: Moleculer v0.14.0-beta3 is starting...
const prefixLen = 35 + bindings.nodeID.length + bindings.mod.length;
this.maxPrefixLength = Math.max(prefixLen, this.maxPrefixLength);
return (type, args) => [
kleur.grey(`[${new Date().toISOString()}]`),
this.levelColorStr[type],
moduleColorName + this.padLeft(prefixLen) + kleur.grey(":"),
...printArgs(args)
];
} else {
// [{timestamp}] {level} {nodeID}/{mod}: {msg}
return (type, args) => {
const timestamp = new Date().toISOString();
return [
this.render(formatter, {
timestamp: kleur.grey(timestamp),
time: kleur.grey(timestamp.substr(11)),
level: this.levelColorStr[type],
nodeID: kleur.grey(bindings.nodeID),
mod: modColorName,
msg: printArgs(args).join(" ")
})
];
};
}
}
/**
* Interpolate a text.
*
* @param {Strimg} str
* @param {Object} obj
* @returns {String}
*/
render(str, obj) {
return str.replace(/\{\s?(\w+)\s?\}/g, (match, v) => obj[v] || "");
}
}
module.exports = FormattedLogger;