326 lines
9.0 KiB
JavaScript

/**
* @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,
loggerConfigFile = options.loggerConfigFile,
refresh = options.refresh,
fs = options.fs || require('fs' ),
createInterval = options.createInterval || setInterval,
minRefresh = options.minRefresh || 10 * 1000,
errorEventName = options.errorEventName;
/**
* create a logger with optional category and level
*
* @param category
* @param level
*/
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');
}
var opts;
// read a dynamic config file if available
if (typeof options.readLoggerConfig === 'function') {
opts = options.readLoggerConfig();
opts.readLoggerConfig = options.readLoggerConfig;
} else {
opts = options;
}
var 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);
}
var 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;
};