UNPKG

@kcutils/logger

Version:
553 lines 22.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Logger = void 0; var util_1 = require("util"); var path_1 = require("path"); var readline_1 = require("readline"); var helper_1 = require("@kcutils/helper"); var chalk_1 = require("chalk"); var Badge = __importStar(require("figures")); var settings_1 = require("../../constants/settings"); var types_1 = require("../../constants/types"); var levels_1 = require("../../constants/levels"); var LoggerOptionBuilder_1 = require("../../builder/LoggerOptionBuilder"); var longestLabel = "longest-label"; //* [ metadata ] [ prefix ] [ data ] [suffix] //* [datetime] [scope] [filename] [separator] [badge] [label] [message] [suffix] //* [YYYY-MM-DD] global text.js ↦ ¤ [label] this this a message (suffix) var Logger = /** @class */ (function () { /** * Never create Logger object directly, * Please use LoggerBuilder or Logger.create() instead * * @param option - logger option */ function Logger(option) { this._id = Logger.counter; Logger.counter++; this._option = option; this._types = helper_1.json.deepMerge(types_1.types, this._option.getTypes()); this._setting = helper_1.json.deepMerge(settings_1.settings, this._option.getSettings()); this.idebug("create new logger (id = " + this._id + ")"); this.idebug("option: ", JSON.stringify(this._option)); this.idebug("setting: ", JSON.stringify(this._setting)); this.idebug("types: ", JSON.stringify(this._types)); this._timers = new Map(); this._color = new chalk_1.Instance(this._option.isColor() ? {} : { level: 0 }); this._isPreviousLogInteractive = false; this._parameters = new Map(); this._parameters.set(longestLabel, this.getLongestLabel()); } Logger.create = function (builder) { if (builder === void 0) { builder = LoggerOptionBuilder_1.LoggerOptionBuilder.initial(); } return new Logger(builder.get()); }; Object.defineProperty(Logger.prototype, "id", { get: function () { return this._id; }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "levels", { /** * all log levels */ get: function () { return levels_1.levels; }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "scopes", { /** * current scopes */ get: function () { return this._option.getScopes(); }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "option", { /** * get current options as readonly */ get: function () { return this._option.toStrictOption(); }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "setting", { get: function () { return Object.assign({}, this._setting); }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "type", { get: function () { return Object.assign({}, this._types); }, enumerable: false, configurable: true }); // print logger message to stream Logger.prototype.print = function (_type, data) { var type = this._types[_type]; if (!this.shouldLog(type)) return; var level = levels_1.toLevel(type.level); var inputOption = typeof data === "string" ? { message: data } : data; var _stream = this._option.isOverrideStream() ? this._option.getOverrideStream() : level.stream; var _streams = helper_1.array.toArray(_stream); if (inputOption.stream) { var streams = helper_1.array.toArray(inputOption.stream); _streams = inputOption.appendStream ? _streams.concat.apply(_streams, streams) : streams; } var message = this.build(_type, data); this.writing(_streams, message); }; // build logger message Logger.prototype.build = function (_type, input) { var type = this._types[_type]; if (!this.shouldLog(type)) return ""; var inputOption = typeof input === "string" ? { message: input } : input; var metadata = this.buildMetadata(inputOption.timestamp, inputOption.scopes); var prefix = this.buildPrefix(type, inputOption.label, inputOption.prefix); var data = this.buildMessage(inputOption.message); var suffix = this.buildSuffix(inputOption.suffix); if (this._option.isJson()) return this.buildAsJson(type, { metadata: metadata, prefix: prefix, data: data, suffix: suffix }); else return this.buildAsString(type, { metadata: metadata, prefix: prefix, data: data, suffix: suffix }); }; Logger.prototype.startTimer = function (_label, message) { var label = _label !== null && _label !== void 0 ? _label : "timer_" + this._timers.size; this._timers.set(label, Date.now()); this.print("start", { message: message !== null && message !== void 0 ? message : "Initialized timer...", label: label }); return label; }; Logger.prototype.endTimer = function (label, message) { if (this._timers.size < 1) return { label: label, timestamp: 0 }; var _label = label; if (!_label) { var is_1 = function (s) { return s && s.includes("timer_"); }; _label = Array.from(this._timers.keys()).reduceRight(function (x, y) { return is_1(x) ? x : is_1(y) ? y : ""; }, ""); } if (this._timers.has(_label)) { var previous = this._timers.get(_label); var current = Date.now(); var timestamp = current - previous; var time = timestamp < 1000 ? timestamp + " ms" : (timestamp / 1000).toFixed(2) + " s"; this._timers.delete(_label); this.print("stop", { message: message !== null && message !== void 0 ? message : "Timer run for: ", suffix: time, label: _label, }); return { label: _label, timestamp: timestamp }; } return { label: _label, timestamp: 0 }; }; /** * remove all secret found in input string * * @param message - input string */ Logger.prototype.censor = function (message) { var _this = this; var secrets = this._option.getSecrets(); if (secrets.length === 0) return message; return secrets.reduce(function (msg, secret) { var regex = new RegExp(secret, "gi"); var s = _this._option.onCensor(secret); var formatting = _this.format(s, _this._setting.secret, undefined, ["censor"]); return msg.replace(regex, formatting); }, message); }; Logger.prototype.isContainSecret = function (message) { var secrets = this._option.getSecrets(); if (secrets.length === 0) return false; return secrets.some(function (secret) { var regex = new RegExp(secret, "g"); return regex.test(message); }); }; /** * merge and replace new options * @param option - new partial option */ Logger.prototype.options = function (option) { this.idebug("options parameters: ", option); this._option = this._option.copy(option); this.idebug("new options: ", option); return this; }; /** * merge and replace new settings * @param option - new partial setting */ Logger.prototype.settings = function (setting) { this.idebug("settings parameters: ", setting); this._setting = helper_1.json.deepMerge(this._setting, setting); this.idebug("new settings: ", setting); return this; }; /** * create new logger base on current configuration * @param option - new option merged with current option * @param setting - new setting merged with current setting * @param type - new type merged with current type */ Logger.prototype.copy = function (option, setting, type) { var options = this._option.copy(option, { types: type, settings: setting }); return new Logger(options); }; Logger.prototype.isEnabled = function () { return !this._option.isDisabled(); }; /** * remove all scope on this logger */ Logger.prototype.unscope = function () { this._option.set("scopes", []); return this; }; /** * remove all secret on this logger */ Logger.prototype.unsecret = function () { this._option.set("secrets", []); return this; }; /** * enable color */ Logger.prototype.color = function () { this._option.set("color", true); this._color.level = chalk_1.level; return this; }; /** * disable color */ Logger.prototype.uncolor = function () { this._option.set("color", false); this._color.level = 0; return this; }; /** * is color enabled */ Logger.prototype.isColor = function () { return this._color.level > 0 && this._option.isColor(); }; Logger.prototype.equals = function (l) { var _this = this; var keys = Object.keys(this.importantData()); return keys.every(function (k) { var cond = helper_1.json.equals(l.option[k], _this.option[k]); if (!cond) _this.idebug("input logger is not equals because '%s'(%s !== %s)", k, _this.option[k], l.option[k]); return cond; }); }; Logger.prototype.toString = function () { var data = this.importantData(); return "Logger(" + Object.keys(data).map(function (key) { return key + "=" + data[key]; }).join(", ") + ")"; }; Logger.prototype.importantData = function () { return { debug: this.option.debug, level: this.option.level, interactive: this.option.interactive, color: this.option.color, scopes: this.option.scopes, }; }; Object.defineProperty(Logger.prototype, "filename", { /** * get current filename */ get: function () { var _ = Error.prepareStackTrace; Error.prepareStackTrace = function (_error, stack) { return stack; }; var error = new Error(); var callers = error.stack.map(function (x) { return x.getFileName(); }); var firstExternalFilePath = callers.find(function (x) { return x !== callers[0]; }); Error.prepareStackTrace = _; return firstExternalFilePath ? path_1.basename(firstExternalFilePath) : "anonymous"; }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "date", { get: function () { var _ = new Date(); var year = helper_1.string.padStart(_.getFullYear().toFixed(0), 2, "0"); var month = helper_1.string.padStart((_.getMonth() + 1).toFixed(0), 2, "0"); var day = helper_1.string.padStart(_.getDate().toFixed(0), 2, "0"); return [year, month, day].join("-"); }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "time", { get: function () { var _ = new Date(); var hour = helper_1.string.padStart(_.getHours().toFixed(0), 2, "0"); var min = helper_1.string.padStart(_.getMinutes().toFixed(0), 2, "0"); var sec = helper_1.string.padStart(_.getSeconds().toFixed(0), 2, "0"); var ms = helper_1.string.padStart(_.getMilliseconds().toFixed(0), 3, "0"); return [hour, min, sec].join(":").concat(".", ms); }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "datetime", { get: function () { return this.date + " " + this.time; }, enumerable: false, configurable: true }); Object.defineProperty(Logger.prototype, "timestamp", { get: function () { var timestamp = +new Date(); return timestamp.toFixed(0); }, enumerable: false, configurable: true }); Logger.prototype.buildAsJson = function (_type, output) { var level = levels_1.toLevel(_type.level); return JSON.stringify(__assign(__assign({}, output), { level: { name: level.name, code: level.level } })); }; Logger.prototype.buildAsString = function (type, output) { var _this = this; var _a; var withSpace = function (i) { if (helper_1.string.isNotEmpty(i)) return " " + i; else return i; }; var datetime = this.format(output.metadata.datetime.data, this._setting.datetime, this._color.gray); var scopes = output.metadata.scopes.data .map(function (scope) { return _this.format(scope, _this._setting.scope, _this._color.gray); }) .filter(function (v) { return helper_1.string.isNotEmpty(v); }) .join(" "); var filename = this.format(output.metadata.filename.data, this._setting.filename); var separator = this.format(output.metadata.seperator.data, this._setting.seperator); var _paddingBadge = helper_1.string.padEnd(output.prefix.badge.data, 2); var badge = this.format(_paddingBadge, this._setting.badge, type.color(this._color)); var _longestLabelLength = ((_a = this._parameters.get(longestLabel)) !== null && _a !== void 0 ? _a : "").length; var _paddingLabel = helper_1.string.padEnd(output.prefix.label.data, _longestLabelLength + 1); var label = this.format(_paddingLabel, this._setting.label, type.color(this._color)); var customPrefix = this.format(output.prefix.custom.data, this._setting.prefix); var message = this.format(output.data.messages.data, this._setting.message); var suffix = this.format(output.suffix.custom.data, this._setting.suffix); var metadata = "" + datetime + withSpace(scopes) + withSpace(filename) + withSpace(separator); var prefix = "" + badge + withSpace(label) + withSpace(customPrefix); return "" + metadata + withSpace(prefix) + withSpace(message) + withSpace(suffix); }; Logger.prototype.buildMetadata = function (timestamp, cusScope) { var d; var datetimeType = this._option.getDatetime(); if (timestamp) d = timestamp; else if (datetimeType === "time") d = this.time; else if (datetimeType === "date") d = this.date; else if (datetimeType === "datetime") d = this.datetime; else if (datetimeType === "timestamp") d = this.timestamp; else d = this.date; // default var datetime = { index: 1, data: d }; var scopes = { index: 2, data: this._option.getScopes().concat(cusScope !== null && cusScope !== void 0 ? cusScope : []) }; var filename = { index: 3, data: this.filename }; var seperator = { index: 4, data: this._option.getSeparator() }; var metadata = { datetime: datetime, scopes: scopes, filename: filename, seperator: seperator }; this.idebug("build metadata object: ", metadata); return metadata; }; Logger.prototype.buildPrefix = function (type, overrideLabel, customPrefix) { var _label = helper_1.string.isNotEmpty(overrideLabel) ? overrideLabel : type.label; var label = { index: 1, data: _label }; var _badge = type.badge(Badge); var badge = { index: 2, data: _badge }; var custom = { index: 3, data: helper_1.array.toArray(customPrefix !== null && customPrefix !== void 0 ? customPrefix : "") }; var prefix = { label: label, badge: badge, custom: custom }; this.idebug("build prefix object: ", prefix); return prefix; }; Logger.prototype.buildMessage = function (msg) { var messages = { index: 1, data: helper_1.array.toArray(msg) }; var data = { messages: messages }; this.idebug("build data object: ", data); return data; }; Logger.prototype.buildSuffix = function (customSuffix) { var custom = { index: 1, data: helper_1.array.toArray(customSuffix !== null && customSuffix !== void 0 ? customSuffix : "") }; var suffix = { custom: custom }; this.idebug("build metadata object: ", suffix); return suffix; }; /** * check log type should be log or not * @param type - log type */ Logger.prototype.shouldLog = function (type) { var level = levels_1.toLevel(this._option.getLevel()); var typeLevel = levels_1.toLevel(type.level); var msg = type.label + "(" + typeLevel.name + ") type for log level " + level.name; var res = typeLevel.level <= level.level; if (res) msg += " is runnable"; else msg += " is disabled"; this.idebug(msg); return res; }; /** * Never call this method outside constructor. use parameters instead */ Logger.prototype.getLongestLabel = function () { var type = this._types; var keys = Object.keys(type); return keys.reduce(function (p, key) { var label = type[key].label; return p.length > label.length ? p : label; }, ""); }; /** * format msg with settings * * @param msg - message to format * @param settings - formatting settings * @param color - with color format */ Logger.prototype.format = function (input, settings, color, disabledList) { var _this = this; if (disabledList === void 0) { disabledList = []; } var msg = helper_1.array.toArray(input).join(" "); this.idebug("formatting " + msg + " by", settings); if (settings === undefined || settings === false) return ""; var executes = [ ["uppercase", settings.uppercase, function (m) { return m.toUpperCase(); }], ["append", settings.prefix !== "" || settings.suffix !== "", function (m) { return settings.prefix + m + settings.suffix; }], ["underline", settings.underline, function (m) { return _this._color.underline(m); }], ["bold", settings.bold, function (m) { return _this._color.bold(m); }], ["italic", settings.italic, function (m) { return _this._color.italic(m); }], ["color", color !== undefined, function (m) { return color(m); }], ["censor", this.isContainSecret(msg), function (m) { return _this.censor(m); }], ]; return executes.reduce(function (p, c) { var name = c[0]; var condition = c[1]; // disabled if (disabledList.includes(name)) { _this.idebug("disabled execute " + name); return p; } var fn = c[2]; if (condition && p !== "") { _this.idebug("start execute " + name); return fn(p); } else { _this.idebug("skip execute " + name); return p; } }, msg); }; /** * write message to stream * @param stream - writable stream * @param message - message */ Logger.prototype.writing = function (stream, message) { var _this = this; var streams = helper_1.array.toArray(stream); this.idebug("write message to " + streams.length + " output"); streams.forEach(function (stream) { if (_this._option.isInteractive() && _this._isPreviousLogInteractive) { readline_1.moveCursor(stream, 0, -1); readline_1.clearLine(stream, 0); readline_1.cursorTo(stream, 0); } stream.write(message + "\n"); _this._isPreviousLogInteractive = _this._option.isInteractive(); }); }; /** * internal debug log with debug is enabled * * @param formatter - format string * @param data - message data */ Logger.prototype.idebug = function (formatter) { var data = []; for (var _i = 1; _i < arguments.length; _i++) { data[_i - 1] = arguments[_i]; } if (this._option.isDebug()) if (data.length === 1) console.log(util_1.format(formatter, util_1.inspect(data[0], false, 1, false))); else console.log(util_1.format.apply(void 0, __spreadArrays([formatter], data))); }; Logger.counter = 0; return Logger; }()); exports.Logger = Logger; //# sourceMappingURL=Logger.js.map