UNPKG

ecs-logs-js

Version:

Simple Node.js console logger that outputs human friendly and ecs-logs compatible messages

190 lines 6.86 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Logger = void 0; const fast_safe_stringify_1 = __importDefault(require("fast-safe-stringify")); const serialize_error_1 = require("serialize-error"); const extract_stack_1 = __importDefault(require("extract-stack")); const replace_string_1 = __importDefault(require("replace-string")); const chalk_1 = __importDefault(require("chalk")); const js_yaml_1 = __importDefault(require("js-yaml")); const LEVELS_MAP = { emerg: 0, alert: 1, crit: 2, error: 3, warn: 4, notice: 5, info: 6, debug: 7, }; /** Checks that the level is valid */ function validateLevel(level) { if (!(level in LEVELS_MAP)) { throw new Error(`Invalid log level '${level}'`); } } class ErrorArrayStack { stack; message; name; constructor(message, stack) { this.message = message; this.name = 'ErrorArrayStack'; this.stack = stack; } } /** JSON.stringify replacer that converts unstringifyable values to stringifyable ones */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function jsonStringifyReplacer(_key, value) { if (typeof value === 'bigint') { return value.toString(); } if (value instanceof Map) { return Array.from(value.entries()); } if (value instanceof Set) { return Array.from(value); } if (value instanceof Error) { const serializedError = (0, serialize_error_1.serializeError)(value); // Tidy up the stack trace a bit and convert it to an array const s = new ErrorArrayStack(serializedError.message || '', extract_stack_1.default.lines(value)); for (const key in value) { if (Object.prototype.hasOwnProperty.call(value, key) && key !== 'message' && key !== 'stack' && key !== 'name') { // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment s[key] = value[key]; } } return s; } return value; } /** Creates a new logger instance. */ class Logger { level = 'debug'; devMode = process.env.NODE_ENV === 'development'; constructor(options = {}) { if (options.level) { validateLevel(options.level); this.level = options.level; } if (options.devMode) { this.devMode = options.devMode; } } /** * Logs a message at the given log level. * @param level Log level for the message. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ log = (level, message, data) => { if (LEVELS_MAP[level] > LEVELS_MAP[this.level]) { return; } const logLineObject = { level: level.toUpperCase(), time: new Date().toISOString(), message, data, }; // Create JSON string with all the exotic values converted to JSON safe versions let logLine = (0, fast_safe_stringify_1.default)(logLineObject, jsonStringifyReplacer); // Format the logs in a human friendly way in development mode if (this.devMode) { // Construct the main log line and add some highlighting styles // Just parse the production log because it already has all the data conversions applied const log = JSON.parse(logLine); logLine = chalk_1.default.bold(`\n${log.level}: ${log.message}`); if (level === 'warn') { logLine = chalk_1.default.yellow(logLine); } else if (LEVELS_MAP[level] <= LEVELS_MAP.error) { logLine = chalk_1.default.red(logLine); } // Convert data to a compact and readable format if (log.data) { let data = js_yaml_1.default.safeDump(log.data, { schema: js_yaml_1.default.JSON_SCHEMA, lineWidth: Infinity }); // Indent the data slightly data = data .trim() .split('\n') .map((line) => ` ${line}`) .join('\n'); // Shorten the absolute file paths data = (0, replace_string_1.default)(data, process.cwd(), '.'); logLine += `\n${data}`; } } process.stdout.write(logLine + '\n'); }; /** * Logs a message at the EMERG log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ emerg = (message, data) => { this.log('emerg', message, data); }; /** * Logs a message at the ALERT log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ alert = (message, data) => { this.log('alert', message, data); }; /** * Logs a message at the CRIT log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ crit = (message, data) => { this.log('crit', message, data); }; /** * Logs a message at the ERROR log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ error = (message, data) => { this.log('error', message, data); }; /** * Logs a message at the WARN log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ warn = (message, data) => { this.log('warn', message, data); }; /** * Logs a message at the NOTICE log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ notice = (message, data) => { this.log('notice', message, data); }; /** * Logs a message at the INFO log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ info = (message, data) => { this.log('info', message, data); }; /** * Logs a message at the DEBUG log level. * @param message The message to log. * @param data Any additional data to log with the message. This can be any type. */ debug = (message, data) => { this.log('debug', message, data); }; } exports.Logger = Logger; //# sourceMappingURL=index.js.map