diff --git a/lib/appenders/file.js b/lib/appenders/file.js index 6788d30..e4cab1a 100644 --- a/lib/appenders/file.js +++ b/lib/appenders/file.js @@ -6,7 +6,8 @@ var layouts = require('../layouts') , streams = require('../streams') , os = require('os') , eol = os.EOL || '\n' -, openFiles = []; +, openFiles = [] +, levels = require('../levels'); //close open files on process exit. process.on('exit', function() { @@ -26,7 +27,7 @@ process.on('exit', function() { * @param numBackups - the number of log files to keep after logSize * has been reached (default 5) */ -function fileAppender (file, layout, logSize, numBackups) { +function fileAppender (file, layout, logSize, numBackups, compress) { var bytesWritten = 0; file = path.normalize(file); layout = layout || layouts.basicLayout; @@ -40,7 +41,8 @@ function fileAppender (file, layout, logSize, numBackups) { stream = new streams.RollingFileStream( file, fileSize, - numFiles + numFiles, + { "compress": compress } ); } else { stream = fs.createWriteStream( @@ -60,10 +62,11 @@ function fileAppender (file, layout, logSize, numBackups) { // push file to the stack of open handlers openFiles.push(logFile); - + return function(loggingEvent) { logFile.write(layout(loggingEvent) + eol, "utf8"); }; + } function configure(config, options) { @@ -76,7 +79,7 @@ function configure(config, options) { config.filename = path.join(options.cwd, config.filename); } - return fileAppender(config.filename, layout, config.maxLogSize, config.backups); + return fileAppender(config.filename, layout, config.maxLogSize, config.backups, config.compress); } function shutdown(cb) { diff --git a/lib/levels.js b/lib/levels.js index 0637099..54a8cf3 100644 --- a/lib/levels.js +++ b/lib/levels.js @@ -63,6 +63,7 @@ module.exports = { WARN: new Level(30000, "WARN"), ERROR: new Level(40000, "ERROR"), FATAL: new Level(50000, "FATAL"), + MARK: new Level(9007199254740992, "MARK"), // 2^53 OFF: new Level(Number.MAX_VALUE, "OFF"), toLevel: toLevel }; diff --git a/lib/log4js.js b/lib/log4js.js index e5dcacb..b908fb7 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -94,6 +94,22 @@ function getBufferedLogger(categoryName) { return logger; } +function normalizeCategory (category) { + return category + '.'; +} + +function doesLevelEntryContainsLogger (levelCategory, loggerCategory) { + var normalizedLevelCategory = normalizeCategory(levelCategory); + var normalizedLoggerCategory = normalizeCategory(loggerCategory); + return normalizedLoggerCategory.substring(0, normalizedLevelCategory.length) == normalizedLevelCategory; +} + +function doesAppenderContainsLogger (appenderCategory, loggerCategory) { + var normalizedAppenderCategory = normalizeCategory(appenderCategory); + var normalizedLoggerCategory = normalizeCategory(loggerCategory); + return normalizedLoggerCategory.substring(0, normalizedAppenderCategory.length) == normalizedAppenderCategory; +} + /** * Get a logger instance. Instance is cached on categoryName level. @@ -101,32 +117,51 @@ function getBufferedLogger(categoryName) { * @return {Logger} instance of logger for the category * @static */ -function getLogger (categoryName) { +function getLogger (loggerCategoryName) { // Use default logger if categoryName is not specified or invalid - if (typeof categoryName !== "string") { - categoryName = Logger.DEFAULT_CATEGORY; + if (typeof loggerCategoryName !== "string") { + loggerCategoryName = Logger.DEFAULT_CATEGORY; } - var appenderList; - if (!hasLogger(categoryName)) { + if (!hasLogger(loggerCategoryName)) { + + var level = undefined; + + // If there's a "levels" entry in the configuration + if (levels.config) { + // Goes through the categories in the levels configuration entry, starting by the "higher" ones. + var keys = Object.keys(levels.config).sort(); + for (var idx = 0; idx < keys.length; idx++) { + var levelCategory = keys[idx]; + if (doesLevelEntryContainsLogger(levelCategory, loggerCategoryName)) { + // level for the logger + level = levels.config[levelCategory]; + } + } + } + // 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); - }); + loggers[loggerCategoryName] = new Logger(loggerCategoryName, level); + + var appenderList; + for(var appenderCategory in appenders) { + if (doesAppenderContainsLogger(appenderCategory, loggerCategoryName)) { + appenderList = appenders[appenderCategory]; + appenderList.forEach(function(appender) { + loggers[loggerCategoryName].addListener("log", appender); + }); + } } if (appenders[ALL_CATEGORIES]) { appenderList = appenders[ALL_CATEGORIES]; appenderList.forEach(function(appender) { - loggers[categoryName].addListener("log", appender); + loggers[loggerCategoryName].addListener("log", appender); }); } } - return loggers[categoryName]; + return loggers[loggerCategoryName]; } /** @@ -143,13 +178,19 @@ function addAppender () { args = args[0]; } - args.forEach(function(category) { - addAppenderToCategory(appender, category); + args.forEach(function(appenderCategory) { + addAppenderToCategory(appender, appenderCategory); - if (category === ALL_CATEGORIES) { + if (appenderCategory === ALL_CATEGORIES) { addAppenderToAllLoggers(appender); - } else if (hasLogger(category)) { - loggers[category].addListener("log", appender); + } else { + + for(var loggerCategory in loggers) { + if (doesAppenderContainsLogger(appenderCategory,loggerCategory)) { + loggers[loggerCategory].addListener("log", appender); + } + } + } }); } @@ -195,14 +236,19 @@ function configureAppenders(appenderList, options) { } } -function configureLevels(levels) { - if (levels) { - for (var category in levels) { - if (levels.hasOwnProperty(category)) { - if(category === ALL_CATEGORIES) { - setGlobalLogLevel(levels[category]); +function configureLevels(_levels) { + levels.config = _levels; // Keep it so we can create loggers later using this cfg + if (_levels) { + var keys = Object.keys(levels.config).sort(); + for (var idx in keys) { + var category = keys[idx]; + if(category === ALL_CATEGORIES) { + setGlobalLogLevel(_levels[category]); + } + for(var loggerCategory in loggers) { + if (doesLevelEntryContainsLogger(category, loggerCategory)) { + loggers[loggerCategory].setLevel(_levels[category]); } - getLogger(category).setLevel(levels[category]); } } } @@ -233,8 +279,8 @@ function loadConfigurationFile(filename) { function configureOnceOff(config, options) { if (config) { try { - configureAppenders(config.appenders, options); configureLevels(config.levels); + configureAppenders(config.appenders, options); if (config.replaceConsole) { replaceConsole(); diff --git a/lib/logger.js b/lib/logger.js index 3615a18..67bb35d 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -63,7 +63,7 @@ Logger.prototype.isLevelEnabled = function(otherLevel) { return this.level.isLessThanOrEqualTo(otherLevel); }; -['Trace','Debug','Info','Warn','Error','Fatal'].forEach( +['Trace','Debug','Info','Warn','Error','Fatal', 'Mark'].forEach( function(levelString) { var level = levels.toLevel(levelString); Logger.prototype['is'+levelString+'Enabled'] = function() { diff --git a/lib/streams/BaseRollingFileStream.js b/lib/streams/BaseRollingFileStream.js index 572794c..9c441ad 100644 --- a/lib/streams/BaseRollingFileStream.js +++ b/lib/streams/BaseRollingFileStream.js @@ -16,7 +16,11 @@ module.exports = BaseRollingFileStream; function BaseRollingFileStream(filename, options) { debug("In BaseRollingFileStream"); this.filename = filename; - this.options = options || { encoding: 'utf8', mode: parseInt('0644', 8), flags: 'a' }; + this.options = options || {}; + this.options.encoding = this.options.encoding || 'utf8'; + this.options.mode = this.options.mode || parseInt('0644', 8); + this.options.flags = this.options.flags || 'a'; + this.currentSize = 0; function currentFileSize(file) { diff --git a/lib/streams/RollingFileStream.js b/lib/streams/RollingFileStream.js index c9d35dd..1b0a0cf 100644 --- a/lib/streams/RollingFileStream.js +++ b/lib/streams/RollingFileStream.js @@ -3,6 +3,8 @@ var BaseRollingFileStream = require('./BaseRollingFileStream') , debug = require('../debug')('RollingFileStream') , util = require('util') , path = require('path') +, child_process = require('child_process') +, zlib = require("zlib") , fs = require('fs') , async = require('async'); @@ -25,7 +27,7 @@ function RollingFileStream (filename, size, backups, options) { util.inherits(RollingFileStream, BaseRollingFileStream); RollingFileStream.prototype.shouldRoll = function() { - debug("should roll with current size %d, and max size %d", this.currentSize, this.size); + debug("should roll with current size " + this.currentSize + " and max size " + this.size); return this.currentSize >= this.size; }; @@ -38,6 +40,7 @@ RollingFileStream.prototype.roll = function(filename, callback) { } function index(filename_) { + debug('Calculating index of '+filename_); return parseInt(filename_.substring((path.basename(filename) + '.').length), 10) || 0; } @@ -51,16 +54,42 @@ RollingFileStream.prototype.roll = function(filename, callback) { } } + function compress (filename, cb) { + + var gzip = zlib.createGzip(); + var inp = fs.createReadStream(filename); + var out = fs.createWriteStream(filename+".gz"); + inp.pipe(gzip).pipe(out); + fs.unlink(filename, cb); + + } + function increaseFileIndex (fileToRename, cb) { var idx = index(fileToRename); debug('Index of ' + fileToRename + ' is ' + idx); if (idx < that.backups) { + + var ext = path.extname(fileToRename); + var destination = filename + '.' + (idx+1); + if (that.options.compress && /^gz$/.test(ext.substring(1))) { + destination+=ext; + } //on windows, you can get a EEXIST error if you rename a file to an existing file //so, we'll try to delete the file we're renaming to first - fs.unlink(filename + '.' + (idx+1), function (err) { + fs.unlink(destination, function (err) { //ignore err: if we could not delete, it's most likely that it doesn't exist - debug('Renaming ' + fileToRename + ' -> ' + filename + '.' + (idx+1)); - fs.rename(path.join(path.dirname(filename), fileToRename), filename + '.' + (idx + 1), cb); + debug('Renaming ' + fileToRename + ' -> ' + destination); + fs.rename(path.join(path.dirname(filename), fileToRename), destination, function(err) { + if (err) { + cb(err); + } else { + if (that.options.compress && ext!=".gz") { + compress(destination, cb); + } else { + cb(); + } + } + }); }); } else { cb(); diff --git a/test/fileAppender-test.js b/test/fileAppender-test.js index 9b4bd0f..b313400 100644 --- a/test/fileAppender-test.js +++ b/test/fileAppender-test.js @@ -5,6 +5,7 @@ var vows = require('vows') , sandbox = require('sandboxed-module') , log4js = require('../lib/log4js') , assert = require('assert') +, zlib = require('zlib') , EOL = require('os').EOL || '\n'; log4js.clearAppenders(); @@ -104,6 +105,70 @@ vows.describe('log4js fileAppender').addBatch({ ); } }, + 'fileAppender subcategories': { + topic: function() { + var that = this; + + log4js.clearAppenders(); + + function addAppender(cat) { + var testFile = path.join(__dirname, '/fa-subcategories-test-'+cat.join('-').replace(/\./g, "_")+'.log'); + remove(testFile); + log4js.addAppender(require('../lib/appenders/file').appender(testFile), cat); + return testFile; + } + + var file_sub1 = addAppender([ 'sub1']); + + var file_sub1_sub12$sub1_sub13 = addAppender([ 'sub1.sub12', 'sub1.sub13' ]); + + var file_sub1_sub12 = addAppender([ 'sub1.sub12' ]); + + + var logger_sub1_sub12_sub123 = log4js.getLogger('sub1.sub12.sub123'); + + var logger_sub1_sub13_sub133 = log4js.getLogger('sub1.sub13.sub133'); + + var logger_sub1_sub14 = log4js.getLogger('sub1.sub14'); + + var logger_sub2 = log4js.getLogger('sub2'); + + + logger_sub1_sub12_sub123.info('sub1_sub12_sub123'); + + logger_sub1_sub13_sub133.info('sub1_sub13_sub133'); + + logger_sub1_sub14.info('sub1_sub14'); + + logger_sub2.info('sub2'); + + + setTimeout(function() { + that.callback(null, { + file_sub1: fs.readFileSync(file_sub1).toString(), + file_sub1_sub12$sub1_sub13: fs.readFileSync(file_sub1_sub12$sub1_sub13).toString(), + file_sub1_sub12: fs.readFileSync(file_sub1_sub12).toString() + }); + }, 3000); + }, + 'check file contents': function (err, fileContents) { + + // everything but category 'sub2' + assert.match(fileContents.file_sub1, /^(\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}\] \[INFO\] (sub1.sub12.sub123 - sub1_sub12_sub123|sub1.sub13.sub133 - sub1_sub13_sub133|sub1.sub14 - sub1_sub14)[\s\S]){3}$/); + assert.ok(fileContents.file_sub1.match(/sub123/) && fileContents.file_sub1.match(/sub133/) && fileContents.file_sub1.match(/sub14/)); + assert.ok(!fileContents.file_sub1.match(/sub2/)); + + // only catgories starting with 'sub1.sub12' and 'sub1.sub13' + assert.match(fileContents.file_sub1_sub12$sub1_sub13, /^(\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}\] \[INFO\] (sub1.sub12.sub123 - sub1_sub12_sub123|sub1.sub13.sub133 - sub1_sub13_sub133)[\s\S]){2}$/); + assert.ok(fileContents.file_sub1_sub12$sub1_sub13.match(/sub123/) && fileContents.file_sub1_sub12$sub1_sub13.match(/sub133/)); + assert.ok(!fileContents.file_sub1_sub12$sub1_sub13.match(/sub14|sub2/)); + + // only catgories starting with 'sub1.sub12' + assert.match(fileContents.file_sub1_sub12, /^(\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}\] \[INFO\] (sub1.sub12.sub123 - sub1_sub12_sub123)[\s\S]){1}$/); + assert.ok(!fileContents.file_sub1_sub12.match(/sub14|sub2|sub13/)); + + } + }, 'with a max file size and no backups': { topic: function() { var testFile = path.join(__dirname, '/fa-maxFileSize-test.log') @@ -214,6 +279,79 @@ vows.describe('log4js fileAppender').addBatch({ } } } + }, + 'with a max file size and 2 compressed backups': { + topic: function() { + var testFile = path.join(__dirname, '/fa-maxFileSize-with-backups-compressed-test.log') + , logger = log4js.getLogger('max-file-size-backups'); + remove(testFile); + remove(testFile+'.1.gz'); + remove(testFile+'.2.gz'); + + //log file of 50 bytes maximum, 2 backups + log4js.clearAppenders(); + log4js.addAppender( + require('../lib/appenders/file').appender(testFile, log4js.layouts.basicLayout, 50, 2, true), + 'max-file-size-backups' + ); + logger.info("This is the first log message."); + logger.info("This is the second log message."); + logger.info("This is the third log message."); + logger.info("This is the fourth log message."); + var that = this; + //give the system a chance to open the stream + setTimeout(function() { + fs.readdir(__dirname, function(err, files) { + if (files) { + that.callback(null, files.sort()); + } else { + that.callback(err, files); + } + }); + }, 1000); + }, + 'the log files': { + topic: function(files) { + var logFiles = files.filter( + function(file) { return file.indexOf('fa-maxFileSize-with-backups-compressed-test.log') > -1; } + ); + return logFiles; + }, + 'should be 3': function (files) { + assert.equal(files.length, 3); + }, + 'should be named in sequence': function (files) { + assert.deepEqual(files, [ + 'fa-maxFileSize-with-backups-compressed-test.log', + 'fa-maxFileSize-with-backups-compressed-test.log.1.gz', + 'fa-maxFileSize-with-backups-compressed-test.log.2.gz' + ]); + }, + 'and the contents of the first file': { + topic: function(logFiles) { + fs.readFile(path.join(__dirname, logFiles[0]), "utf8", this.callback); + }, + 'should be the last log message': function(contents) { + assert.include(contents, 'This is the fourth log message.'); + } + }, + 'and the contents of the second file': { + topic: function(logFiles) { + zlib.gunzip(fs.readFileSync(path.join(__dirname, logFiles[1])), this.callback); + }, + 'should be the third log message': function(contents) { + assert.include(contents.toString('utf8'), 'This is the third log message.'); + } + }, + 'and the contents of the third file': { + topic: function(logFiles) { + zlib.gunzip(fs.readFileSync(path.join(__dirname, logFiles[2])), this.callback); + }, + 'should be the second log message': function(contents) { + assert.include(contents.toString('utf8'), 'This is the second log message.'); + } + } + } } }).addBatch({ 'configure' : { diff --git a/test/levels-test.js b/test/levels-test.js index 99dd1fc..9a0fdfc 100644 --- a/test/levels-test.js +++ b/test/levels-test.js @@ -43,6 +43,7 @@ vows.describe('levels').addBatch({ assert.isNotNull(levels.WARN); assert.isNotNull(levels.ERROR); assert.isNotNull(levels.FATAL); + assert.isNotNull(levels.MARK); assert.isNotNull(levels.OFF); }, 'ALL': { @@ -56,7 +57,8 @@ vows.describe('levels').addBatch({ levels.INFO, levels.WARN, levels.ERROR, - levels.FATAL, + levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -70,6 +72,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -84,6 +87,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -99,6 +103,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -113,6 +118,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -127,6 +133,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -141,6 +148,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -154,6 +162,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -168,6 +177,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ] ); @@ -180,6 +190,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ]); assertThat(info).isNotLessThanOrEqualTo([levels.ALL, levels.TRACE, levels.DEBUG]); @@ -190,6 +201,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ]); }, @@ -202,6 +214,7 @@ vows.describe('levels').addBatch({ levels.WARN, levels.ERROR, levels.FATAL, + levels.MARK, levels.OFF ]); } @@ -209,7 +222,7 @@ vows.describe('levels').addBatch({ 'WARN': { topic: levels.WARN, 'should be less than ERROR': function(warn) { - assertThat(warn).isLessThanOrEqualTo([levels.ERROR, levels.FATAL, levels.OFF]); + assertThat(warn).isLessThanOrEqualTo([levels.ERROR, levels.FATAL, levels.MARK, levels.OFF]); assertThat(warn).isNotLessThanOrEqualTo([ levels.ALL, levels.TRACE, @@ -224,7 +237,7 @@ vows.describe('levels').addBatch({ levels.DEBUG, levels.INFO ]); - assertThat(warn).isNotGreaterThanOrEqualTo([levels.ERROR, levels.FATAL, levels.OFF]); + assertThat(warn).isNotGreaterThanOrEqualTo([levels.ERROR, levels.FATAL, levels.MARK, levels.OFF]); }, 'should only be equal to WARN': function(trace) { assertThat(trace).isEqualTo([levels.toLevel("WARN")]); @@ -242,7 +255,7 @@ vows.describe('levels').addBatch({ 'ERROR': { topic: levels.ERROR, 'should be less than FATAL': function(error) { - assertThat(error).isLessThanOrEqualTo([levels.FATAL, levels.OFF]); + assertThat(error).isLessThanOrEqualTo([levels.FATAL, levels.MARK, levels.OFF]); assertThat(error).isNotLessThanOrEqualTo([ levels.ALL, levels.TRACE, @@ -259,7 +272,7 @@ vows.describe('levels').addBatch({ levels.INFO, levels.WARN ]); - assertThat(error).isNotGreaterThanOrEqualTo([levels.FATAL, levels.OFF]); + assertThat(error).isNotGreaterThanOrEqualTo([levels.FATAL, levels.MARK, levels.OFF]); }, 'should only be equal to ERROR': function(trace) { assertThat(trace).isEqualTo([levels.toLevel("ERROR")]); @@ -270,6 +283,7 @@ vows.describe('levels').addBatch({ levels.INFO, levels.WARN, levels.FATAL, + levels.MARK, levels.OFF ]); } @@ -277,7 +291,7 @@ vows.describe('levels').addBatch({ 'FATAL': { topic: levels.FATAL, 'should be less than OFF': function(fatal) { - assertThat(fatal).isLessThanOrEqualTo([levels.OFF]); + assertThat(fatal).isLessThanOrEqualTo([levels.MARK, levels.OFF]); assertThat(fatal).isNotLessThanOrEqualTo([ levels.ALL, levels.TRACE, @@ -295,8 +309,8 @@ vows.describe('levels').addBatch({ levels.INFO, levels.WARN, levels.ERROR - ]); - assertThat(fatal).isNotGreaterThanOrEqualTo([levels.OFF]); + ]); + assertThat(fatal).isNotGreaterThanOrEqualTo([levels.MARK, levels.OFF]); }, 'should only be equal to FATAL': function(fatal) { assertThat(fatal).isEqualTo([levels.toLevel("FATAL")]); @@ -306,7 +320,48 @@ vows.describe('levels').addBatch({ levels.DEBUG, levels.INFO, levels.WARN, - levels.ERROR, + levels.ERROR, + levels.MARK, + levels.OFF + ]); + } + }, + 'MARK': { + topic: levels.MARK, + 'should be less than OFF': function(mark) { + assertThat(mark).isLessThanOrEqualTo([levels.OFF]); + assertThat(mark).isNotLessThanOrEqualTo([ + levels.ALL, + levels.TRACE, + levels.DEBUG, + levels.INFO, + levels.WARN, + levels.FATAL, + levels.ERROR + ]); + }, + 'should be greater than FATAL': function(mark) { + assertThat(mark).isGreaterThanOrEqualTo([ + levels.ALL, + levels.TRACE, + levels.DEBUG, + levels.INFO, + levels.WARN, + levels.ERROR, + levels.FATAL + ]); + assertThat(mark).isNotGreaterThanOrEqualTo([levels.OFF]); + }, + 'should only be equal to MARK': function(mark) { + assertThat(mark).isEqualTo([levels.toLevel("MARK")]); + assertThat(mark).isNotEqualTo([ + levels.ALL, + levels.TRACE, + levels.DEBUG, + levels.INFO, + levels.WARN, + levels.ERROR, + levels.FATAL, levels.OFF ]); } @@ -321,7 +376,8 @@ vows.describe('levels').addBatch({ levels.INFO, levels.WARN, levels.ERROR, - levels.FATAL + levels.FATAL, + levels.MARK ]); }, 'should be greater than everything': function(off) { @@ -332,7 +388,8 @@ vows.describe('levels').addBatch({ levels.INFO, levels.WARN, levels.ERROR, - levels.FATAL + levels.FATAL, + levels.MARK ]); }, 'should only be equal to OFF': function(off) { @@ -344,7 +401,8 @@ vows.describe('levels').addBatch({ levels.INFO, levels.WARN, levels.ERROR, - levels.FATAL + levels.FATAL, + levels.MARK ]); } } @@ -353,14 +411,14 @@ vows.describe('levels').addBatch({ topic: levels.INFO, 'should handle string arguments': function(info) { assertThat(info).isGreaterThanOrEqualTo(["all", "trace", "debug"]); - assertThat(info).isNotGreaterThanOrEqualTo(['warn', 'ERROR', 'Fatal', 'off']); + assertThat(info).isNotGreaterThanOrEqualTo(['warn', 'ERROR', 'Fatal', 'MARK', 'off']); } }, 'isLessThanOrEqualTo': { topic: levels.INFO, 'should handle string arguments': function(info) { assertThat(info).isNotLessThanOrEqualTo(["all", "trace", "debug"]); - assertThat(info).isLessThanOrEqualTo(['warn', 'ERROR', 'Fatal', 'off']); + assertThat(info).isLessThanOrEqualTo(['warn', 'ERROR', 'Fatal', 'MARK', 'off']); } }, 'isEqualTo': { diff --git a/test/subcategories-test.js b/test/subcategories-test.js new file mode 100644 index 0000000..32ff9b2 --- /dev/null +++ b/test/subcategories-test.js @@ -0,0 +1,86 @@ +"use strict"; +var assert = require('assert') +, vows = require('vows') +, sandbox = require('sandboxed-module') +, log4js = require('../lib/log4js') +, levels = require('../lib/levels'); + +vows.describe('subcategories').addBatch({ + 'loggers created after levels configuration is loaded': { + topic: function() { + + log4js.configure({ + "levels": { + "sub1": "WARN", + "sub1.sub11": "TRACE", + "sub1.sub11.sub111": "WARN", + "sub1.sub12": "INFO" + } + }, { reloadSecs: 30 }) + + return { + "sub1": log4js.getLogger('sub1'), // WARN + "sub11": log4js.getLogger('sub1.sub11'), // TRACE + "sub111": log4js.getLogger('sub1.sub11.sub111'), // WARN + "sub12": log4js.getLogger('sub1.sub12'), // INFO + + "sub13": log4js.getLogger('sub1.sub13'), // Inherits sub1: WARN + "sub112": log4js.getLogger('sub1.sub11.sub112'), // Inherits sub1.sub11: TRACE + "sub121": log4js.getLogger('sub1.sub12.sub121'), // Inherits sub12: INFO + "sub0": log4js.getLogger('sub0') // Not defined, not inherited: TRACE + }; + }, + 'check logger levels': function(loggers) { + assert.equal(loggers.sub1.level, levels.WARN); + assert.equal(loggers.sub11.level, levels.TRACE); + assert.equal(loggers.sub111.level, levels.WARN); + assert.equal(loggers.sub12.level, levels.INFO); + + assert.equal(loggers.sub13.level, levels.WARN); + assert.equal(loggers.sub112.level, levels.TRACE); + assert.equal(loggers.sub121.level, levels.INFO); + assert.equal(loggers.sub0.level, levels.TRACE); + } + }, + 'loggers created before levels configuration is loaded': { + topic: function() { + + var loggers = { + "sub1": log4js.getLogger('sub1'), // WARN + "sub11": log4js.getLogger('sub1.sub11'), // TRACE + "sub111": log4js.getLogger('sub1.sub11.sub111'), // WARN + "sub12": log4js.getLogger('sub1.sub12'), // INFO + + "sub13": log4js.getLogger('sub1.sub13'), // Inherits sub1: WARN + "sub112": log4js.getLogger('sub1.sub11.sub112'), // Inherits sub1.sub11: TRACE + "sub121": log4js.getLogger('sub1.sub12.sub121'), // Inherits sub12: INFO + "sub0": log4js.getLogger('sub0') // Not defined, not inherited: TRACE + }; + + + log4js.configure({ + "levels": { + "sub1": "WARN", + "sub1.sub11": "TRACE", + "sub1.sub11.sub111": "WARN", + "sub1.sub12": "INFO" + } + }, { reloadSecs: 30 }) + + return loggers; + + + }, + 'check logger levels': function(loggers) { + assert.equal(loggers.sub1.level, levels.WARN); + assert.equal(loggers.sub11.level, levels.TRACE); + assert.equal(loggers.sub111.level, levels.WARN); + assert.equal(loggers.sub12.level, levels.INFO); + + assert.equal(loggers.sub13.level, levels.WARN); + assert.equal(loggers.sub112.level, levels.TRACE); + assert.equal(loggers.sub121.level, levels.INFO); + assert.equal(loggers.sub0.level, levels.TRACE); + } + } +}).exportTo(module);