UNPKG

simple-node-logger

Version:

A node console and file logger suitable for small, medium and large production projects.

327 lines (268 loc) 9.1 kB
/** * @class SimpleLogger * * @author: darryl.west@raincitysoftware.com * @created: 2014-07-06 */ const dash = require('lodash'); const Logger = require('./Logger'); const ConsoleAppender = require('./ConsoleAppender'); const FileAppender = require('./FileAppender'); const RollingFileAppender = require('./RollingFileAppender'); const SimpleLogger = function(opts) { 'use strict'; const options = Object.assign({}, opts); const manager = this; const domain = options.domain; const appenders = options.appenders || []; const loggers = options.loggers || []; let dfltLevel = options.level || Logger.DEFAULT_LEVEL; let loggerConfigFile = options.loggerConfigFile; let refresh = options.refresh; let fs = options.fs || require('fs'); let createInterval = options.createInterval || setInterval; let minRefresh = options.minRefresh || 10 * 1000; let errorEventName = options.errorEventName; /** * create a logger with optional category and level * * @param category * @param level * @returns Logger */ this.createLogger = function(category, level) { const opts = Object.prototype.toString.call(category) === '[object String]' ? options : dash.merge({}, options, category); opts.category = dash.isString(category) ? category : opts.category; opts.level = level ? level : opts.level || dfltLevel; opts.appenders = appenders; if (errorEventName) { opts.errorEventName = errorEventName; } const logger = new Logger(opts); loggers.push(logger); return logger; }; /** * create the console appender and add it to the appenders list * * @param opts - appender settings * @returns ConsoleAppender - */ this.createConsoleAppender = function(opts) { return manager.addAppender(new ConsoleAppender(Object.assign({}, opts))); }; /** * create a file appender and add it to the appenders list * * @param opts * @returns a FileAppender object */ this.createFileAppender = function(opts) { if (!opts) { throw new Error('file appender must be created with log file path set in options'); } return manager.addAppender(new FileAppender(opts)); }; /** * create a rolling file appender and add it to the appender list * * @param opts * @returns the appender */ this.createRollingFileAppender = function(opts) { return manager.addAppender(new RollingFileAppender(opts)); }; /** * add the appender to list * * @param appender * @returns the new appender */ this.addAppender = function(appender) { appenders.push(appender); return appender; }; this.getAppenders = function() { return appenders; }; this.getLoggers = function() { return loggers; }; /** * start the refresh thread; minimum cycle time = 10 seconds... */ this.startRefreshThread = function() { // TODO replace with watcher thread if (fs.existsSync(loggerConfigFile) && dash.isNumber(refresh)) { const t = Math.max(minRefresh, refresh); createInterval(manager.readConfig, t); } }; /** * set the level of all loggers to the specified level * * @param level - one of the know levels */ this.setAllLoggerLevels = function(level) { loggers.forEach(function(logger) { logger.setLevel(level); }); }; /** * read and parse the config file; change settings if required */ this.readConfig = function(completeCallback) { // TODO refactor into configuration delegate to read stats and then process file only if stats change const callback = (err, buf) => { if (err) { /*eslint no-console: "off"*/ console.log(err); } else { const conf = JSON.parse(buf.toString()); if (conf.appenders && conf.appenders.length > 0) { // find each appender and set the level conf.appenders.forEach(function(app) { const level = app.level; const appender = dash.find(appenders, (item) => { if (item.getTypeName() === app.typeName && app.level) { return item; } }); if (appender && typeof appender.setLevel === 'function') { appender.setLevel(level); } }); } if (conf.loggers && conf.loggers.length > 0) { conf.loggers.forEach(item => { if (item.category === 'all') { manager.setAllLoggerLevels(item.level); } }); } } if (completeCallback) { return completeCallback(err); } }; fs.readFile(loggerConfigFile, callback); }; this.__protected = function() { return { domain: domain, dfltLevel: dfltLevel, refresh: refresh, loggerConfigFile: loggerConfigFile }; }; }; module.exports = SimpleLogger; /** * static convenience method to create a simple console logger; see options for details * * @param options - optional, if present then it could be 1) a string or 2) and object. if it's a string it's assumed * to be the logFilePath; if it's a string or an object with logFilePath property, then a file appender is created. * * Valid options: * - logFilePath : a path to the file appender * - domain : the logger domain, e.g., machine or site id * - dfltLevel : the default log level (overrides info level) * - timestampFormat : the format used for log entries (see moment date formats for all possibilities) * * @returns Logger */ SimpleLogger.createSimpleLogger = function(options) { 'use strict'; let opts; // if options is a string then it must be the if (typeof options === 'string') { opts = { logFilePath: options }; } else { opts = Object.assign({}, options); } const manager = new SimpleLogger(opts); // pass options in to change date formats, etc manager.createConsoleAppender(opts); if (opts.logFilePath) { manager.createFileAppender(opts); } return manager.createLogger(); }; /** * static convenience method to create a file logger (no console logging); * * @param options - if string then it's the logFilePath, else options with the logFilePath * @returns Logger */ SimpleLogger.createSimpleFileLogger = function(options) { 'use strict'; if (!options) { throw new Error('must create file logger with a logFilePath'); } let opts; // if options is a string then it must be the if (typeof options === 'string') { opts = { logFilePath: options }; } else { opts = Object.assign({}, options); } const manager = new SimpleLogger(opts); manager.createFileAppender(opts); return manager.createLogger(); }; /** * create a rolling file logger by passing options to SimpleLogger and Logger. this enables setting * of domain, category, etc. * * @param options * @returns rolling logger */ SimpleLogger.createRollingFileLogger = function(options) { 'use strict'; if (!options) { throw new Error('createRollingFileLogger requires configuration options for this constructor'); } let opts; // read a dynamic config file if available if (typeof options.readLoggerConfig === 'function') { opts = options.readLoggerConfig(); opts.readLoggerConfig = options.readLoggerConfig; } else { opts = options; } const manager = new SimpleLogger(opts); manager.createRollingFileAppender(opts); if (opts.refresh && opts.loggerConfigFile) { process.nextTick(manager.startRefreshThread); } return manager.createLogger(opts); }; /** * create a log manager * * @param options - file or rolling file specs; */ SimpleLogger.createLogManager = function(options) { 'use strict'; let opts; // read a dynamic config file if available if (options && typeof options.readLoggerConfig === 'function') { opts = options.readLoggerConfig(); opts.readLoggerConfig = options.readLoggerConfig; } else { opts = Object.assign({}, options); } const manager = new SimpleLogger(opts); if (opts.logDirectory && opts.fileNamePattern) { manager.createRollingFileAppender(opts); } // create at least one appender if (manager.getAppenders().length === 0) { manager.createConsoleAppender(opts); } return manager; };