diff --git a/lib/log4js.js b/lib/log4js.js index 8e88217..4a2dbfd 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -44,299 +44,480 @@ * @static * Website: http://log4js.berlios.de */ -module.exports = function (fileSystem, standardOutput, configPaths) { - var events = require('events'), - path = require('path'), - sys = require('sys'), - fs = fileSystem || require('fs'), - standardOutput = standardOutput || sys.puts, - configPaths = configPaths || require.paths, - DEFAULT_CATEGORY = '[default]', - ALL_CATEGORIES = '[all]', - loggers = {}, - appenders = {}, - levels = { - ALL: new Level(Number.MIN_VALUE, "ALL", "grey"), - TRACE: new Level(5000, "TRACE", "blue"), - DEBUG: new Level(10000, "DEBUG", "cyan"), - INFO: new Level(20000, "INFO", "green"), - WARN: new Level(30000, "WARN", "yellow"), - ERROR: new Level(40000, "ERROR", "red"), - FATAL: new Level(50000, "FATAL", "magenta"), - OFF: new Level(Number.MAX_VALUE, "OFF", "grey") - }, - appenderMakers = { - "file": function(config) { - var layout; - if (config.layout) { - layout = layoutMakers[config.layout.type](config.layout); - } - return fileAppender(config.filename, layout, config.maxLogSize, config.backups, config.pollInterval); - }, - "console": function(config) { - var layout; - if (config.layout) { - layout = layoutMakers[config.layout.type](config.layout); - } - return consoleAppender(layout); - }, - "logLevelFilter": function(config) { - var appender = appenderMakers[config.appender.type](config.appender); - return logLevelFilter(config.level, appender); +var events = require('events'), +path = require('path'), +sys = require('sys'), +DEFAULT_CATEGORY = '[default]', +ALL_CATEGORIES = '[all]', +appenders = {}, +loggers = {}, +levels = { + ALL: new Level(Number.MIN_VALUE, "ALL", "grey"), + TRACE: new Level(5000, "TRACE", "blue"), + DEBUG: new Level(10000, "DEBUG", "cyan"), + INFO: new Level(20000, "INFO", "green"), + WARN: new Level(30000, "WARN", "yellow"), + ERROR: new Level(40000, "ERROR", "red"), + FATAL: new Level(50000, "FATAL", "magenta"), + OFF: new Level(Number.MAX_VALUE, "OFF", "grey") +}, +appenderMakers = { + "file": function(config, fileAppender) { + var layout; + if (config.layout) { + layout = layoutMakers[config.layout.type](config.layout); } + return fileAppender(config.filename, layout, config.maxLogSize, config.backups, config.pollInterval); }, - layoutMakers = { - "messagePassThrough": function() { return messagePassThroughLayout; }, - "basic": function() { return basicLayout; }, - "pattern": function (config) { - var pattern = config.pattern || undefined; - return patternLayout(pattern); + "console": function(config, fileAppender, consoleAppender) { + var layout; + if (config.layout) { + layout = layoutMakers[config.layout.type](config.layout); } - }; + return consoleAppender(layout); + }, + "logLevelFilter": function(config, fileAppender, consoleAppender) { + var appender = appenderMakers[config.appender.type](config.appender, fileAppender, consoleAppender); + return logLevelFilter(config.level, appender); + } +}, +layoutMakers = { + "messagePassThrough": function() { return messagePassThroughLayout; }, + "basic": function() { return basicLayout; }, + "pattern": function (config) { + var pattern = config.pattern || undefined; + return patternLayout(pattern); + } +}; - /** - * Get a logger instance. Instance is cached on categoryName level. - * @param {String} categoryName name of category to log to. - * @return {Logger} instance of logger for the category - * @static - */ - function getLogger (categoryName) { - - // Use default logger if categoryName is not specified or invalid - if (!(typeof categoryName == "string")) { - categoryName = DEFAULT_CATEGORY; - } +/** + * Get a logger instance. Instance is cached on categoryName level. + * @param {String} categoryName name of category to log to. + * @return {Logger} instance of logger for the category + * @static + */ +function getLogger (categoryName) { + + // Use default logger if categoryName is not specified or invalid + if (!(typeof categoryName == "string")) { + categoryName = DEFAULT_CATEGORY; + } - var appenderList; - if (!loggers[categoryName]) { - // Create the logger for this name if it doesn't already exist - loggers[categoryName] = new Logger(categoryName); - if (appenders[categoryName]) { - appenderList = appenders[categoryName]; - appenderList.forEach(function(appender) { - loggers[categoryName].addListener("log", appender); - }); - } - if (appenders[ALL_CATEGORIES]) { - appenderList = appenders[ALL_CATEGORIES]; - appenderList.forEach(function(appender) { - loggers[categoryName].addListener("log", appender); - }); - } + var appenderList; + if (!loggers[categoryName]) { + // Create the logger for this name if it doesn't already exist + loggers[categoryName] = new Logger(categoryName); + if (appenders[categoryName]) { + appenderList = appenders[categoryName]; + appenderList.forEach(function(appender) { + loggers[categoryName].addListener("log", appender); + }); + } + if (appenders[ALL_CATEGORIES]) { + appenderList = appenders[ALL_CATEGORIES]; + appenderList.forEach(function(appender) { + loggers[categoryName].addListener("log", appender); + }); } - - return loggers[categoryName]; } + + return loggers[categoryName]; +} - /** - * args are appender, then zero or more categories - */ - function addAppender () { - var args = Array.prototype.slice.call(arguments); - var appender = args.shift(); - if (args.length == 0 || args[0] === undefined) { - args = [ ALL_CATEGORIES ]; - } - //argument may already be an array - if (args[0].forEach) { - args = args[0]; +/** + * args are appender, then zero or more categories + */ +function addAppender () { + var args = Array.prototype.slice.call(arguments); + var appender = args.shift(); + if (args.length == 0 || args[0] === undefined) { + args = [ ALL_CATEGORIES ]; + } + //argument may already be an array + if (args[0].forEach) { + args = args[0]; + } + + args.forEach(function(category) { + if (!appenders[category]) { + appenders[category] = []; } + appenders[category].push(appender); - args.forEach(function(category) { - if (!appenders[category]) { - appenders[category] = []; - } - appenders[category].push(appender); - - if (category === ALL_CATEGORIES) { - for (var logger in loggers) { - if (loggers.hasOwnProperty(logger)) { - loggers[logger].addListener("log", appender); - } + if (category === ALL_CATEGORIES) { + for (var logger in loggers) { + if (loggers.hasOwnProperty(logger)) { + loggers[logger].addListener("log", appender); } - } else if (loggers[category]) { - loggers[category].addListener("log", appender); + } + } else if (loggers[category]) { + loggers[category].addListener("log", appender); + } + }); + appenders.count = appenders.count ? appenders.count++ : 1; +} + +function clearAppenders () { + appenders = {}; + for (var logger in loggers) { + if (loggers.hasOwnProperty(logger)) { + loggers[logger].removeAllListeners("log"); + } + } +} + +function configureAppenders(appenderList, fileAppender, consoleAppender) { + clearAppenders(); + if (appenderList) { + appenderList.forEach(function(appenderConfig) { + var appender = appenderMakers[appenderConfig.type](appenderConfig, fileAppender, consoleAppender); + if (appender) { + addAppender(appender, appenderConfig.category); + } else { + throw new Error("log4js configuration problem for "+sys.inspect(appenderConfig)); } }); + } else { + addAppender(consoleAppender); } +} - function clearAppenders () { - appenders = []; - for (var logger in loggers) { - if (loggers.hasOwnProperty(logger)) { - loggers[logger].removeAllListeners("log"); +function configureLevels(levels) { + if (levels) { + for (var category in levels) { + if (levels.hasOwnProperty(category)) { + getLogger(category).setLevel(levels[category]); } } } +} - function configure (configurationFile) { - if (configurationFile) { - try { - var config = JSON.parse(fs.readFileSync(configurationFile, "utf8")); - configureAppenders(config.appenders); - configureLevels(config.levels); - } catch (e) { - throw new Error("Problem reading log4js config file " + configurationFile + ". Error was " + e.message); - } - } - } +function Level(level, levelStr, colour) { + this.level = level; + this.levelStr = levelStr; + this.colour = colour; +} - function findConfiguration() { - //add current directory onto the list of configPaths - var paths = ['.'].concat(configPaths); - //add this module's directory to the end of the list, so that we pick up the default config - paths.push(__dirname); - var pathsWithConfig = paths.filter( function (pathToCheck) { - try { - fs.statSync(path.join(pathToCheck, "log4js.json")); - return true; - } catch (e) { - return false; - } - }); - if (pathsWithConfig.length > 0) { - return path.join(pathsWithConfig[0], 'log4js.json'); - } - return undefined; +/** + * converts given String to corresponding Level + * @param {String} sArg String value of Level + * @param {Log4js.Level} defaultLevel default Level, if no String representation + * @return Level object + * @type Log4js.Level + */ +Level.toLevel = function(sArg, defaultLevel) { + + if (sArg === null) { + return defaultLevel; } - - function configureAppenders(appenderList) { - clearAppenders(); - if (appenderList) { - appenderList.forEach(function(appenderConfig) { - var appender = appenderMakers[appenderConfig.type](appenderConfig); - if (appender) { - addAppender(appender, appenderConfig.category); - } else { - throw new Error("log4js configuration problem for "+sys.inspect(appenderConfig)); - } - }); - } else { - addAppender(consoleAppender); + + if (typeof sArg == "string") { + var s = sArg.toUpperCase(); + if (levels[s]) { + return levels[s]; } } + return defaultLevel; +}; - function configureLevels(levels) { - if (levels) { - for (var category in levels) { - if (levels.hasOwnProperty(category)) { - getLogger(category).setLevel(levels[category]); - } - } - } - } +Level.prototype.toString = function() { + return this.levelStr; +}; + +Level.prototype.isLessThanOrEqualTo = function(otherLevel) { + return this.level <= otherLevel.level; +}; - function Level(level, levelStr, colour) { - this.level = level; - this.levelStr = levelStr; - this.colour = colour; +Level.prototype.isGreaterThanOrEqualTo = function(otherLevel) { + return this.level >= otherLevel.level; +}; + +/** + * Models a logging event. + * @constructor + * @param {String} categoryName name of category + * @param {Log4js.Level} level level of message + * @param {String} message message to log + * @param {Log4js.Logger} logger the associated logger + * @author Seth Chisamore + */ +function LoggingEvent (categoryName, level, message, exception, logger) { + this.startTime = new Date(); + this.categoryName = categoryName; + this.message = message; + this.level = level; + this.logger = logger; + if (exception && exception.message && exception.name) { + this.exception = exception; + } else if (exception) { + this.exception = new Error(sys.inspect(exception)); } +} - /** - * converts given String to corresponding Level - * @param {String} sArg String value of Level - * @param {Log4js.Level} defaultLevel default Level, if no String representation - * @return Level object - * @type Log4js.Level - */ - Level.toLevel = function(sArg, defaultLevel) { - - if (sArg === null) { - return defaultLevel; - } +/** + * Logger to log messages. + * use {@see Log4js#getLogger(String)} to get an instance. + * @constructor + * @param name name of category to log to + * @author Stephan Strittmatter + */ +function Logger (name, level) { + this.category = name || DEFAULT_CATEGORY; + this.level = Level.toLevel(level, levels.TRACE); +} +sys.inherits(Logger, events.EventEmitter); + +Logger.prototype.setLevel = function(level) { + this.level = Level.toLevel(level, levels.TRACE); +}; + +Logger.prototype.log = function(logLevel, message, exception) { + var loggingEvent = new LoggingEvent(this.category, logLevel, message, exception, this); + this.emit("log", loggingEvent); +}; + +Logger.prototype.isLevelEnabled = function(otherLevel) { + return this.level.isLessThanOrEqualTo(otherLevel); +}; + +['Trace','Debug','Info','Warn','Error','Fatal'].forEach( + function(levelString) { + var level = Level.toLevel(levelString); + Logger.prototype['is'+levelString+'Enabled'] = function() { + return this.isLevelEnabled(level); + }; - if (typeof sArg == "string") { - var s = sArg.toUpperCase(); - if (levels[s]) { - return levels[s]; + Logger.prototype[levelString.toLowerCase()] = function (message, exception) { + if (this.isLevelEnabled(level)) { + this.log(level, message, exception); } + }; + } +); + +/** + * Get the default logger instance. + * @return {Logger} instance of default logger + * @static + */ +function getDefaultLogger () { + return getLogger(DEFAULT_CATEGORY); +} + +function logLevelFilter (levelString, appender) { + var level = Level.toLevel(levelString); + return function(logEvent) { + if (logEvent.level.isGreaterThanOrEqualTo(level)) { + appender(logEvent); } - return defaultLevel; - }; + } +} - Level.prototype.toString = function() { - return this.levelStr; - }; +/** + * BasicLayout is a simple layout for storing the logs. The logs are stored + * in following format: + *
+ * [startTime] [logLevel] categoryName - message\n
+ * 
+ * + * @author Stephan Strittmatter + */ +function basicLayout (loggingEvent) { + var timestampLevelAndCategory = '[' + loggingEvent.startTime.toFormattedString() + '] '; + timestampLevelAndCategory += '[' + loggingEvent.level.toString() + '] '; + timestampLevelAndCategory += loggingEvent.categoryName + ' - '; - Level.prototype.isLessThanOrEqualTo = function(otherLevel) { - return this.level <= otherLevel.level; - }; + var output = timestampLevelAndCategory + loggingEvent.message; + + if (loggingEvent.exception) { + output += '\n' + output += timestampLevelAndCategory; + if (loggingEvent.exception.stack) { + output += loggingEvent.exception.stack; + } else { + output += loggingEvent.exception.name + ': '+loggingEvent.exception.message; + } + } + return output; +} - Level.prototype.isGreaterThanOrEqualTo = function(otherLevel) { - return this.level >= otherLevel.level; +/** + * Taken from masylum's fork (https://github.com/masylum/log4js-node) + */ +function colorize (str, style) { + var styles = { + //styles + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + //grayscale + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [90, 39], + //colors + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] }; + return '\033[' + styles[style][0] + 'm' + str + + '\033[' + styles[style][1] + 'm'; +} - /** - * Models a logging event. - * @constructor - * @param {String} categoryName name of category - * @param {Log4js.Level} level level of message - * @param {String} message message to log - * @param {Log4js.Logger} logger the associated logger - * @author Seth Chisamore - */ - function LoggingEvent (categoryName, level, message, exception, logger) { - this.startTime = new Date(); - this.categoryName = categoryName; - this.message = message; - this.level = level; - this.logger = logger; - if (exception && exception.message && exception.name) { - this.exception = exception; - } else if (exception) { - this.exception = new Error(sys.inspect(exception)); +/** + * colouredLayout - taken from masylum's fork. + * same as basicLayout, but with colours. + */ +function colouredLayout (loggingEvent) { + var timestampLevelAndCategory = colorize('[' + loggingEvent.startTime.toFormattedString() + '] ', 'grey'); + timestampLevelAndCategory += colorize( + '[' + loggingEvent.level.toString() + '] ', loggingEvent.level.colour + ); + timestampLevelAndCategory += colorize(loggingEvent.categoryName + ' - ', 'grey'); + + var output = timestampLevelAndCategory + loggingEvent.message; + + if (loggingEvent.exception) { + output += '\n' + output += timestampLevelAndCategory; + if (loggingEvent.exception.stack) { + output += loggingEvent.exception.stack; + } else { + output += loggingEvent.exception.name + ': '+loggingEvent.exception.message; } } + return output; +} - /** - * Logger to log messages. - * use {@see Log4js#getLogger(String)} to get an instance. - * @constructor - * @param name name of category to log to - * @author Stephan Strittmatter - */ - function Logger (name, level) { - this.category = name || DEFAULT_CATEGORY; - this.level = Level.toLevel(level, levels.TRACE); - } - sys.inherits(Logger, events.EventEmitter); +function messagePassThroughLayout (loggingEvent) { + return loggingEvent.message; +} - Logger.prototype.setLevel = function(level) { - this.level = Level.toLevel(level, levels.TRACE); - }; +/** + * PatternLayout + * Takes a pattern string and returns a layout function. + * @author Stephan Strittmatter + */ +function patternLayout (pattern) { + var TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n"; + var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([cdmnpr%])(\{([^\}]+)\})?|([^%]+)/; - Logger.prototype.log = function(logLevel, message, exception) { - var loggingEvent = new LoggingEvent(this.category, logLevel, message, exception, this); - this.emit("log", loggingEvent); - }; + pattern = pattern || patternLayout.TTCC_CONVERSION_PATTERN; - Logger.prototype.isLevelEnabled = function(otherLevel) { - return this.level.isLessThanOrEqualTo(otherLevel); - }; + return function(loggingEvent) { + var formattedString = ""; + var result; + var searchString = this.pattern; + + while ((result = regex.exec(searchString))) { + var matchedString = result[0]; + var padding = result[1]; + var truncation = result[2]; + var conversionCharacter = result[3]; + var specifier = result[5]; + var text = result[6]; + + // Check if the pattern matched was just normal text + if (text) { + formattedString += "" + text; + } else { + // Create a raw replacement string based on the conversion + // character and specifier + var replacement = ""; + switch(conversionCharacter) { + case "c": + var loggerName = loggingEvent.categoryName; + if (specifier) { + var precision = parseInt(specifier, 10); + var loggerNameBits = loggingEvent.categoryName.split("."); + if (precision >= loggerNameBits.length) { + replacement = loggerName; + } else { + replacement = loggerNameBits.slice(loggerNameBits.length - precision).join("."); + } + } else { + replacement = loggerName; + } + break; + case "d": + var dateFormat = Date.ISO8601_FORMAT; + if (specifier) { + dateFormat = specifier; + // Pick up special cases + if (dateFormat == "ISO8601") { + dateFormat = Date.ISO8601_FORMAT; + } else if (dateFormat == "ABSOLUTE") { + dateFormat = Date.ABSOLUTETIME_FORMAT; + } else if (dateFormat == "DATE") { + dateFormat = Date.DATETIME_FORMAT; + } + } + // Format the date + replacement = loggingEvent.startTime.toFormattedString(dateFormat); + break; + case "m": + replacement = loggingEvent.message; + break; + case "n": + replacement = "\n"; + break; + case "p": + replacement = loggingEvent.level.toString(); + break; + case "r": + replacement = "" + loggingEvent.startTime.toLocaleTimeString(); + break; + case "%": + replacement = "%"; + break; + default: + replacement = matchedString; + break; + } + // Format the replacement according to any padding or + // truncation specified + + var len; - ['Trace','Debug','Info','Warn','Error','Fatal'].forEach( - function(levelString) { - var level = Level.toLevel(levelString); - Logger.prototype['is'+levelString+'Enabled'] = function() { - return this.isLevelEnabled(level); - }; - - Logger.prototype[levelString.toLowerCase()] = function (message, exception) { - if (this.isLevelEnabled(level)) { - this.log(level, message, exception); + // First, truncation + if (truncation) { + len = parseInt(truncation.substr(1), 10); + replacement = replacement.substring(0, len); } - }; + // Next, padding + if (padding) { + if (padding.charAt(0) == "-") { + len = parseInt(padding.substr(1), 10); + // Right pad with spaces + while (replacement.length < len) { + replacement += " "; + } + } else { + len = parseInt(padding, 10); + // Left pad with spaces + while (replacement.length < len) { + replacement = " " + replacement; + } + } + } + formattedString += replacement; + } + searchString = searchString.substr(result.index + result[0].length); } - ); + return formattedString; + }; + +}; + + +module.exports = function (fileSystem, standardOutput, configPaths) { + var fs = fileSystem || require('fs'), + standardOutput = standardOutput || sys.puts, + configPaths = configPaths || require.paths; - /** - * Get the default logger instance. - * @return {Logger} instance of default logger - * @static - */ - function getDefaultLogger () { - return getLogger(DEFAULT_CATEGORY); - } function consoleAppender (layout) { layout = layout || colouredLayout; @@ -410,214 +591,37 @@ module.exports = function (fileSystem, standardOutput, configPaths) { } } - function logLevelFilter (levelString, appender) { - var level = Level.toLevel(levelString); - return function(logEvent) { - if (logEvent.level.isGreaterThanOrEqualTo(level)) { - appender(logEvent); - } - } - } - - /** - * BasicLayout is a simple layout for storing the logs. The logs are stored - * in following format: - *
-     * [startTime] [logLevel] categoryName - message\n
-     * 
- * - * @author Stephan Strittmatter - */ - function basicLayout (loggingEvent) { - var timestampLevelAndCategory = '[' + loggingEvent.startTime.toFormattedString() + '] '; - timestampLevelAndCategory += '[' + loggingEvent.level.toString() + '] '; - timestampLevelAndCategory += loggingEvent.categoryName + ' - '; - - var output = timestampLevelAndCategory + loggingEvent.message; - - if (loggingEvent.exception) { - output += '\n' - output += timestampLevelAndCategory; - if (loggingEvent.exception.stack) { - output += loggingEvent.exception.stack; - } else { - output += loggingEvent.exception.name + ': '+loggingEvent.exception.message; - } - } - return output; - } - - /** - * Taken from masylum's fork (https://github.com/masylum/log4js-node) - */ - function colorize (str, style) { - var styles = { - //styles - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - //grayscale - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [90, 39], - //colors - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] - }; - return '\033[' + styles[style][0] + 'm' + str + - '\033[' + styles[style][1] + 'm'; - } - - /** - * colouredLayout - taken from masylum's fork. - * same as basicLayout, but with colours. - */ - function colouredLayout (loggingEvent) { - var timestampLevelAndCategory = colorize('[' + loggingEvent.startTime.toFormattedString() + '] ', 'grey'); - timestampLevelAndCategory += colorize( - '[' + loggingEvent.level.toString() + '] ', loggingEvent.level.colour - ); - timestampLevelAndCategory += colorize(loggingEvent.categoryName + ' - ', 'grey'); - - var output = timestampLevelAndCategory + loggingEvent.message; - - if (loggingEvent.exception) { - output += '\n' - output += timestampLevelAndCategory; - if (loggingEvent.exception.stack) { - output += loggingEvent.exception.stack; - } else { - output += loggingEvent.exception.name + ': '+loggingEvent.exception.message; + function configure (configurationFile) { + if (configurationFile) { + try { + var config = JSON.parse(fs.readFileSync(configurationFile, "utf8")); + configureAppenders(config.appenders, fileAppender, consoleAppender); + configureLevels(config.levels); + } catch (e) { + throw new Error("Problem reading log4js config file " + configurationFile + ". Error was \"" + e.message + "\" ("+e.stack+")"); } } - return output; } - function messagePassThroughLayout (loggingEvent) { - return loggingEvent.message; + function findConfiguration() { + //add current directory onto the list of configPaths + var paths = ['.'].concat(configPaths); + //add this module's directory to the end of the list, so that we pick up the default config + paths.push(__dirname); + var pathsWithConfig = paths.filter( function (pathToCheck) { + try { + fs.statSync(path.join(pathToCheck, "log4js.json")); + return true; + } catch (e) { + return false; + } + }); + if (pathsWithConfig.length > 0) { + return path.join(pathsWithConfig[0], 'log4js.json'); + } + return undefined; } - /** - * PatternLayout - * Takes a pattern string and returns a layout function. - * @author Stephan Strittmatter - */ - function patternLayout (pattern) { - var TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n"; - var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([cdmnpr%])(\{([^\}]+)\})?|([^%]+)/; - - pattern = pattern || patternLayout.TTCC_CONVERSION_PATTERN; - - return function(loggingEvent) { - var formattedString = ""; - var result; - var searchString = this.pattern; - - while ((result = regex.exec(searchString))) { - var matchedString = result[0]; - var padding = result[1]; - var truncation = result[2]; - var conversionCharacter = result[3]; - var specifier = result[5]; - var text = result[6]; - - // Check if the pattern matched was just normal text - if (text) { - formattedString += "" + text; - } else { - // Create a raw replacement string based on the conversion - // character and specifier - var replacement = ""; - switch(conversionCharacter) { - case "c": - var loggerName = loggingEvent.categoryName; - if (specifier) { - var precision = parseInt(specifier, 10); - var loggerNameBits = loggingEvent.categoryName.split("."); - if (precision >= loggerNameBits.length) { - replacement = loggerName; - } else { - replacement = loggerNameBits.slice(loggerNameBits.length - precision).join("."); - } - } else { - replacement = loggerName; - } - break; - case "d": - var dateFormat = Date.ISO8601_FORMAT; - if (specifier) { - dateFormat = specifier; - // Pick up special cases - if (dateFormat == "ISO8601") { - dateFormat = Date.ISO8601_FORMAT; - } else if (dateFormat == "ABSOLUTE") { - dateFormat = Date.ABSOLUTETIME_FORMAT; - } else if (dateFormat == "DATE") { - dateFormat = Date.DATETIME_FORMAT; - } - } - // Format the date - replacement = loggingEvent.startTime.toFormattedString(dateFormat); - break; - case "m": - replacement = loggingEvent.message; - break; - case "n": - replacement = "\n"; - break; - case "p": - replacement = loggingEvent.level.toString(); - break; - case "r": - replacement = "" + loggingEvent.startTime.toLocaleTimeString(); - break; - case "%": - replacement = "%"; - break; - default: - replacement = matchedString; - break; - } - // Format the replacement according to any padding or - // truncation specified - - var len; - - // First, truncation - if (truncation) { - len = parseInt(truncation.substr(1), 10); - replacement = replacement.substring(0, len); - } - // Next, padding - if (padding) { - if (padding.charAt(0) == "-") { - len = parseInt(padding.substr(1), 10); - // Right pad with spaces - while (replacement.length < len) { - replacement += " "; - } - } else { - len = parseInt(padding, 10); - // Left pad with spaces - while (replacement.length < len) { - replacement = " " + replacement; - } - } - } - formattedString += replacement; - } - searchString = searchString.substr(result.index + result[0].length); - } - return formattedString; - }; - - }; - function replaceConsole(logger) { function replaceWith (fn) { return function() { @@ -634,10 +638,13 @@ module.exports = function (fileSystem, standardOutput, configPaths) { } - //set ourselves up if we can find a default log4js.json - configure(findConfiguration()); - //replace console.log, etc with log4js versions - replaceConsole(getLogger("console")); + //do we already have appenders? + if (!appenders.count) { + //set ourselves up if we can find a default log4js.json + configure(findConfiguration()); + //replace console.log, etc with log4js versions + replaceConsole(getLogger("console")); + } return { getLogger: getLogger, diff --git a/test/logging.js b/test/logging.js index 0e4cc41..b108ec1 100644 --- a/test/logging.js +++ b/test/logging.js @@ -247,7 +247,9 @@ vows.describe('log4js').addBatch({ 'with no appenders defined' : { topic: function() { - var logger, message, log4js = require('../lib/log4js')(null, function (msg) { message = msg; } ); + var logger, message, log4jsFn = require('../lib/log4js'), log4js; + log4jsFn().clearAppenders(); + log4js = log4jsFn(null, function (msg) { message = msg; } ); logger = log4js.getLogger("some-logger"); logger.debug("This is a test"); return message; @@ -364,10 +366,15 @@ vows.describe('log4js').addBatch({ }, fakeConsoleLog = function (msg) { message = msg; }, fakeRequirePath = [ '/a/b/c', '/some/other/path', '/path/to/config', '/some/later/directory' ], - log4js = require('../lib/log4js')(fakeFS, fakeConsoleLog, fakeRequirePath), + log4jsFn = require('../lib/log4js'), + log4js, logger; + + log4jsFn().clearAppenders(); + log4js = log4jsFn(fakeFS, fakeConsoleLog, fakeRequirePath); logger = log4js.getLogger('a-test'); logger.debug("this is a test"); + return [ pathsChecked, message ]; }, @@ -478,8 +485,8 @@ vows.describe('log4js').addBatch({ topic: function() { var log4js = require('../lib/log4js')(), logEvents = [], logger; log4js.clearAppenders(); - log4js.addAppender(log4js.logLevelFilter('ERROR', function(evt) { logEvents.push(evt); })); - logger = log4js.getLogger(); + log4js.addAppender(log4js.logLevelFilter('ERROR', function(evt) { logEvents.push(evt); }), "logLevelTest"); + logger = log4js.getLogger("logLevelTest"); logger.debug('this should not trigger an event'); logger.warn('neither should this'); logger.error('this should, though'); @@ -535,6 +542,19 @@ vows.describe('log4js').addBatch({ assert.equal(logEvent.message, "tracing"); assert.equal(logEvent.level.toString(), "TRACE"); } + }, + + 'configuration persistence' : { + 'should maintain appenders between requires': function () { + var logEvent, firstLog4js = require('../lib/log4js')(), secondLog4js; + firstLog4js.clearAppenders(); + firstLog4js.addAppender(function(evt) { logEvent = evt; }); + + secondLog4js = require('../lib/log4js')(); + secondLog4js.getLogger().info("This should go to the appender defined in firstLog4js"); + + assert.equal(logEvent.message, "This should go to the appender defined in firstLog4js"); + } } }).export(module);