lib/logging.js
"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 = void 0;
// 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;
}
exports.make_logging = make_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