diff --git a/lib/log4js.js b/lib/log4js.js index 8d779ab..b42580b 100644 --- a/lib/log4js.js +++ b/lib/log4js.js @@ -18,8 +18,6 @@ * @fileoverview log4js is a library to log in JavaScript in similar manner * than in log4j for Java. The API should be nearly the same. * - * This file contains all log4js code and is the only file required for logging. - * *

Example:

*
  *  var logging = require('log4js');
@@ -37,6 +35,8 @@
  *  log.trace("trace me" );
  * 
* + * NOTE: the authors below are the original browser-based log4js authors + * don't try to contact them about bugs in this version :) * @version 1.0 * @author Stephan Strittmatter - http://jroller.com/page/stritti * @author Seth Chisamore - http://www.chisamore.com @@ -136,7 +136,9 @@ function configureAppenders(appenderList) { clearAppenders(); if (appenderList) { appenderList.forEach(function(appenderConfig) { - var appender = appenderMakers[appenderConfig.type](appenderConfig); + var appender; + appenderConfig.makers = appenderMakers; + appender = appenderMakers[appenderConfig.type](appenderConfig); if (appender) { addAppender(appender, appenderConfig.category); } else { @@ -144,7 +146,7 @@ function configureAppenders(appenderList) { } }); } else { - addAppender(consoleAppender); + addAppender(consoleAppender()); } } @@ -247,7 +249,6 @@ function configure (configurationFileOrObject) { } if (config) { try { - config.makers = appenderMakers; configureAppenders(config.appenders); configureLevels(config.levels); } catch (e) { @@ -283,10 +284,11 @@ function replaceConsole(logger) { } ['log','debug','info','warn','error'].forEach(function (item) { - console['_preLog4js_'+item] = console[item]; + if (console['_preLog4js_log'] === undefined) { + console['_preLog4js_'+item] = console[item]; + } console[item] = replaceWith(item === 'log' ? logger.info : logger[item]); }); - } function loadAppenders() { diff --git a/log-rolling.js b/log-rolling.js new file mode 100644 index 0000000..34c18ce --- /dev/null +++ b/log-rolling.js @@ -0,0 +1,28 @@ +var log4js = require('./lib/log4js') +, log +, i = 0; +log4js.configure({ + "appenders": [ + { + "type": "file", + "filename": "tmp-test.log", + "maxLogSize": 1024, + "backups": 3, + "pollInterval": 0.1, + "category": "test" + }, + { + type: "console" + , category: "console" + } + ] +}); +log = log4js.getLogger("test"); + +function doTheLogging(x) { + log.info("Logging something %d", x); +} + +for ( ; i < 100000; i++) { + doTheLogging(i); +} \ No newline at end of file diff --git a/test/fileAppender.js b/test/fileAppender.js index 6a3bbd7..8ce2ac8 100644 --- a/test/fileAppender.js +++ b/test/fileAppender.js @@ -14,6 +14,7 @@ function remove(filename) { } vows.describe('log4js fileAppender').addBatch({ + 'with default fileAppender settings': { topic: function() { var testFile = __dirname + '/fa-default-test.log' @@ -122,5 +123,61 @@ vows.describe('log4js fileAppender').addBatch({ } } } +}).addBatch({ + 'configure' : { + 'with fileAppender': { + topic: function() { + var log4js = require('../lib/log4js') + , logger; + //this config file defines one file appender (to ./tmp-tests.log) + //and sets the log level for "tests" to WARN + log4js.configure('test/log4js.json'); + logger = log4js.getLogger('tests'); + logger.info('this should not be written to the file'); + logger.warn('this should be written to the file'); + + fs.readFile('tmp-tests.log', 'utf8', this.callback); + }, + 'should load appender configuration from a json file': function(err, contents) { + assert.include(contents, 'this should be written to the file\n'); + assert.equal(contents.indexOf('this should not be written to the file'), -1); + }, + 'and log rolling': { + topic: function() { + var sandbox = require('sandboxed-module') + , that = this + , fileAppender = sandbox.require( + '../lib/appenders/file.js' + , { requires: + { 'fs': + { + watchFile: function(filename, options, cb) { + that.callback(null, filename); + } + , createWriteStream: function() { + return { + on: function() {} + , end: function() {} + , destroy: function() {} + }; + } + } + } + } + ); + + fileAppender.configure({ + filename: "cheese.log" + , maxLogSize: 100 + , backups: 5 + , pollInterval: 30 + }); + }, + 'should watch the log file': function(watchedFile) { + assert.equal(watchedFile, 'cheese.log'); + } + } + } + } }).export(module); \ No newline at end of file diff --git a/test/layouts.js b/test/layouts.js index 0bb0a6e..2a3b55c 100644 --- a/test/layouts.js +++ b/test/layouts.js @@ -102,29 +102,24 @@ vows.describe('log4js layouts').addBatch({ error = new Error("Some made-up error"), stack = error.stack.split(/\n/); - event.data = ['this is a test', error]; + event.data = ['this is a test ', error]; output = layout(event); lines = output.split(/\n/); - assert.length(lines, stack.length+1); - assert.equal(lines[0], "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test"); - assert.equal(lines[1], "Error: Some made-up error"); + assert.length(lines, stack.length); + assert.equal(lines[0], "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test Error: Some made-up error"); for (var i = 1; i < stack.length; i++) { - assert.equal(lines[i+1], stack[i]); + assert.equal(lines[i+1], stack[i+1]); } }, 'should output any extra data in the log event as util.inspect strings': function(args) { var layout = args[0], event = args[1], output, lines; - event.data = ['this is a test', { + event.data = ['this is a test ', { name: 'Cheese', message: 'Gorgonzola smells.' }]; output = layout(event); - lines = output.split(/\n/); - - assert.length(lines, 2); - assert.equal(lines[0], "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test"); - assert.equal(lines[1], "{ name: 'Cheese', message: 'Gorgonzola smells.' }"); + assert.equal(output, "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test { name: 'Cheese', message: 'Gorgonzola smells.' }"); } }, diff --git a/test/logLevelFilter.js b/test/logLevelFilter.js new file mode 100644 index 0000000..6cef459 --- /dev/null +++ b/test/logLevelFilter.js @@ -0,0 +1,69 @@ +var vows = require('vows') +, fs = require('fs') +, assert = require('assert'); + +function remove(filename) { + try { + fs.unlinkSync(filename); + } catch (e) { + //doesn't really matter if it failed + } +} + +vows.describe('log4js logLevelFilter').addBatch({ + 'appender': { + topic: function() { + var log4js = require('../lib/log4js'), logEvents = [], logger; + log4js.clearAppenders(); + 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'); + logger.fatal('so should this'); + return logEvents; + }, + 'should only pass log events greater than or equal to its own level' : function(logEvents) { + assert.length(logEvents, 2); + assert.equal(logEvents[0].data[0], 'this should, though'); + assert.equal(logEvents[1].data[0], 'so should this'); + } + }, + + 'configure': { + topic: function() { + var log4js = require('../lib/log4js') + , logger; + + remove(__dirname + '/logLevelFilter.log'); + remove(__dirname + '/logLevelFilter-warnings.log'); + + log4js.configure('test/with-logLevelFilter.json'); + logger = log4js.getLogger("tests"); + logger.info('main'); + logger.error('both'); + logger.warn('both'); + logger.debug('main'); + + return logger; + }, + 'tmp-tests.log': { + topic: function() { + fs.readFile(__dirname + '/logLevelFilter.log', 'utf8', this.callback); + }, + 'should contain all log messages': function(contents) { + var messages = contents.trim().split('\n'); + assert.deepEqual(messages, ['main','both','both','main']); + } + }, + 'tmp-tests-warnings.log': { + topic: function() { + fs.readFile(__dirname + '/logLevelFilter-warnings.log','utf8',this.callback); + }, + 'should contain only error and warning log messages': function(contents) { + var messages = contents.trim().split('\n'); + assert.deepEqual(messages, ['both','both']); + } + } + } +}).export(module); \ No newline at end of file diff --git a/test/logging.js b/test/logging.js index 05f679d..b08fd13 100644 --- a/test/logging.js +++ b/test/logging.js @@ -55,81 +55,33 @@ vows.describe('log4js').addBatch({ }, - 'configure' : { - topic: function() { - var messages = {}, fakeFS = { - createWriteStream: function(file) { - return { - write: function(message) { - if (!messages.hasOwnProperty(file)) { - messages[file] = []; - } - messages[file].push(message); - } - , end: function() {} - , destroySoon: function() {} - }; - }, - readdirSync: function(dir) { - return require('fs').readdirSync(dir); - }, - readFileSync: function(file, encoding) { - return require('fs').readFileSync(file, encoding); - }, - watchFile: function(file) { - messages.watchedFile = file; - } - }, - log4js = sandbox.require( - '../lib/log4js' - , { - requires: { - 'fs': fakeFS + 'invalid configuration': { + 'should throw an exception': function() { + assert.throws(function() { + log4js.configure({ "type": "invalid" }); + }); + } + }, + + 'configuration when passed as object': { + topic: function() { + var appenderConfig + , log4js = sandbox.require( + '../lib/log4js' + , { requires: + { './appenders/file.js': + { + name: "file" + , appender: function() {} + , configure: function(configuration) { + appenderConfig = configuration; + return function() {}; + } } + } } - ); - return [ log4js, messages ]; - }, - 'should load appender configuration from a json file': function(args) { - var log4js = args[0], messages = args[1]; - delete messages['tmp-tests.log']; - log4js.clearAppenders(); - //this config file defines one file appender (to ./tmp-tests.log) - //and sets the log level for "tests" to WARN - log4js.configure('test/log4js.json'); - var logger = log4js.getLogger("tests"); - logger.info('this should not be written to the file'); - logger.warn('this should be written to the file'); - assert.length(messages['tmp-tests.log'], 1); - assert.equal(messages['tmp-tests.log'][0], 'this should be written to the file\n'); - }, - 'should handle logLevelFilter configuration': function(args) { - var log4js = args[0], messages = args[1]; - delete messages['tmp-tests.log']; - delete messages['tmp-tests-warnings.log']; - log4js.clearAppenders(); - log4js.configure('test/with-logLevelFilter.json'); - var logger = log4js.getLogger("tests"); - logger.info('main'); - logger.error('both'); - logger.warn('both'); - logger.debug('main'); - - assert.length(messages['tmp-tests.log'], 4); - assert.length(messages['tmp-tests-warnings.log'], 2); - assert.deepEqual(messages['tmp-tests.log'], ['main\n','both\n','both\n','main\n']); - assert.deepEqual(messages['tmp-tests-warnings.log'], ['both\n','both\n']); - }, - 'should handle fileAppender with log rolling' : function(args) { - var log4js = args[0], messages = args[1]; - delete messages['tmp-test.log']; - log4js.configure('test/with-log-rolling.json'); - assert.equal(messages.watchedFile, 'tmp-test.log'); - }, - 'should handle an object or a file name': function(args) { - var log4js = args[0], - messages = args[1], - config = { + ) + , config = { "appenders": [ { "type" : "file", @@ -140,34 +92,88 @@ vows.describe('log4js').addBatch({ } ] }; - delete messages['cheesy-wotsits.log']; log4js.configure(config); - assert.equal(messages.watchedFile, 'cheesy-wotsits.log'); + return appenderConfig; + }, + 'should be passed to appender config': function(configuration) { + assert.equal(configuration.filename, 'cheesy-wotsits.log'); } }, + 'configuration when passed as filename': { + topic: function() { + var appenderConfig + , configFilename + , log4js = sandbox.require( + '../lib/log4js' + , { requires: + { 'fs': + { + readFileSync: function(filename) { + configFilename = filename; + return JSON.stringify({ + appenders: [ + { type: "file" + , filename: "whatever.log" + } + ] + }); + }, + readdirSync: function() { + return ['file.js']; + } + } + , './appenders/file.js': + { + name: "file" + , appender: function() {} + , configure: function(configuration) { + appenderConfig = configuration; + return function() {}; + } + } + } + } + ); + log4js.configure("/path/to/cheese.json"); + return [ configFilename, appenderConfig ]; + }, + 'should read the config from a file': function(args) { + assert.equal(args[0], '/path/to/cheese.json'); + }, + 'should pass config to appender': function(args) { + assert.equal(args[1].filename, "whatever.log"); + } + }, + 'with no appenders defined' : { topic: function() { var logger - , message + , that = this + , fakeConsoleAppender = { + name: "console" + , appender: function() { + return function(evt) { + that.callback(null, evt); + } + } + , configure: function() { + return fakeConsoleAppender.appender(); + } + } , log4js = sandbox.require( '../lib/log4js' , { - globals: { - console: { - log: function(msg) { - message = msg; - } - } + requires: { + './appenders/console.js': fakeConsoleAppender + } } - } ); logger = log4js.getLogger("some-logger"); logger.debug("This is a test"); - return message; }, - 'should default to the console appender': function(message) { - assert.isTrue(/This is a test$/.test(message)); + 'should default to the console appender': function(evt) { + assert.equal(evt.data[0], "This is a test"); } }, @@ -259,7 +265,7 @@ vows.describe('log4js').addBatch({ 'default setup': { topic: function() { var pathsChecked = [], - message, + appenderEvent, logger, modulePath = require('path').normalize(__dirname + '/../lib/log4js.json'), fakeFS = { @@ -281,28 +287,27 @@ vows.describe('log4js').addBatch({ } }, fakeConsole = { - log : function (msg) { message = msg; }, - info: this.log, - warn: this.log, - debug: this.log, - error: this.log + 'name': 'console' + , 'appender': function () { + return function(evt) { appenderEvent = evt; } + } + , 'configure': function (config) { + return fakeConsole.appender(); + } }, log4js = sandbox.require( '../lib/log4js', { requires: { 'fs': fakeFS - }, - globals: { - 'console': fakeConsole + , './appenders/console.js': fakeConsole } } ); logger = log4js.getLogger('a-test'); logger.debug("this is a test"); - - return [ pathsChecked, message, modulePath ]; + return [ pathsChecked, appenderEvent, modulePath ]; }, 'should check current directory, require paths, and finally the module dir for log4js.json': function(args) { @@ -317,27 +322,8 @@ vows.describe('log4js').addBatch({ }, 'should configure log4js from first log4js.json found': function(args) { - var message = args[1]; - assert.equal(message, 'this is a test'); - } - }, - - 'logLevelFilter': { - topic: function() { - var log4js = require('../lib/log4js'), logEvents = [], logger; - log4js.clearAppenders(); - 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'); - logger.fatal('so should this'); - return logEvents; - }, - 'should only pass log events greater than or equal to its own level' : function(logEvents) { - assert.length(logEvents, 2); - assert.equal(logEvents[0].data[0], 'this should, though'); - assert.equal(logEvents[1].data[0], 'so should this'); + var appenderEvent = args[1]; + assert.equal(appenderEvent.data[0], 'this is a test'); } }, diff --git a/test/with-logLevelFilter.json b/test/with-logLevelFilter.json index c1ac2cd..d564ace 100644 --- a/test/with-logLevelFilter.json +++ b/test/with-logLevelFilter.json @@ -6,7 +6,7 @@ "level": "WARN", "appender": { "type": "file", - "filename": "tmp-tests-warnings.log", + "filename": "test/logLevelFilter-warnings.log", "layout": { "type": "messagePassThrough" } @@ -15,7 +15,7 @@ { "category": "tests", "type": "file", - "filename": "tmp-tests.log", + "filename": "test/logLevelFilter.log", "layout": { "type": "messagePassThrough" }