UNPKG

seneca

Version:

A Microservices Framework for Node.js

403 lines 13.9 kB
"use strict"; /* Copyright © 2016-2022 Richard Rodger and other contributors, MIT License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.make_logging = make_logging; // NOTES // Valid log level values range from 100 to 999 inclusive only. const util_1 = __importDefault(require("util")); const Common = require('./common'); const default_logspec = { level: 'info', default_level: 'debug', level_text: { 100: 'all', 200: 'debug', 300: 'info', 400: 'warn', 500: 'error', 600: 'fatal', 999: 'none', }, logger: json_logger, }; const level_abbrev = { quiet: 'none', silent: 'none', any: 'all', all: 'all', print: 'debug', standard: 'info', test: 'warn', }; const internal_loggers = { flat_logger, test_logger, json_logger, }; function make_logging() { const logging = { default_logspec: Common.deep(default_logspec), level_abbrev: Common.deep(level_abbrev), load_logger, build_log_spec, build_log, flat_logger, test_logger, json_logger, }; return logging; } function flat_logger(entry) { let opts = this.options(); var datalen = opts.debug.datalen || 111; var level_str = (entry.level_name + '').toUpperCase(); if (level_str.length < 5) { level_str += '_'.repeat(5 - level_str.length); } level_str = level_str.substring(0, 5); var data_src = null != entry.err ? [ entry.err.message, entry.err.callpoint, entry.err.plugin || '', entry.err.plugin_callpoint || '', ] : null != entry.res ? [entry.res] : null != entry.msg ? [entry.msg] : Array.isArray(entry.data) ? entry.data : null != entry.data ? [entry.data] : []; var data_fmt = new Array(data_src.length); for (var i = 0; i < data_src.length; i++) { data_fmt[i] = data_src[i] && 'object' === typeof data_src[i] ? Common.clean(data_src[i]) : data_src[i]; data_fmt[i] = util_1.default.inspect(data_fmt[i], { compact: true, depth: entry.depth$ || opts.debug.print.depth, breakLength: Infinity, }); } var data_str = data_fmt.join(' '); data_str = data_str.substring(0, datalen) + (datalen < data_str.length ? '...' : ''); var plugin_str = null == entry.plugin_name ? '' : entry.plugin_name + (null == entry.plugin_tag || '-' == entry.plugin_tag ? '' : '$' + entry.plugin_tag); var sb = [ entry.isot, 'string' === typeof entry.seneca_id ? entry.seneca_id.substring(0, 5) : '-----', level_str, null == entry.kind ? 'log' : entry.kind, null == entry.case ? 'LOG' : entry.case, plugin_str, null == entry.pattern ? '' : entry.pattern, null == entry.action ? '' : entry.action, null == entry.idpath ? '' : entry.idpath, data_str, entry.callpoint ? util_1.default.inspect(entry.callpoint) : '', ]; this.private$.print.log(sb.join('\t').substring(0, entry.maxlen$ || 11111)); if (entry.err && opts.debug.print.err) { this.private$.print.err(entry.err); } } // TODO: make default in 4.x function json_logger(entry) { var logstr = Common.stringify(entry); this.private$.print.log(logstr); } function test_logger(entry) { try { var logstr = build_test_log(this, entry); this.private$.print.log(logstr); } catch (e) { this.private$.print.log(e, entry); } } function load_logger(instance, log_plugin) { log_plugin = log_plugin || json_logger; var logger = log_plugin; if ('string' === typeof logger) { logger = internal_loggers[logger + '_logger']; } // The logger is actually a seneca plugin that generates a logger function if (log_plugin.preload) { logger = log_plugin.preload.call(instance).extend.logger; logger.from_options$ = log_plugin.from_options$; } if (2 == logger.length) { var lla = function logger_legacy_adapter(entry) { return logger(this, entry); }; lla.from_options$ = logger.from_options$; return lla; } else { return logger; } } function build_log_spec(self) { var options = self.options(); var orig_logspec = options.log; // Canonize logspec into a standard object structure var logspec = Common.deep({ text_level: {} }, default_logspec, orig_logspec && 'object' === typeof orig_logspec ? orig_logspec : {}); // Define reverse lookup of log level values by name Object.keys(logspec.level_text).forEach((val) => { logspec.text_level[logspec.level_text[val]] = parseInt(val, 10); }); var text_level = logspec.text_level; var level_text = logspec.level_text; // logger can be set at top level as a convenience var logger = (options.internal && options.internal.logger) || options.logger || logspec.logger; // level can be set by abbreviation if ('string' === typeof orig_logspec) { let level_value = null; let found_logger = null; // abbreviation could be an actual log level name or value if (text_level[orig_logspec]) { logspec.level = orig_logspec; } // otherwise resolve abbreviation to log level name else if (level_abbrev[orig_logspec]) { logspec.level = level_abbrev[orig_logspec]; } else if (!isNaN((level_value = parseInt(orig_logspec, 10)))) { logspec.level = level_value; } // set logger by name else if ('function' === typeof (found_logger = internal_loggers[orig_logspec + '_logger'])) { logger = found_logger; } else { throw Common.error('bad_logspec_string', { logspec: orig_logspec }); } } // level value can be set directly else if ('number' === typeof orig_logspec) { logspec.level = parseInt(orig_logspec, 10); } else if ('function' === typeof orig_logspec) { logger = orig_logspec; } else if (orig_logspec && 'object' !== typeof orig_logspec && null != orig_logspec) { throw Common.error('bad_logspec', { logspec: orig_logspec }); } // If level was a known level value, replace with level text, // otherwise leave as value (as string). logspec.level = level_text[logspec.level] || '' + logspec.level; // Set live log level value from log level name, and ensure in valid range var live_level = text_level[logspec.level] || parseInt(logspec.level, 10); live_level = live_level < 100 ? 100 : 999 < live_level ? 999 : live_level; logspec.live_level = live_level; if (logger) { logspec.logger = logger; } return logspec; } function build_log(self) { var logspec = build_log_spec(self); // shortcut for direct access (avoids seneca.options() call) self.private$.logspec = logspec; var logger = load_logger(self, logspec.logger); self.private$.logger = logger; self.log = function log(entry) { var instance = this; // Handle legacy entity call if (instance.entity$) { instance = instance.private$.get_instance(); entry = { data: Array.prototype.slice.call(arguments) }; } else if ('string' === typeof entry) { entry = { data: Array.prototype.slice.call(arguments) }; } var logspec = instance.private$.logspec; entry.level = entry.level || logspec.default_level; if ('number' !== typeof entry.level) { entry.level = logspec.text_level[entry.level] || logspec.text_level[logspec.default_level]; } var now = new Date(); // NOTE: don't overwrite entry data! entry.isot = entry.isot || now.toISOString(); entry.when = entry.when || now.getTime(); entry.level_name = entry.level_name || logspec.level_text[entry.level]; entry.seneca_id = entry.seneca_id || instance.id; if (instance.did) { entry.seneca_did = entry.seneca_did || instance.did; } if (instance.fixedargs.plugin$) { entry.plugin_name = entry.plugin_name || instance.fixedargs.plugin$.name; entry.plugin_tag = entry.plugin_tag || instance.fixedargs.plugin$.tag; } if (instance.private$.act) { intern.build_act_entry(instance.private$.act, entry); } // Log event is called on all logs - they are not filtered by level instance.emit('log', entry); var level_match = logspec.live_level <= entry.level; if (level_match) { instance.private$.logger.call(this, entry); } return this; }; self.log.self = () => self; Object.keys(logspec.text_level).forEach((level_name) => { self.log[level_name] = make_log_level(level_name, logspec); }); return logspec; } function make_log_level(level_name, logspec) { var level = logspec.text_level[level_name]; var log_level = function (entry) { var self = this.self(); if (entry && 'object' !== typeof entry) { entry = { data: Array.prototype.slice.call(arguments), }; } entry.level = level; return self.log(entry); }; Object.defineProperty(log_level, 'name', { value: 'log_' + level_name }); return log_level; } function build_test_log(seneca, data) { var logstr; var time = data.when - seneca.start_time; var exports = seneca.private$.exports; var debug_opts = exports && exports.options && exports.options.debug; var datalen = (debug_opts && debug_opts.datalen) || 111; var logb = [ time + '/' + seneca.id.substring(0, 2) + '/' + seneca.tag + ' ' + (data.level_name + '').toUpperCase(), (data.kind || 'data') + (data.case ? '/' + data.case : '') + (data.meta ? (data.meta.sync ? '/s' : '/a') : ''), ]; if ('act' === data.kind) { if (data.meta) { logb.push(data.meta.id .split('/') .map(function (s) { return s.substring(0, 2); }) .join('/')); logb.push(data.meta.pattern); } if (data.res || data.result || data.msg) { let obj = data.res || data.result || data.msg || {}; let objstr = util_1.default.inspect(seneca.util.clean(obj)) .replace(/\s+/g, '') .substring(0, datalen); if (objstr.length <= 22 || !data.err) { logb.push(objstr); } else { logb.push(objstr.substring(0, 22)) + '...'; } } if (data.actdef) { logb.push(data.actdef.id); } if (data.notice) { logb.push(data.notice); } if (data.data) { logb.push(data.data); } if ('ERR' === data.case && data.err) { logb.push((data.err.code ? '\n\n' + data.err.code : '') + '\n\n' + data.err.stack + '\n' + data.caller + '\n'); } } else if ('add' === data.kind) { logb.push(data.pattern); logb.push(data.name); } else if ('ready' === data.kind) { logb.push(data.name); } else if ('plugin' === data.kind) { logb.push(data.plugin_name + (data.plugin_tag ? '$' + data.plugin_tag : '')); } else if ('options' === data.kind) { // deliberately omit } else if ('notice' === data.kind) { logb.push(data.notice); } else if ('fatal' === data.kind) { logb.push(data.notice); logb.push(data.err && data.err.stack); } else if ('listen' === data.kind || 'client' === data.kind) { var config = (data.options ? data.options[0] : data.data ? data.data[0] : {}) || {}; logb.push([ config.type, config.pin, config.host, 'function' === typeof config.port ? '' : config.port, ].join(';')); } // Just plain data else { // TODO: use jsonic util let datastr = util_1.default.inspect(seneca.util.clean(data.data || data)) .replace(/\s+/g, ''); // .substring(0, datalen) logb.push(datastr.length <= datalen ? datastr : datastr.substring(0, datalen) + '...'); } if (data.did) { logb.push(data.did); } logstr = logb.join('\t'); return logstr; } const intern = { build_act_entry: function (act, entry) { entry.kind = entry.kind || 'act'; entry.actid = entry.actid || act.meta.id; entry.pattern = entry.pattern || act.meta.pattern; entry.action = entry.action || act.def.id; entry.idpath = ('' + act.meta.tx).substring(0, 5); if (act.meta.parents) { for (var i = 0; i < act.meta.parents.length; i++) { entry.idpath += ('.' + ((act.meta.parents[i] || [])[1] || '-').split('/')[0]).substring(0, 6); } } entry.idpath += ('.' + act.meta.mi).substring(0, 6); }, }; make_logging.intern = intern; //# sourceMappingURL=logging.js.map