From 8e0a0f9f5353f088c2f239e475f5009bfa51d80e Mon Sep 17 00:00:00 2001 From: Blake Ambrose Date: Wed, 8 Jun 2016 11:51:36 +1000 Subject: [PATCH 1/6] Added ability to add custom log levels to client, simillar to log4j for java --- lib/levels.js | 9 +++-- lib/log4js.js | 37 ++++++++++++-------- lib/logger.js | 40 ++++++++++++++-------- package.json | 2 +- test/newLevel-test.js | 79 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 32 deletions(-) create mode 100644 test/newLevel-test.js diff --git a/lib/levels.js b/lib/levels.js index c2816fc..cb9243a 100644 --- a/lib/levels.js +++ b/lib/levels.js @@ -16,6 +16,10 @@ function toLevel(sArg, defaultLevel) { if (!sArg) { return defaultLevel; } + if (sArg instanceof Level) { + module.exports[sArg.toString()] = sArg; + return sArg; + } if (typeof sArg === "string") { return module.exports[sArg.toUpperCase()] || defaultLevel; } @@ -41,7 +45,7 @@ Level.prototype.isGreaterThanOrEqualTo = function(otherLevel) { }; Level.prototype.isEqualTo = function(otherLevel) { - if (typeof otherLevel == "string") { + if (typeof otherLevel === "string") { otherLevel = toLevel(otherLevel); } return this.level === otherLevel.level; @@ -57,5 +61,6 @@ module.exports = { FATAL: new Level(50000, "FATAL"), MARK: new Level(9007199254740992, "MARK"), // 2^53 OFF: new Level(Number.MAX_VALUE, "OFF"), - toLevel: toLevel + toLevel: toLevel, + Level: Level }; diff --git a/lib/log4js.js b/lib/log4js.js index 8ad03f6..c16b6d6 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -70,6 +70,15 @@ function hasLogger(logger) { return loggers.hasOwnProperty(logger); } +levels.forName = function(levelStr, levelVal) { + var level; + if (typeof levelStr === "string" && typeof levelVal === "number") { + var levelUpper = levelStr.toUpperCase(); + level = new levels.Level(levelVal, levelUpper); + loggerModule.addLevelMethods(level); + } + return level; +}; function getBufferedLogger(categoryName) { var base_logger = getLogger(categoryName); @@ -97,7 +106,7 @@ function normalizeCategory (category) { return category + '.'; } -function doesLevelEntryContainsLogger (levelCategory, loggerCategory) { +function doesLevelEntryContainsLogger (levelCategory, loggerCategory) { var normalizedLevelCategory = normalizeCategory(levelCategory); var normalizedLoggerCategory = normalizeCategory(loggerCategory); return normalizedLoggerCategory.substring(0, normalizedLevelCategory.length) == normalizedLevelCategory; //jshint ignore:line @@ -142,7 +151,7 @@ function getLogger (loggerCategoryName) { } } /* jshint +W073 */ - + // Create the logger for this name if it doesn't already exist loggers[loggerCategoryName] = new Logger(loggerCategoryName, level); @@ -165,7 +174,7 @@ function getLogger (loggerCategoryName) { }); } } - + return loggers[loggerCategoryName]; } @@ -182,10 +191,10 @@ function addAppender () { if (Array.isArray(args[0])) { args = args[0]; } - + args.forEach(function(appenderCategory) { addAppenderToCategory(appender, appenderCategory); - + if (appenderCategory === ALL_CATEGORIES) { addAppenderToAllLoggers(appender); } else { @@ -195,7 +204,7 @@ function addAppender () { loggers[loggerCategory].addListener("log", appender); } } - + } }); } @@ -288,7 +297,7 @@ function configureOnceOff(config, options) { try { configureLevels(config.levels); configureAppenders(config.appenders, options); - + if (config.replaceConsole) { replaceConsole(); } else { @@ -296,7 +305,7 @@ function configureOnceOff(config, options) { } } catch (e) { throw new Error( - "Problem reading log4js config " + util.inspect(config) + + "Problem reading log4js config " + util.inspect(config) + ". Error was \"" + e.message + "\" (" + e.stack + ")" ); } @@ -306,7 +315,7 @@ function configureOnceOff(config, options) { function reloadConfiguration(options) { var mtime = getMTime(configState.filename); if (!mtime) return; - + if (configState.lastMTime && (mtime.getTime() > configState.lastMTime.getTime())) { configureOnceOff(loadConfigurationFile(configState.filename), options); } @@ -337,7 +346,7 @@ function configure(configurationFileOrObject, options) { var config = configurationFileOrObject; config = config || process.env.LOG4JS_CONFIG; options = options || {}; - + if (config === undefined || config === null || typeof(config) === 'string') { if (options.reloadSecs) { initReloadConfiguration(config, options); @@ -463,19 +472,19 @@ module.exports = { getLogger: getLogger, getDefaultLogger: getDefaultLogger, hasLogger: hasLogger, - + addAppender: addAppender, loadAppender: loadAppender, clearAppenders: clearAppenders, configure: configure, shutdown: shutdown, - + replaceConsole: replaceConsole, restoreConsole: restoreConsole, - + levels: levels, setGlobalLogLevel: setGlobalLogLevel, - + layouts: layouts, appenders: {}, appenderMakers: appenderMakers, diff --git a/lib/logger.js b/lib/logger.js index 2128312..984bd38 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -68,24 +68,33 @@ Logger.prototype.isLevelEnabled = function(otherLevel) { ['Trace','Debug','Info','Warn','Error','Fatal', 'Mark'].forEach( function(levelString) { - var level = levels.toLevel(levelString); - Logger.prototype['is'+levelString+'Enabled'] = function() { - return this.isLevelEnabled(level); - }; - - Logger.prototype[levelString.toLowerCase()] = function () { - if (logWritesEnabled && this.isLevelEnabled(level)) { - var numArgs = arguments.length; - var args = new Array(numArgs); - for (var i = 0; i < numArgs; i++) { - args[i] = arguments[i]; - } - this._log(level, args); - } - }; + addLevelMethods(levelString); } ); +function addLevelMethods(level) { + level = levels.toLevel(level); + + var levelStrLower = level.toString().toLowerCase(); + var levelMethod = levelStrLower.replace(/_([a-z])/g, function(g) { return g[1].toUpperCase(); } ); + var isLevelMethod = levelMethod[0].toUpperCase() + levelMethod.slice(1); + + Logger.prototype['is'+isLevelMethod+'Enabled'] = function() { + return this.isLevelEnabled(level.toString()); + }; + + Logger.prototype[levelMethod] = function () { + if (logWritesEnabled && this.isLevelEnabled(level)) { + var numArgs = arguments.length; + var args = new Array(numArgs); + for (var i = 0; i < numArgs; i++) { + args[i] = arguments[i]; + } + this._log(level, args); + } + }; +} + Logger.prototype._log = function(level, data) { var loggingEvent = new LoggingEvent(this.category, level, data, this); this.emit('log', loggingEvent); @@ -111,3 +120,4 @@ exports.LoggingEvent = LoggingEvent; exports.Logger = Logger; exports.disableAllLogWrites = disableAllLogWrites; exports.enableAllLogWrites = enableAllLogWrites; +exports.addLevelMethods = addLevelMethods; \ No newline at end of file diff --git a/package.json b/package.json index dd71e68..320be24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "log4js", - "version": "0.6.36", + "version": "0.6.37", "description": "Port of Log4js to work with node.", "keywords": [ "logging", diff --git a/test/newLevel-test.js b/test/newLevel-test.js new file mode 100644 index 0000000..f340994 --- /dev/null +++ b/test/newLevel-test.js @@ -0,0 +1,79 @@ +"use strict"; +var vows = require('vows') + , assert = require('assert') + , levels = require('../lib/levels') + , log4js = require('../lib/log4js') + , loggerModule = require('../lib/logger') + , Logger = loggerModule.Logger; + +vows.describe('../lib/logger').addBatch({ + 'new log level and methods': { + topic: function () { + log4js.levels.forName("DIAG", 6000); + return new Logger(); + }, + + 'should export new log level in levels module': function (logger) { + assert.isDefined(levels.DIAG); + assert.equal(levels.DIAG.levelStr, "DIAG"); + assert.equal(levels.DIAG.level, 6000); + }, + + 'new log level method is present on logger prototype': function(logger) { + assert.isFunction(logger.diag); + }, + + 'new log level method isLevelEnabled present on logger prototype': function(logger) { + assert.isFunction(logger.isDiagEnabled); + } + }, + + 'new log level and method for underscored levels': { + topic: function () { + log4js.levels.forName("NEW_LEVEL", 6000); + return new Logger(); + }, + + 'should export new log level in levels module': function (logger) { + assert.isDefined(levels.NEW_LEVEL); + assert.equal(levels.NEW_LEVEL.levelStr, "NEW_LEVEL"); + assert.equal(levels.NEW_LEVEL.level, 6000); + }, + + 'new log level method is present on logger prototype in camel case': function(logger) { + assert.isFunction(logger.newLevel); + }, + + 'new log level method isLevelEnabled present on logger prototype': function(logger) { + assert.isFunction(logger.isNewLevelEnabled); + } + }, + + 'log events contain newly created log level': { + topic: function() { + var events = [], + logger = new Logger(); + logger.addListener("log", function (logEvent) { events.push(logEvent); }); + + logger.log(log4js.levels.forName("LVL1", 6000), "Event 1"); + logger.log("LVL1", "Event 2"); + logger.lvl1("Event 3"); + + logger.setLevel(log4js.levels.forName("LVL2", 7000)); + logger.lvl1("Event 4"); + + return events; + }, + + 'events are present with new log level': function(events) { + assert.equal(events[0].level.toString(), "LVL1"); + assert.equal(events[1].level.toString(), "LVL1"); + assert.equal(events[2].level.toString(), "LVL1"); + }, + + 'event should NOT be present if min log level greater than newly created level': + function(events) { + assert.equal(events.length, 3); + } + } +}).exportTo(module); \ No newline at end of file From ccd94fa95b36c39e31cc420e212f650e8c1e2d0c Mon Sep 17 00:00:00 2001 From: Blake Ambrose Date: Wed, 8 Jun 2016 12:13:10 +1000 Subject: [PATCH 2/6] changed npm version back to 0.6.36 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 320be24..dd71e68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "log4js", - "version": "0.6.37", + "version": "0.6.36", "description": "Port of Log4js to work with node.", "keywords": [ "logging", From 76d3438b4f80738f9d345d57dad7440c13b64bff Mon Sep 17 00:00:00 2001 From: Blake Ambrose Date: Wed, 8 Jun 2016 14:21:28 +1000 Subject: [PATCH 3/6] added getLevel to retrieve custom level, added additional coverage tests --- lib/log4js.js | 9 ++++++ test/newLevel-test.js | 69 ++++++++++++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/lib/log4js.js b/lib/log4js.js index c16b6d6..629aed5 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -80,6 +80,15 @@ levels.forName = function(levelStr, levelVal) { return level; }; +levels.getLevel = function(levelStr) { + var level; + if (typeof levelStr === "string") { + var levelUpper = levelStr.toUpperCase(); + level = levels.toLevel(levelStr); + } + return level; +}; + function getBufferedLogger(categoryName) { var base_logger = getLogger(categoryName); var logger = {}; diff --git a/test/newLevel-test.js b/test/newLevel-test.js index f340994..f467a01 100644 --- a/test/newLevel-test.js +++ b/test/newLevel-test.js @@ -7,7 +7,7 @@ var vows = require('vows') , Logger = loggerModule.Logger; vows.describe('../lib/logger').addBatch({ - 'new log level and methods': { + 'creating a new log level': { topic: function () { log4js.levels.forName("DIAG", 6000); return new Logger(); @@ -19,61 +19,88 @@ vows.describe('../lib/logger').addBatch({ assert.equal(levels.DIAG.level, 6000); }, - 'new log level method is present on logger prototype': function(logger) { + 'should create named function on logger prototype': function(logger) { assert.isFunction(logger.diag); }, - 'new log level method isLevelEnabled present on logger prototype': function(logger) { + 'should create isLevelEnabled function on logger prototype': function(logger) { assert.isFunction(logger.isDiagEnabled); - } + }, }, - 'new log level and method for underscored levels': { + 'creating a new log level with underscores': { topic: function () { - log4js.levels.forName("NEW_LEVEL", 6000); + log4js.levels.forName("NEW_LEVEL_OTHER", 6000); return new Logger(); }, - 'should export new log level in levels module': function (logger) { - assert.isDefined(levels.NEW_LEVEL); - assert.equal(levels.NEW_LEVEL.levelStr, "NEW_LEVEL"); - assert.equal(levels.NEW_LEVEL.level, 6000); + 'should export new log level to levels module': function (logger) { + assert.isDefined(levels.NEW_LEVEL_OTHER); + assert.equal(levels.NEW_LEVEL_OTHER.levelStr, "NEW_LEVEL_OTHER"); + assert.equal(levels.NEW_LEVEL_OTHER.level, 6000); }, - 'new log level method is present on logger prototype in camel case': function(logger) { - assert.isFunction(logger.newLevel); + 'should create named function on logger prototype in camel case': function(logger) { + assert.isFunction(logger.newLevelOther); }, - 'new log level method isLevelEnabled present on logger prototype': function(logger) { - assert.isFunction(logger.isNewLevelEnabled); + 'should create named isLevelEnabled function on logger prototype in camel case': function(logger) { + assert.isFunction(logger.isNewLevelOtherEnabled); } }, - 'log events contain newly created log level': { + 'creating log events containing newly created log level': { topic: function() { var events = [], logger = new Logger(); logger.addListener("log", function (logEvent) { events.push(logEvent); }); logger.log(log4js.levels.forName("LVL1", 6000), "Event 1"); - logger.log("LVL1", "Event 2"); - logger.lvl1("Event 3"); + logger.log(log4js.levels.getLevel("LVL1"), "Event 2"); + logger.log("LVL1", "Event 3"); + logger.lvl1("Event 4"); logger.setLevel(log4js.levels.forName("LVL2", 7000)); - logger.lvl1("Event 4"); + logger.lvl1("Event 5"); return events; }, - 'events are present with new log level': function(events) { + 'should show log events with new log level': function(events) { assert.equal(events[0].level.toString(), "LVL1"); + assert.equal(events[0].data[0], "Event 1"); + assert.equal(events[1].level.toString(), "LVL1"); + assert.equal(events[1].data[0], "Event 2"); + assert.equal(events[2].level.toString(), "LVL1"); + assert.equal(events[2].data[0], "Event 3"); + + assert.equal(events[3].level.toString(), "LVL1"); + assert.equal(events[3].data[0], "Event 4"); }, - 'event should NOT be present if min log level greater than newly created level': + 'should not be present if min log level is greater than newly created level': function(events) { - assert.equal(events.length, 3); + assert.equal(events.length, 4); + } + }, + + 'calling log with an undefined log level': { + topic: function() { + var events = [], + logger = new Logger(); + logger.addListener("log", function (logEvent) { events.push(logEvent); }); + + logger.log("LEVEL_DOES_NEXT_EXIST", "Event 1"); + logger.log(log4js.levels.forName("LEVEL_DOES_NEXT_EXIST"), "Event 2"); + + return events; + }, + + 'should fallback to the default log level (INFO)': function(events) { + assert.equal(events[0].level.toString(), "INFO"); + assert.equal(events[1].level.toString(), "INFO"); } } }).exportTo(module); \ No newline at end of file From 9768e0b470f1930910a5bda2477c5e871abb6b1d Mon Sep 17 00:00:00 2001 From: Blake Ambrose Date: Wed, 8 Jun 2016 15:31:33 +1000 Subject: [PATCH 4/6] added additional failure test cases --- test/newLevel-test.js | 57 +++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/test/newLevel-test.js b/test/newLevel-test.js index f467a01..9dff0ff 100644 --- a/test/newLevel-test.js +++ b/test/newLevel-test.js @@ -1,7 +1,7 @@ "use strict"; var vows = require('vows') , assert = require('assert') - , levels = require('../lib/levels') + , Level = require('../lib/levels') , log4js = require('../lib/log4js') , loggerModule = require('../lib/logger') , Logger = loggerModule.Logger; @@ -9,14 +9,14 @@ var vows = require('vows') vows.describe('../lib/logger').addBatch({ 'creating a new log level': { topic: function () { - log4js.levels.forName("DIAG", 6000); + Level.forName("DIAG", 6000); return new Logger(); }, 'should export new log level in levels module': function (logger) { - assert.isDefined(levels.DIAG); - assert.equal(levels.DIAG.levelStr, "DIAG"); - assert.equal(levels.DIAG.level, 6000); + assert.isDefined(Level.DIAG); + assert.equal(Level.DIAG.levelStr, "DIAG"); + assert.equal(Level.DIAG.level, 6000); }, 'should create named function on logger prototype': function(logger) { @@ -30,14 +30,14 @@ vows.describe('../lib/logger').addBatch({ 'creating a new log level with underscores': { topic: function () { - log4js.levels.forName("NEW_LEVEL_OTHER", 6000); + Level.forName("NEW_LEVEL_OTHER", 6000); return new Logger(); }, 'should export new log level to levels module': function (logger) { - assert.isDefined(levels.NEW_LEVEL_OTHER); - assert.equal(levels.NEW_LEVEL_OTHER.levelStr, "NEW_LEVEL_OTHER"); - assert.equal(levels.NEW_LEVEL_OTHER.level, 6000); + assert.isDefined(Level.NEW_LEVEL_OTHER); + assert.equal(Level.NEW_LEVEL_OTHER.levelStr, "NEW_LEVEL_OTHER"); + assert.equal(Level.NEW_LEVEL_OTHER.level, 6000); }, 'should create named function on logger prototype in camel case': function(logger) { @@ -55,12 +55,12 @@ vows.describe('../lib/logger').addBatch({ logger = new Logger(); logger.addListener("log", function (logEvent) { events.push(logEvent); }); - logger.log(log4js.levels.forName("LVL1", 6000), "Event 1"); - logger.log(log4js.levels.getLevel("LVL1"), "Event 2"); + logger.log(Level.forName("LVL1", 6000), "Event 1"); + logger.log(Level.getLevel("LVL1"), "Event 2"); logger.log("LVL1", "Event 3"); logger.lvl1("Event 4"); - logger.setLevel(log4js.levels.forName("LVL2", 7000)); + logger.setLevel(Level.forName("LVL2", 7000)); logger.lvl1("Event 5"); return events; @@ -86,6 +86,19 @@ vows.describe('../lib/logger').addBatch({ } }, + 'creating a new log level with incorrect parameters': { + topic: function() { + log4js.levels.forName(9000, "FAIL_LEVEL_1"); + log4js.levels.forName("FAIL_LEVEL_2"); + return new Logger(); + }, + + 'should fail to create the level': function(logger) { + assert.isUndefined(Level.FAIL_LEVEL_1); + assert.isUndefined(Level.FAIL_LEVEL_2); + } + }, + 'calling log with an undefined log level': { topic: function() { var events = [], @@ -93,7 +106,7 @@ vows.describe('../lib/logger').addBatch({ logger.addListener("log", function (logEvent) { events.push(logEvent); }); logger.log("LEVEL_DOES_NEXT_EXIST", "Event 1"); - logger.log(log4js.levels.forName("LEVEL_DOES_NEXT_EXIST"), "Event 2"); + logger.log(Level.forName("LEVEL_DOES_NEXT_EXIST"), "Event 2"); return events; }, @@ -102,5 +115,23 @@ vows.describe('../lib/logger').addBatch({ assert.equal(events[0].level.toString(), "INFO"); assert.equal(events[1].level.toString(), "INFO"); } + }, + + 'creating a new level with an existing level name': { + topic: function() { + var events = [], + logger = new Logger(); + logger.addListener("log", function (logEvent) { events.push(logEvent); }); + + logger.log(log4js.levels.forName("MY_LEVEL", 9000), "Event 1"); + logger.log(log4js.levels.forName("MY_LEVEL", 8000), "Event 1"); + + return events; + }, + + 'should override the existing log level': function(events) { + assert.equal(events[0].level.level, 9000); + assert.equal(events[1].level.level, 8000); + } } }).exportTo(module); \ No newline at end of file From 056575faf4970efa1ef30fa43379a8974784267e Mon Sep 17 00:00:00 2001 From: Blake Ambrose Date: Wed, 8 Jun 2016 15:33:20 +1000 Subject: [PATCH 5/6] fixed up lint failure on test --- test/newLevel-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/newLevel-test.js b/test/newLevel-test.js index 9dff0ff..72dece9 100644 --- a/test/newLevel-test.js +++ b/test/newLevel-test.js @@ -44,7 +44,8 @@ vows.describe('../lib/logger').addBatch({ assert.isFunction(logger.newLevelOther); }, - 'should create named isLevelEnabled function on logger prototype in camel case': function(logger) { + 'should create named isLevelEnabled function on logger prototype in camel case': + function(logger) { assert.isFunction(logger.isNewLevelOtherEnabled); } }, From 81b2328aadd0fa2cc5984cdcacf4df7d35ac0fa0 Mon Sep 17 00:00:00 2001 From: Blake Ambrose Date: Wed, 8 Jun 2016 17:07:05 +1000 Subject: [PATCH 6/6] run travis again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f2d5c7..4a3084d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # log4js-node [![Build Status](https://secure.travis-ci.org/nomiddlename/log4js-node.png?branch=master)](http://travis-ci.org/nomiddlename/log4js-node) [![NPM](https://nodei.co/npm/log4js.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/log4js/) - + This is a conversion of the [log4js](https://github.com/stritti/log4js) framework to work with [node](http://nodejs.org). I've mainly stripped out the browser-specific code and tidied up some of the javascript.