Repository URL to install this package:
|
Version:
0.9.2-rc0 ▾
|
// (c) Copyright 2023 Supertenant Ltd. - all rights reserved.
// See LICENSE file in project root for license terms.
/* eslint-disable dot-notation */
'use strict';
/** @type number */
let threadId = 0;
try {
threadId = require('worker_threads').threadId;
} catch (ignored) {
// We are apparently running in a Node.js version that does not have worker threads yet, thus we are on the main
// thread (0).
}
const consts = require('@supertenant/superconsts');
const bunyan = require('bunyan');
const { logger, superbrainLogger } = require('@supertenant/core');
/** @type {bunyan | import('@supertenant/core/src/logger').GenericLogger} */
let parentLogger = null;
/** @type {Object.<string, (logger: import('@supertenant/core/src/logger').GenericLogger) => *>} */
const registry = {};
/** @type {{[id: number]: number}} */
const bunyanToSuperbrainLogLevel = {};
bunyanToSuperbrainLogLevel[bunyan.TRACE] = consts.BrainLogLevel.Trace;
bunyanToSuperbrainLogLevel[bunyan.DEBUG] = consts.BrainLogLevel.Debug;
bunyanToSuperbrainLogLevel[bunyan.INFO] = consts.BrainLogLevel.Info;
bunyanToSuperbrainLogLevel[bunyan.WARN] = consts.BrainLogLevel.Warn;
bunyanToSuperbrainLogLevel[bunyan.ERROR] = consts.BrainLogLevel.Error;
bunyanToSuperbrainLogLevel[bunyan.FATAL] = consts.BrainLogLevel.Fatal;
/**
*
* @param {import('@supertenant/core').superbrainLogger} [sbLogger]
* @returns {import('bunyan').WriteFn}
*/
function superbrainToBunyanWriteFn(sbLogger) {
function SuperBrainLogStream() {}
/**
* @param {*} [record]
* @returns {void}
*/
SuperBrainLogStream.prototype.write = function (record) {
try {
if (record.msg) {
const level = bunyanToSuperbrainLogLevel[record.level] || consts.BrainLogLevel.Info;
sbLogger(level, JSON.stringify(record));
}
} catch (e) {
// skip this - bunyan probably complained about this record too.
}
};
return new SuperBrainLogStream();
}
/**
* @param {import('./util/normalizeConfig').CollectorConfig} config
* @param {function(typeof consts.BrainLogLevel, string): void} sbLogger
* @param {boolean} [isReInit]
*/
exports.init = function init(config, sbLogger, isReInit) {
if (config.logger && typeof config.logger.child === 'function') {
// A bunyan or pino logger has been provided via config. In either case we create a child logger directly under the
// given logger which serves as the parent for all loggers we create later on.
parentLogger = config.logger.child({
module: 'supertenant-nodejs-logger-parent',
__in: 1
});
} else if (config.logger && hasLoggingFunctions(config.logger)) {
// A custom non-bunyan logger has been provided via config. We use it as is.
parentLogger = config.logger;
} else {
// No custom logger has been provided via config, we create a new bunyan logger as the parent logger for all loggers
// we create later on.
parentLogger = bunyan.createLogger({
name: '@supertenant/collector',
thread: threadId,
streams: [{
level: bunyan.TRACE,
stream: superbrainToBunyanWriteFn(sbLogger),
type: 'raw'
}],
__in: 1
});
}
if (isBunyan(parentLogger)) {
// in case we are using a bunyan logger we also forward logs to the agent
if (process.env['SUPERTENANT_SUPERBRAIN_DEBUG_MODE']) {
/** @type {bunyan} */ (parentLogger).level('debug');
} else if (config.level) {
/** @type {bunyan} */ (parentLogger).level(/** @type {import('bunyan').LogLevel} */ (config.level));
} else if (process.env['SUPERTENANT_SUPERBRAIN_LOG__LEVEL']) {
/** @type {bunyan} */ (parentLogger).level(
/** @type {import('bunyan').LogLevel} */ (process.env['SUPERTENANT_SUPERBRAIN_LOG__LEVEL'].toLowerCase())
);
}
}
if (isReInit) {
Object.keys(registry).forEach(loggerName => {
const reInitFn = registry[loggerName];
reInitFn(exports.getLogger(loggerName));
});
// cascade re-init to @supertenant/core
logger.init(config);
}
};
/**
* @param {string} loggerName
* @param {(logger: import('@supertenant/core/src/logger').GenericLogger) => *} [reInitFn]
* @returns {import('@supertenant/core/src/logger').GenericLogger}
*/
exports.getLogger = function getLogger(loggerName, reInitFn) {
if (!parentLogger) {
exports.init({}, superbrainLogger);
}
let _logger;
if (typeof parentLogger.child === 'function') {
// Either bunyan or pino, both support parent-child relationships between loggers.
_logger = parentLogger.child({
module: loggerName
});
} else {
// Unknown logger type (neither bunyan nor pino), we simply return the user provided custom logger as-is.
_logger = parentLogger;
}
if (reInitFn) {
if (registry[loggerName]) {
throw new Error(`Duplicate logger name: ${loggerName}.`);
}
registry[loggerName] = reInitFn;
}
return _logger;
};
/**
* @param {import('bunyan') | *} _logger
* @returns {boolean}
*/
function isBunyan(_logger) {
return _logger instanceof bunyan;
}
/**
* @param {import('@supertenant/core/src/logger').GenericLogger | *} _logger
* @returns {boolean}
*/
function hasLoggingFunctions(_logger) {
return (
typeof _logger.debug === 'function' &&
typeof _logger.info === 'function' &&
typeof _logger.warn === 'function' &&
typeof _logger.error === 'function'
);
}