/** * @fileoverview log4js is a library to log in JavaScript in similar manner * than in log4j for Java (but not really). * *
* const logging = require('log4js'); * const log = logging.getLogger('some-category'); * * //call the log * log.trace('trace me' ); ** * NOTE: the authors below are the original browser-based log4js authors * don't try to contact them about bugs in this version :) * @author Stephan Strittmatter - http://jroller.com/page/stritti * @author Seth Chisamore - http://www.chisamore.com * @since 2005-05-20 * Website: http://log4js.berlios.de */ const debug = require('debug')('log4js:main'); const fs = require('fs'); const deepClone = require('rfdc')({ proto: true }); const configuration = require('./configuration'); const layouts = require('./layouts'); const levels = require('./levels'); const appenders = require('./appenders'); const categories = require('./categories'); const Logger = require('./logger'); const clustering = require('./clustering'); const connectLogger = require('./connect-logger'); const recordingModule = require('./appenders/recording'); let enabled = false; function sendLogEventToAppender(logEvent) { if (!enabled) return; debug('Received log event ', logEvent); const categoryAppenders = categories.appendersForCategory( logEvent.categoryName ); categoryAppenders.forEach((appender) => { appender(logEvent); }); } function loadConfigurationFile(filename) { debug(`Loading configuration from ${filename}`); try { return JSON.parse(fs.readFileSync(filename, 'utf8')); } catch (e) { throw new Error( `Problem reading config from file "${filename}". Error was ${e.message}`, e ); } } function configure(configurationFileOrObject) { if (enabled) { // eslint-disable-next-line no-use-before-define shutdown(); } let configObject = configurationFileOrObject; if (typeof configObject === 'string') { configObject = loadConfigurationFile(configurationFileOrObject); } debug(`Configuration is ${configObject}`); configuration.configure(deepClone(configObject)); clustering.onMessage(sendLogEventToAppender); enabled = true; // eslint-disable-next-line no-use-before-define return log4js; } function isConfigured() { return enabled; } function recording() { return recordingModule; } /** * This callback type is called `shutdownCallback` and is displayed as a global symbol. * * @callback shutdownCallback * @param {Error} [error] */ /** * Shutdown all log appenders. This will first disable all writing to appenders * and then call the shutdown function each appender. * * @param {shutdownCallback} [callback] - The callback to be invoked once all appenders have * shutdown. If an error occurs, the callback will be given the error object * as the first argument. */ function shutdown(callback = () => {}) { if (typeof callback !== 'function') { throw new TypeError('Invalid callback passed to shutdown'); } debug('Shutdown called. Disabling all log writing.'); // First, disable all writing to appenders. This prevents appenders from // not being able to be drained because of run-away log writes. enabled = false; // Clone out to maintain a reference const appendersToCheck = Array.from(appenders.values()); // Reset immediately to prevent leaks appenders.init(); categories.init(); // Count the number of shutdown functions const shutdownFunctions = appendersToCheck.reduce( (accum, next) => (next.shutdown ? accum + 1 : accum), 0 ); if (shutdownFunctions === 0) { debug('No appenders with shutdown functions found.'); callback(); } let completed = 0; let error; debug(`Found ${shutdownFunctions} appenders with shutdown functions.`); function complete(err) { error = error || err; completed += 1; debug(`Appender shutdowns complete: ${completed} / ${shutdownFunctions}`); if (completed >= shutdownFunctions) { debug('All shutdown functions completed.'); callback(error); } } // Call each of the shutdown functions appendersToCheck .filter((a) => a.shutdown) .forEach((a) => a.shutdown(complete)); } /** * Get a logger instance. * @static * @param {string} [category=default] * @return {Logger} instance of logger for the category */ function getLogger(category) { if (!enabled) { configure( process.env.LOG4JS_CONFIG || { appenders: { out: { type: 'stdout' } }, categories: { default: { appenders: ['out'], level: 'OFF' } }, } ); } return new Logger(category || 'default'); } /** * @name log4js * @namespace Log4js * @property getLogger * @property configure * @property shutdown */ const log4js = { getLogger, configure, isConfigured, shutdown, connectLogger, levels, addLayout: layouts.addLayout, recording, }; module.exports = log4js;