forked from log4js-node/log4js-node
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
328 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
var log4js = require('./lib/log4js')(); | ||
log4js.addAppender(log4js.consoleAppender()); | ||
log4js.addAppender(log4js.fileAppender('cheese.log'), 'cheese'); | ||
|
||
var logger = log4js.getLogger('cheese'); | ||
|
||
logger.setLevel('INFO'); | ||
|
||
var app = require('express').createServer(); | ||
app.configure(function() { | ||
app.use(log4js.connectLogger(logger, { level: log4js.levels.INFO })); | ||
}); | ||
app.get('/', function(req,res) { | ||
res.send('hello world'); | ||
}); | ||
app.listen(5000); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/** | ||
* Log requests with the given `options` or a `format` string. | ||
* | ||
* Options: | ||
* | ||
* - `format` Format string, see below for tokens | ||
* - `level` A log4js levels instance. | ||
* | ||
* Tokens: | ||
* | ||
* - `:req[header]` ex: `:req[Accept]` | ||
* - `:res[header]` ex: `:res[Content-Length]` | ||
* - `:http-version` | ||
* - `:response-time` | ||
* - `:remote-addr` | ||
* - `:date` | ||
* - `:method` | ||
* - `:url` | ||
* - `:referrer` | ||
* - `:user-agent` | ||
* - `:status` | ||
* | ||
* @param {String|Function|Object} format or options | ||
* @return {Function} | ||
* @api public | ||
*/ | ||
|
||
module.exports = function(log4js_module) { | ||
var log4js = log4js_module; | ||
|
||
function getLogger(logger4js, options) { | ||
if ('object' == typeof options) { | ||
options = options || {}; | ||
} else if (options) { | ||
options = { format: options }; | ||
} else { | ||
options = {}; | ||
} | ||
|
||
var thislogger = logger4js; | ||
var level = options.level || log4js.levels.TRACE; | ||
var fmt = options.format; | ||
|
||
return function logger(req, res, next) { | ||
|
||
// mount safety | ||
if (req._logging) return next(); | ||
|
||
if (thislogger.isLevelEnabled(level)) { | ||
|
||
var start = +new Date | ||
, statusCode | ||
, writeHead = res.writeHead | ||
, end = res.end | ||
, url = req.originalUrl; | ||
|
||
// flag as logging | ||
req._logging = true; | ||
|
||
// proxy for statusCode. | ||
res.writeHead = function(code, headers){ | ||
res.writeHead = writeHead; | ||
res.writeHead(code, headers); | ||
res.__statusCode = statusCode = code; | ||
res.__headers = headers || {}; | ||
}; | ||
|
||
// proxy end to output a line to the provided logger. | ||
if (fmt) { | ||
res.end = function(chunk, encoding) { | ||
res.end = end; | ||
res.end(chunk, encoding); | ||
res.responseTime = +new Date - start; | ||
if ('function' == typeof fmt) { | ||
var line = fmt(req, res, function(str){ return format(str, req, res); }); | ||
if (line) thislogger.log(level, line); | ||
} else { | ||
thislogger.log(level, format(fmt, req, res)); | ||
} | ||
}; | ||
} else { | ||
res.end = function(chunk, encoding) { | ||
var contentLength = (res._headers && res._headers['content-length']) | ||
|| (res.__headers && res.__headers['Content-Length']) | ||
|| '-'; | ||
|
||
res.end = end; | ||
res.end(chunk, encoding); | ||
|
||
thislogger.log(level, | ||
(req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))) + | ||
' - - "' + req.method + ' ' + url + | ||
' HTTP/' + req.httpVersionMajor + '.' + req.httpVersionMinor + '" ' + | ||
(statusCode || res.statusCode) + ' ' + contentLength + ' "' + | ||
(req.headers['referer'] || req.headers['referrer'] || '') + '" "' + | ||
(req.headers['user-agent'] || '') + '"'); | ||
}; | ||
} | ||
|
||
next(); | ||
}; | ||
}; | ||
|
||
/** | ||
* Return formatted log line. | ||
* | ||
* @param {String} str | ||
* @param {IncomingMessage} req | ||
* @param {ServerResponse} res | ||
* @return {String} | ||
* @api private | ||
*/ | ||
|
||
function format(str, req, res) { | ||
return str | ||
.replace(':url', req.originalUrl) | ||
.replace(':method', req.method) | ||
.replace(':status', res.__statusCode || res.statusCode) | ||
.replace(':response-time', res.responseTime) | ||
.replace(':date', new Date().toUTCString()) | ||
.replace(':referrer', req.headers['referer'] || req.headers['referrer'] || '') | ||
.replace(':http-version', req.httpVersionMajor + '.' + req.httpVersionMinor) | ||
.replace(':remote-addr', req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))) | ||
.replace(':user-agent', req.headers['user-agent'] || '') | ||
.replace(/:req\[([^\]]+)\]/g, function(_, field){ return req.headers[field.toLowerCase()]; }) | ||
.replace(/:res\[([^\]]+)\]/g, function(_, field){ | ||
return res._headers | ||
? (res._headers[field.toLowerCase()] || res.__headers[field]) | ||
: (res.__headers && res.__headers[field]); | ||
}); | ||
} | ||
|
||
} | ||
|
||
return { | ||
connectLogger: getLogger | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
var vows = require('vows'), | ||
assert = require('assert'); | ||
|
||
var mockLog4js = { | ||
levels: { | ||
TRACE: 0, | ||
DEBUG: 1, | ||
INFO: 2, | ||
WARN: 3, | ||
ERROR: 4, | ||
FATAL: 5 | ||
} | ||
} | ||
|
||
function MockLogger() { | ||
|
||
var that = this; | ||
this.messages = []; | ||
|
||
this.log = function(level, message, exception) { | ||
that.messages.push({ level: level, message: message }); | ||
}; | ||
|
||
this.isLevelEnabled = function(level) { | ||
return (level >= that.level); | ||
}; | ||
|
||
this.level = mockLog4js.levels.TRACE; | ||
|
||
} | ||
|
||
function MockRequest(remoteAddr, method, originalUrl) { | ||
|
||
this.socket = { remoteAddress: remoteAddr }; | ||
this.originalUrl = originalUrl; | ||
this.method = method; | ||
this.httpVersionMajor = '5'; | ||
this.httpVersionMinor = '0'; | ||
this.headers = {} | ||
|
||
} | ||
|
||
function MockResponse(statusCode) { | ||
|
||
this.statusCode = statusCode; | ||
|
||
this.end = function(chunk, encoding) { | ||
|
||
} | ||
|
||
} | ||
|
||
vows.describe('log4js connect logger').addBatch({ | ||
'getConnectLoggerModule': { | ||
topic: function() { | ||
var clm = require('../lib/connect-logger')(mockLog4js); | ||
return clm; | ||
}, | ||
|
||
'should return a "connect logger" factory' : function(clm) { | ||
assert.isObject(clm); | ||
}, | ||
|
||
'take a log4js logger and return a "connect logger"' : { | ||
topic: function(clm) { | ||
var ml = new MockLogger(); | ||
var cl = clm.connectLogger(ml); | ||
return cl; | ||
}, | ||
|
||
'should return a "connect logger"': function(cl) { | ||
assert.isFunction(cl); | ||
} | ||
}, | ||
|
||
'log events' : { | ||
topic: function(clm) { | ||
var ml = new MockLogger(); | ||
var cl = clm.connectLogger(ml); | ||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url'); | ||
var res = new MockResponse(200); | ||
cl(req, res, function() { }); | ||
res.end('chunk', 'encoding'); | ||
return ml.messages; | ||
}, | ||
|
||
'check message': function(messages) { | ||
assert.isArray(messages); | ||
assert.length(messages, 1); | ||
assert.equal(messages[0].level, mockLog4js.levels.TRACE); | ||
assert.include(messages[0].message, 'GET'); | ||
assert.include(messages[0].message, 'http://url'); | ||
assert.include(messages[0].message, 'my.remote.addr'); | ||
assert.include(messages[0].message, '200'); | ||
} | ||
}, | ||
|
||
'log events with level below logging level' : { | ||
topic: function(clm) { | ||
var ml = new MockLogger(); | ||
ml.level = mockLog4js.levels.FATAL; | ||
var cl = clm.connectLogger(ml); | ||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url'); | ||
var res = new MockResponse(200); | ||
cl(req, res, function() { }); | ||
res.end('chunk', 'encoding'); | ||
return ml.messages; | ||
}, | ||
|
||
'check message': function(messages) { | ||
assert.isArray(messages); | ||
assert.isEmpty(messages); | ||
} | ||
}, | ||
|
||
'log events with non-default level and custom format' : { | ||
topic: function(clm) { | ||
var ml = new MockLogger(); | ||
ml.level = mockLog4js.levels.INFO; | ||
var cl = clm.connectLogger(ml, { level: mockLog4js.levels.INFO, format: ':method :url' } ); | ||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url'); | ||
var res = new MockResponse(200); | ||
cl(req, res, function() { }); | ||
res.end('chunk', 'encoding'); | ||
return ml.messages; | ||
}, | ||
|
||
'check message': function(messages) { | ||
assert.isArray(messages); | ||
assert.length(messages, 1); | ||
assert.equal(messages[0].level, mockLog4js.levels.INFO); | ||
assert.equal(messages[0].message, 'GET http://url'); | ||
} | ||
} | ||
|
||
} | ||
|
||
}).export(module); |