Merge branch 'master' of github.com:csausdev/log4js-node

unstable
csausdev 14 years ago
commit cf7d5f681a

@ -2,7 +2,7 @@
This is a conversion of the [log4js](http://log4js.berlios.de/index.html)
framework to work with [node](http://nodejs.org). I've mainly stripped out the browser-specific code
and tidied up some of the javascript. It includes a basic file logger, with log rolling based on file size.
and tidied up some of the javascript. It includes a basic file logger, with log rolling based on file size. It also enhances the default console logging functions (console.log, console.debug, etc) so that they use log4js and can be directed to a file, with log rolling etc - which is handy if you have some third party modules that use console.log but want that output included in your application log files.
NOTE: since v0.2.0 require('log4js') returns a function, so you need to call that function in your code before you can use it. I've done this to make testing easier (allows dependency injection).
@ -12,7 +12,7 @@ npm install log4js
## tests
Tests now use [vows](http://vowsjs.org), run with `vows test/logging.js`. I am slowly porting the previous tests from jspec (run those with `node tests.js`), since jspec is no longer maintained.
Tests now use [vows](http://vowsjs.org), run with `vows test/logging.js`.
## usage
@ -20,6 +20,9 @@ Minimalist version:
var log4js = require('log4js')();
var logger = log4js.getLogger();
logger.debug("Some debug messages");
Even more minimalist version:
require('log4js')();
console.debug("Some debug messages");
By default, log4js outputs to stdout with the coloured layout (thanks to [masylum](http://github.com/masylum)), so for the above you would see:
[2010-01-17 11:43:37.987] [DEBUG] [default] - Some debug messages

@ -45,12 +45,12 @@
* Website: http://log4js.berlios.de
*/
module.exports = function (fileSystem, standardOutput, configPaths) {
var fs = fileSystem || require('fs'),
standardOutput = standardOutput || console.log,
configPaths = configPaths || require.paths,
sys = require('sys'),
events = require('events'),
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 = {},
@ -279,9 +279,13 @@ module.exports = function (fileSystem, standardOutput, configPaths) {
this.startTime = new Date();
this.categoryName = categoryName;
this.message = message;
this.exception = exception;
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));
}
}
/**
@ -614,8 +618,26 @@ module.exports = function (fileSystem, standardOutput, configPaths) {
};
function replaceConsole(logger) {
function replaceWith (fn) {
return function() {
fn.apply(logger, arguments);
}
}
console.log = replaceWith(logger.info);
console.debug = replaceWith(logger.debug);
console.trace = replaceWith(logger.trace);
console.info = replaceWith(logger.info);
console.warn = replaceWith(logger.warn);
console.error = replaceWith(logger.error);
}
//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,

@ -1,6 +1,6 @@
{
"name": "log4js",
"version": "0.2.0",
"version": "0.2.2",
"description": "Port of Log4js to work with node.",
"keywords": [
"logging",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

@ -1,149 +0,0 @@
body.jspec {
margin: 45px 0;
font: 12px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
background: #efefef url(images/bg.png) top left repeat-x;
text-align: center;
}
#jspec {
margin: 0 auto;
padding-top: 30px;
width: 1008px;
background: url(images/vr.png) top left repeat-y;
text-align: left;
}
#jspec-top {
position: relative;
margin: 0 auto;
width: 1008px;
height: 40px;
background: url(images/sprites.bg.png) top left no-repeat;
}
#jspec-bottom {
margin: 0 auto;
width: 1008px;
height: 15px;
background: url(images/sprites.bg.png) bottom left no-repeat;
}
#jspec .loading {
margin-top: -45px;
width: 1008px;
height: 80px;
background: url(images/loading.gif) 50% 50% no-repeat;
}
#jspec-title {
position: absolute;
top: 15px;
left: 20px;
width: 160px;
font-size: 22px;
font-weight: normal;
background: url(images/sprites.png) 0 -126px no-repeat;
text-align: center;
}
#jspec-title em {
font-size: 10px;
font-style: normal;
color: #BCC8D1;
}
#jspec-report * {
margin: 0;
padding: 0;
background: none;
border: none;
}
#jspec-report {
padding: 15px 40px;
font: 11px "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
color: #7B8D9B;
}
#jspec-report.has-failures {
padding-bottom: 30px;
}
#jspec-report .hidden {
display: none;
}
#jspec-report .heading {
margin-bottom: 15px;
}
#jspec-report .heading span {
padding-right: 10px;
}
#jspec-report .heading .passes em {
color: #0ea0eb;
}
#jspec-report .heading .failures em {
color: #FA1616;
}
#jspec-report table {
font-size: 11px;
border-collapse: collapse;
}
#jspec-report td {
padding: 8px;
text-indent: 30px;
color: #7B8D9B;
}
#jspec-report tr.body {
display: none;
}
#jspec-report tr.body pre {
margin: 0;
padding: 0 0 5px 25px;
}
#jspec-report tr.even:hover + tr.body,
#jspec-report tr.odd:hover + tr.body {
display: block;
}
#jspec-report tr td:first-child em {
display: block;
clear: both;
font-style: normal;
font-weight: normal;
color: #7B8D9B;
}
#jspec-report tr.even:hover,
#jspec-report tr.odd:hover {
text-shadow: 1px 1px 1px #fff;
background: #F2F5F7;
}
#jspec-report td + td {
padding-right: 0;
width: 15px;
}
#jspec-report td.pass {
background: url(images/sprites.png) 3px -7px no-repeat;
}
#jspec-report td.fail {
background: url(images/sprites.png) 3px -158px no-repeat;
font-weight: bold;
color: #FC0D0D;
}
#jspec-report td.requires-implementation {
background: url(images/sprites.png) 3px -333px no-repeat;
}
#jspec-report tr.description td {
margin-top: 25px;
padding-top: 25px;
font-size: 12px;
font-weight: bold;
text-indent: 0;
color: #1a1a1a;
}
#jspec-report tr.description:first-child td {
border-top: none;
}
#jspec-report .assertion {
display: block;
float: left;
margin: 0 0 0 1px;
padding: 0;
width: 1px;
height: 5px;
background: #7B8D9B;
}
#jspec-report .assertion.failed {
background: red;
}
.jspec-sandbox {
display: none;
}

@ -1,115 +0,0 @@
// JSpec - Growl - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
;(function(){
Growl = {
// --- Version
version: '1.0.0',
/**
* Execute the given _cmd_, returning an array of lines from stdout.
*
* Examples:
*
* Growl.exec('growlnotify', '-m', msg)
*
* @param {string ...} cmd
* @return {array}
* @api public
*/
exec: function(cmd) {
var lines = [], line
with (JavaImporter(java.lang, java.io)) {
var proccess = Runtime.getRuntime().exec(Array.prototype.slice.call(arguments))
var stream = new DataInputStream(proccess.getInputStream())
while (line = stream.readLine())
lines.push(line + '')
stream.close()
}
return lines
},
/**
* Return the extension of the given _path_ or null.
*
* @param {string} path
* @return {string}
* @api private
*/
extname: function(path) {
return path.lastIndexOf('.') != -1 ?
path.slice(path.lastIndexOf('.') + 1, path.length) :
null
},
/**
* Version of the 'growlnotify' binary.
*
* @return {string}
* @api private
*/
binVersion: function() {
try { return this.exec('growlnotify', '-v')[0].split(' ')[1] } catch (e) {}
},
/**
* Send growl notification _msg_ with _options_.
*
* Options:
*
* - title Notification title
* - sticky Make the notification stick (defaults to false)
* - name Application name (defaults to growlnotify)
* - image
* - path to an icon sets --iconpath
* - path to an image sets --image
* - capitalized word sets --appIcon
* - filename uses extname as --icon
* - otherwise treated as --icon
*
* Examples:
*
* Growl.notify('New email')
* Growl.notify('5 new emails', { title: 'Thunderbird' })
*
* @param {string} msg
* @param {options} hash
* @api public
*/
notify: function(msg, options) {
options = options || {}
var args = ['growlnotify', '-m', msg]
if (!this.binVersion()) throw new Error('growlnotify executable is required')
if (image = options.image) {
var flag, ext = this.extname(image)
flag = flag || ext == 'icns' && 'iconpath'
flag = flag || /^[A-Z]/.test(image) && 'appIcon'
flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image'
flag = flag || ext && (image = ext) && 'icon'
flag = flag || 'icon'
args.push('--' + flag, image)
}
if (options.sticky) args.push('--sticky')
if (options.name) args.push('--name', options.name)
if (options.title) args.push(options.title)
this.exec.apply(this, args)
}
}
JSpec.include({
name: 'Growl',
reporting: function(options){
var stats = JSpec.stats
if (stats.failures) Growl.notify('failed ' + stats.failures + ' assertions', { title: 'JSpec'})
else Growl.notify('passed ' + stats.passes + ' assertions', { title: 'JSpec' })
}
})
})()

@ -1,71 +0,0 @@
// JSpec - jQuery - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
JSpec
.requires('jQuery', 'when using jspec.jquery.js')
.include({
name: 'jQuery',
// --- Initialize
init : function() {
jQuery.ajaxSetup({ async: false })
},
// --- Utilities
utilities : {
element: jQuery,
elements: jQuery,
sandbox : function() {
return jQuery('<div class="sandbox"></div>')
}
},
// --- Matchers
matchers : {
have_tag : "jQuery(expected, actual).length == 1",
have_one : "alias have_tag",
have_tags : "jQuery(expected, actual).length > 1",
have_many : "alias have_tags",
have_child : "jQuery(actual).children(expected).length == 1",
have_children : "jQuery(actual).children(expected).length > 1",
have_text : "jQuery(actual).text() == expected",
have_value : "jQuery(actual).val() == expected",
be_enabled : "!jQuery(actual).attr('disabled')",
have_class : "jQuery(actual).hasClass(expected)",
be_visible : function(actual) {
return jQuery(actual).css('display') != 'none' &&
jQuery(actual).css('visibility') != 'hidden' &&
jQuery(actual).attr('type') != 'hidden'
},
be_hidden : function(actual) {
return !JSpec.does(actual, 'be_visible')
},
have_classes : function(actual) {
return !JSpec.any(JSpec.toArray(arguments, 1), function(arg){
return !JSpec.does(actual, 'have_class', arg)
})
},
have_attr : function(actual, attr, value) {
return value ? jQuery(actual).attr(attr) == value:
jQuery(actual).attr(attr)
},
'be disabled selected checked' : function(attr) {
return 'jQuery(actual).attr("' + attr + '")'
},
'have type id title alt href src sel rev name target' : function(attr) {
return function(actual, value) {
return JSpec.does(actual, 'have_attr', attr, value)
}
}
}
})

File diff suppressed because it is too large Load Diff

@ -1,39 +0,0 @@
// JSpec - Shell - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
;(function(){
var _quit = quit
Shell = {
// --- Global
main: this,
// --- Commands
commands: {
quit: ['Terminate the shell', function(){ _quit() }],
exit: ['Terminate the shell', function(){ _quit() }],
p: ['Inspect an object', function(o){ return o.toSource() }]
},
/**
* Start the interactive shell.
*
* @api public
*/
start : function() {
for (var name in this.commands)
if (this.commands.hasOwnProperty(name))
this.commands[name][1].length ?
this.main[name] = this.commands[name][1] :
this.main.__defineGetter__(name, this.commands[name][1])
}
}
Shell.start()
})()

@ -1,90 +0,0 @@
// JSpec - Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
;(function(){
/**
* Version.
*/
mockTimersVersion = '1.0.2'
/**
* Localized timer stack.
*/
var timers = []
/**
* Set mock timeout with _callback_ and timeout of _ms_.
*
* @param {function} callback
* @param {int} ms
* @return {int}
* @api public
*/
setTimeout = function(callback, ms) {
var id
return id = setInterval(function(){
callback()
clearInterval(id)
}, ms)
}
/**
* Set mock interval with _callback_ and interval of _ms_.
*
* @param {function} callback
* @param {int} ms
* @return {int}
* @api public
*/
setInterval = function(callback, ms) {
callback.step = ms, callback.current = callback.last = 0
return timers[timers.length] = callback, timers.length
}
/**
* Destroy timer with _id_.
*
* @param {int} id
* @return {bool}
* @api public
*/
clearInterval = clearTimeout = function(id) {
return delete timers[--id]
}
/**
* Reset timers.
*
* @return {array}
* @api public
*/
resetTimers = function() {
return timers = []
}
/**
* Increment each timers internal clock by _ms_.
*
* @param {int} ms
* @api public
*/
tick = function(ms) {
for (var i = 0, len = timers.length; i < len; ++i)
if (timers[i] && (timers[i].current += ms))
if (timers[i].current - timers[i].last >= timers[i].step) {
var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step)
var remainder = (timers[i].current - timers[i].last) % timers[i].step
timers[i].last = timers[i].current - remainder
while (times-- && timers[i]) timers[i]()
}
}
})()

@ -1,193 +0,0 @@
// JSpec - XHR - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
(function(){
// --- Original XMLHttpRequest
var OriginalXMLHttpRequest = 'XMLHttpRequest' in this ?
XMLHttpRequest :
function(){}
var OriginalActiveXObject = 'ActiveXObject' in this ?
ActiveXObject :
undefined
// --- MockXMLHttpRequest
var MockXMLHttpRequest = function() {
this.requestHeaders = {}
}
MockXMLHttpRequest.prototype = {
status: 0,
async: true,
readyState: 0,
responseText: '',
abort: function(){},
onreadystatechange: function(){},
/**
* Return response headers hash.
*/
getAllResponseHeaders : function(){
return this.responseHeaders
},
/**
* Return case-insensitive value for header _name_.
*/
getResponseHeader : function(name) {
return this.responseHeaders[name.toLowerCase()]
},
/**
* Set case-insensitive _value_ for header _name_.
*/
setRequestHeader : function(name, value) {
this.requestHeaders[name.toLowerCase()] = value
},
/**
* Open mock request.
*/
open : function(method, url, async, user, password) {
this.user = user
this.password = password
this.url = url
this.readyState = 1
this.method = method.toUpperCase()
if (async != undefined) this.async = async
if (this.async) this.onreadystatechange()
},
/**
* Send request _data_.
*/
send : function(data) {
var self = this
this.data = data
this.readyState = 4
if (this.method == 'HEAD') this.responseText = null
this.responseHeaders['content-length'] = (this.responseText || '').length
if(this.async) this.onreadystatechange()
lastRequest = function(){
return self
}
}
}
// --- Response status codes
JSpec.statusCodes = {
100: 'Continue',
101: 'Switching Protocols',
200: 'OK',
201: 'Created',
202: 'Accepted',
203: 'Non-Authoritative Information',
204: 'No Content',
205: 'Reset Content',
206: 'Partial Content',
300: 'Multiple Choice',
301: 'Moved Permanently',
302: 'Found',
303: 'See Other',
304: 'Not Modified',
305: 'Use Proxy',
307: 'Temporary Redirect',
400: 'Bad Request',
401: 'Unauthorized',
402: 'Payment Required',
403: 'Forbidden',
404: 'Not Found',
405: 'Method Not Allowed',
406: 'Not Acceptable',
407: 'Proxy Authentication Required',
408: 'Request Timeout',
409: 'Conflict',
410: 'Gone',
411: 'Length Required',
412: 'Precondition Failed',
413: 'Request Entity Too Large',
414: 'Request-URI Too Long',
415: 'Unsupported Media Type',
416: 'Requested Range Not Satisfiable',
417: 'Expectation Failed',
422: 'Unprocessable Entity',
500: 'Internal Server Error',
501: 'Not Implemented',
502: 'Bad Gateway',
503: 'Service Unavailable',
504: 'Gateway Timeout',
505: 'HTTP Version Not Supported'
}
/**
* Mock XMLHttpRequest requests.
*
* mockRequest().and_return('some data', 'text/plain', 200, { 'X-SomeHeader' : 'somevalue' })
*
* @return {hash}
* @api public
*/
function mockRequest() {
return { and_return : function(body, type, status, headers) {
XMLHttpRequest = MockXMLHttpRequest
ActiveXObject = false
status = status || 200
headers = headers || {}
headers['content-type'] = type
JSpec.extend(XMLHttpRequest.prototype, {
responseText: body,
responseHeaders: headers,
status: status,
statusText: JSpec.statusCodes[status]
})
}}
}
/**
* Unmock XMLHttpRequest requests.
*
* @api public
*/
function unmockRequest() {
XMLHttpRequest = OriginalXMLHttpRequest
ActiveXObject = OriginalActiveXObject
}
JSpec.include({
name: 'Mock XHR',
// --- Utilities
utilities : {
mockRequest: mockRequest,
unmockRequest: unmockRequest
},
// --- Hooks
afterSpec : function() {
unmockRequest()
},
// --- DSLs
DSLs : {
snake : {
mock_request: mockRequest,
unmock_request: unmockRequest,
last_request: function(){ return lastRequest() }
}
}
})
})()

@ -1,144 +0,0 @@
describe 'log4js'
before
extend(context, {
log4js : require("log4js")()
});
end
before_each
log4js.clearAppenders();
event = '';
logger = log4js.getLogger('tests');
logger.setLevel("TRACE");
logger.addListener("log", function (logEvent) { event = logEvent; });
end
describe 'addAppender'
before_each
appenderEvent = undefined;
appender = function(logEvent) { appenderEvent = logEvent; };
end
describe 'without a category'
it 'should register the function as a listener for all loggers'
log4js.addAppender(appender);
logger.debug("This is a test");
appenderEvent.should.be event
end
it 'should also register as an appender for loggers if an appender for that category is defined'
var otherEvent;
log4js.addAppender(appender);
log4js.addAppender(function (evt) { otherEvent = evt; }, 'cheese');
var cheeseLogger = log4js.getLogger('cheese');
cheeseLogger.addListener("log", function (logEvent) { event = logEvent; });
cheeseLogger.debug('This is a test');
appenderEvent.should.be event
otherEvent.should.be event
otherEvent = undefined;
appenderEvent = undefined;
log4js.getLogger('pants').debug("this should not be propagated to otherEvent");
otherEvent.should.be undefined
appenderEvent.should.not.be undefined
appenderEvent.message.should.be "this should not be propagated to otherEvent"
cheeseLogger = null;
end
end
describe 'with a category'
it 'should only register the function as a listener for that category'
log4js.addAppender(appender, 'tests');
logger.debug('this is a test');
appenderEvent.should.be event
appenderEvent = undefined;
log4js.getLogger('some other category').debug('Cheese');
appenderEvent.should.be undefined
end
end
describe 'with multiple categories'
it 'should register the function as a listener for all the categories'
log4js.addAppender(appender, 'tests', 'biscuits');
logger.debug('this is a test');
appenderEvent.should.be event
appenderEvent = undefined;
var otherLogger = log4js.getLogger('biscuits');
otherLogger.debug("mmm... garibaldis");
appenderEvent.should.not.be undefined
appenderEvent.message.should.be "mmm... garibaldis"
appenderEvent = undefined;
otherLogger = null;
log4js.getLogger("something else").debug("pants");
appenderEvent.should.be undefined
end
it 'should register the function when the list of categories is an array'
log4js.addAppender(appender, ['tests', 'pants']);
logger.debug('this is a test');
appenderEvent.should.be event
appenderEvent = undefined;
var otherLogger = log4js.getLogger('pants');
otherLogger.debug("big pants");
appenderEvent.should.not.be undefined
appenderEvent.message.should.be "big pants"
appenderEvent = undefined;
otherLogger = null;
log4js.getLogger("something else").debug("pants");
appenderEvent.should.be undefined
end
end
end
describe 'basicLayout'
it 'should take a logevent and output a formatted string'
logger.debug('this is a test');
var output = log4js.basicLayout(event);
output.should.match /\[.*?\] \[DEBUG\] tests - this is a test/
end
it 'should output a stacktrace, message if the event has an error attached'
var error = new Error("Some made-up error");
var stack = error.stack.split(/\n/);
logger.debug('this is a test', error);
var output = log4js.basicLayout(event);
var lines = output.split(/\n/);
lines.length.should.be stack.length+1
lines[0].should.match /\[.*?\] \[DEBUG\] tests - this is a test/
lines[1].should.match /\[.*?\] \[DEBUG\] tests - Error: Some made-up error/
for (var i = 1; i < stack.length; i++) {
lines[i+1].should.eql stack[i]
}
end
it 'should output a name and message if the event has something that pretends to be an error'
logger.debug('this is a test', { name: 'Cheese', message: 'Gorgonzola smells.' });
var output = log4js.basicLayout(event);
var lines = output.split(/\n/);
lines.length.should.be 2
lines[0].should.match /\[.*?\] \[DEBUG\] tests - this is a test/
lines[1].should.match /\[.*?\] \[DEBUG\] tests - Cheese: Gorgonzola smells./
end
end
end

@ -29,6 +29,8 @@ vows.describe('log4js').addBatch({
logger.trace("Trace event 1");
logger.trace("Trace event 2");
logger.warn("Warning event");
logger.error("Aargh!", new Error("Pants are on fire!"));
logger.error("Simulated CouchDB problem", { err: 127, cause: "incendiary underwear" });
return events;
},
@ -39,9 +41,20 @@ vows.describe('log4js').addBatch({
},
'should not emit events of a lower level': function(events) {
assert.length(events, 2);
assert.length(events, 4);
assert.equal(events[1].level.toString(), 'WARN');
}
},
'should include the error if passed in': function (events) {
assert.instanceOf(events[2].exception, Error);
assert.equal(events[2].exception.message, 'Pants are on fire!');
},
'should convert things that claim to be errors into Error objects': function (events) {
assert.instanceOf(events[3].exception, Error);
assert.equal(events[3].exception.message, "{ err: 127, cause: 'incendiary underwear' }");
},
},
},
@ -244,6 +257,91 @@ vows.describe('log4js').addBatch({
}
},
'addAppender' : {
topic: function() {
var log4js = require('../lib/log4js')();
log4js.clearAppenders();
return log4js;
},
'without a category': {
'should register the function as a listener for all loggers': function (log4js) {
var appenderEvent, appender = function(evt) { appenderEvent = evt; }, logger = log4js.getLogger("tests");
log4js.addAppender(appender);
logger.debug("This is a test");
assert.equal(appenderEvent.message, "This is a test");
assert.equal(appenderEvent.categoryName, "tests");
assert.equal(appenderEvent.level.toString(), "DEBUG");
},
'should also register as an appender for loggers if an appender for that category is defined': function (log4js) {
var otherEvent, appenderEvent, cheeseLogger;
log4js.addAppender(function (evt) { appenderEvent = evt; });
log4js.addAppender(function (evt) { otherEvent = evt; }, 'cheese');
cheeseLogger = log4js.getLogger('cheese');
cheeseLogger.debug('This is a test');
assert.deepEqual(appenderEvent, otherEvent);
assert.equal(otherEvent.message, 'This is a test');
assert.equal(otherEvent.categoryName, 'cheese');
otherEvent = undefined;
appenderEvent = undefined;
log4js.getLogger('pants').debug("this should not be propagated to otherEvent");
assert.isUndefined(otherEvent);
assert.equal(appenderEvent.message, "this should not be propagated to otherEvent");
}
},
'with a category': {
'should only register the function as a listener for that category': function(log4js) {
var appenderEvent, appender = function(evt) { appenderEvent = evt; }, logger = log4js.getLogger("tests");
log4js.addAppender(appender, 'tests');
logger.debug('this is a category test');
assert.equal(appenderEvent.message, 'this is a category test');
appenderEvent = undefined;
log4js.getLogger('some other category').debug('Cheese');
assert.isUndefined(appenderEvent);
}
},
'with multiple categories': {
'should register the function as a listener for all the categories': function(log4js) {
var appenderEvent, appender = function(evt) { appenderEvent = evt; }, logger = log4js.getLogger('tests');
log4js.addAppender(appender, 'tests', 'biscuits');
logger.debug('this is a test');
assert.equal(appenderEvent.message, 'this is a test');
appenderEvent = undefined;
var otherLogger = log4js.getLogger('biscuits');
otherLogger.debug("mmm... garibaldis");
assert.equal(appenderEvent.message, "mmm... garibaldis");
appenderEvent = undefined;
log4js.getLogger("something else").debug("pants");
assert.isUndefined(appenderEvent);
},
'should register the function when the list of categories is an array': function(log4js) {
var appenderEvent, appender = function(evt) { appenderEvent = evt; };
log4js.addAppender(appender, ['tests', 'pants']);
log4js.getLogger('tests').debug('this is a test');
assert.equal(appenderEvent.message, 'this is a test');
appenderEvent = undefined;
log4js.getLogger('pants').debug("big pants");
assert.equal(appenderEvent.message, "big pants");
appenderEvent = undefined;
log4js.getLogger("something else").debug("pants");
assert.isUndefined(appenderEvent);
}
}
},
'default setup': {
topic: function() {
var pathsChecked = [],
@ -327,6 +425,55 @@ vows.describe('log4js').addBatch({
}
},
'basicLayout': {
topic: function() {
var layout = require('../lib/log4js')().basicLayout,
event = {
message: 'this is a test',
startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
categoryName: "tests",
level: {
colour: "green",
toString: function() { return "DEBUG"; }
}
};
return [layout, event];
},
'should take a logevent and output a formatted string': function(args) {
var layout = args[0], event = args[1];
assert.equal(layout(event), "[2010-12-05 14:18:30.045] [DEBUG] tests - this is a test");
},
'should output a stacktrace, message if the event has an error attached': function(args) {
var layout = args[0], event = args[1], output, lines,
error = new Error("Some made-up error"),
stack = error.stack.split(/\n/);
event.exception = 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], "[2010-12-05 14:18:30.045] [DEBUG] tests - Error: Some made-up error");
for (var i = 1; i < stack.length; i++) {
assert.equal(lines[i+1], stack[i]);
}
},
'should output a name and message if the event has something that pretends to be an error': function(args) {
var layout = args[0], event = args[1], output, lines;
event.exception = {
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], "[2010-12-05 14:18:30.045] [DEBUG] tests - Cheese: Gorgonzola smells.");
}
},
'logLevelFilter': {
topic: function() {
var log4js = require('../lib/log4js')(), logEvents = [], logger;
@ -348,7 +495,7 @@ vows.describe('log4js').addBatch({
'Date extensions': {
topic: function() {
require('../lib/log4js');
require('../lib/log4js')();
return new Date(2010, 0, 11, 14, 31, 30, 5);
},
'should add a toFormattedString method to Date': function(date) {
@ -357,6 +504,37 @@ vows.describe('log4js').addBatch({
'should default to a format': function(date) {
assert.equal(date.toFormattedString(), '2010-01-11 14:31:30.005');
}
},
'console' : {
topic: function() {
return require('../lib/log4js')();
},
'should replace console.log methods with log4js ones': function(log4js) {
var logEvent;
log4js.clearAppenders();
log4js.addAppender(function(evt) { logEvent = evt; });
console.log("Some debug message someone put in a module");
assert.equal(logEvent.message, "Some debug message someone put in a module");
assert.equal(logEvent.level.toString(), "INFO");
logEvent = undefined;
console.debug("Some debug");
assert.equal(logEvent.message, "Some debug");
assert.equal(logEvent.level.toString(), "DEBUG");
logEvent = undefined;
console.error("An error");
assert.equal(logEvent.message, "An error");
assert.equal(logEvent.level.toString(), "ERROR");
logEvent = undefined;
console.info("some info");
assert.equal(logEvent.message, "some info");
assert.equal(logEvent.level.toString(), "INFO");
logEvent = undefined;
console.trace("tracing");
assert.equal(logEvent.message, "tracing");
assert.equal(logEvent.level.toString(), "TRACE");
}
}
}).export(module);

@ -1,43 +0,0 @@
require.paths.unshift("./spec/lib", "./lib");
require("jspec");
var sys = require("sys"), fs = require("fs");
quit = process.exit
print = sys.puts
readFile = function(path) {
var result;
try {
result = fs.readFileSync(path, "utf8");
} catch (e) {
throw e;
}
return result;
}
var specsFound = false;
if (process.ARGV[2]) {
specsFound = true;
JSpec.exec('spec/spec.' + process.ARGV[2] + '.js');
} else {
var files = fs.readdirSync('spec/');
files.filter(
function (file) {
return file.indexOf('spec.') === 0;
}
).forEach(
function(file) {
specsFound = true;
JSpec.exec('spec/'+file);
}
);
}
if (specsFound) {
JSpec.run({ reporter: JSpec.reporters.Terminal, failuresOnly: false });
JSpec.report();
} else {
print("No tests to run. This makes me sad.");
}
Loading…
Cancel
Save