Merge pull request #1 from CartoDB/master
Upstream update, adds x-forwarde-for by default
This commit is contained in:
@@ -87,6 +87,15 @@ function createAppender(config) {
|
||||
// console.log("master : " + cluster.isMaster + " received message: " + JSON.stringify(message.event));
|
||||
|
||||
var loggingEvent = deserializeLoggingEvent(message.event);
|
||||
|
||||
// Adding PID metadata
|
||||
loggingEvent.pid = worker.process.pid;
|
||||
loggingEvent.cluster = {
|
||||
master: process.pid,
|
||||
worker: worker.process.pid,
|
||||
workerId: worker.id
|
||||
};
|
||||
|
||||
masterAppender(loggingEvent);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
var layouts = require('../layouts')
|
||||
, consoleLog = console.log.bind(console);
|
||||
|
||||
function consoleAppender (layout) {
|
||||
function consoleAppender (layout, timezoneOffset) {
|
||||
layout = layout || layouts.colouredLayout;
|
||||
return function(loggingEvent) {
|
||||
consoleLog(layout(loggingEvent));
|
||||
consoleLog(layout(loggingEvent, timezoneOffset));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ function configure(config) {
|
||||
if (config.layout) {
|
||||
layout = layouts.layout(config.layout.type, config.layout);
|
||||
}
|
||||
return consoleAppender(layout);
|
||||
return consoleAppender(layout, config.timezoneOffset);
|
||||
}
|
||||
|
||||
exports.appender = consoleAppender;
|
||||
|
||||
@@ -20,8 +20,9 @@ process.on('exit', function() {
|
||||
* @pattern the format that will be added to the end of filename when rolling,
|
||||
* also used to check when to roll files - defaults to '.yyyy-MM-dd'
|
||||
* @layout layout function for log messages - defaults to basicLayout
|
||||
* @timezoneOffset optional timezone offset in minutes - defaults to system local
|
||||
*/
|
||||
function appender(filename, pattern, alwaysIncludePattern, layout) {
|
||||
function appender(filename, pattern, alwaysIncludePattern, layout, timezoneOffset) {
|
||||
layout = layout || layouts.basicLayout;
|
||||
|
||||
var logFile = new streams.DateRollingFileStream(
|
||||
@@ -32,7 +33,7 @@ function appender(filename, pattern, alwaysIncludePattern, layout) {
|
||||
openFiles.push(logFile);
|
||||
|
||||
return function(logEvent) {
|
||||
logFile.write(layout(logEvent) + eol, "utf8");
|
||||
logFile.write(layout(logEvent, timezoneOffset) + eol, "utf8");
|
||||
};
|
||||
|
||||
}
|
||||
@@ -52,7 +53,7 @@ function configure(config, options) {
|
||||
config.filename = path.join(options.cwd, config.filename);
|
||||
}
|
||||
|
||||
return appender(config.filename, config.pattern, config.alwaysIncludePattern, layout);
|
||||
return appender(config.filename, config.pattern, config.alwaysIncludePattern, layout, config.timezoneOffset);
|
||||
}
|
||||
|
||||
function shutdown(cb) {
|
||||
|
||||
@@ -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() {
|
||||
@@ -25,8 +26,10 @@ process.on('exit', function() {
|
||||
* if not provided then logs won't be rotated.
|
||||
* @param numBackups - the number of log files to keep after logSize
|
||||
* has been reached (default 5)
|
||||
* @param compress - flag that controls log file compression
|
||||
* @param timezoneOffset - optional timezone offset in minutes (default system local)
|
||||
*/
|
||||
function fileAppender (file, layout, logSize, numBackups) {
|
||||
function fileAppender (file, layout, logSize, numBackups, compress, timezoneOffset) {
|
||||
var bytesWritten = 0;
|
||||
file = path.normalize(file);
|
||||
layout = layout || layouts.basicLayout;
|
||||
@@ -40,7 +43,8 @@ function fileAppender (file, layout, logSize, numBackups) {
|
||||
stream = new streams.RollingFileStream(
|
||||
file,
|
||||
fileSize,
|
||||
numFiles
|
||||
numFiles,
|
||||
{ "compress": compress }
|
||||
);
|
||||
} else {
|
||||
stream = fs.createWriteStream(
|
||||
@@ -60,10 +64,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");
|
||||
logFile.write(layout(loggingEvent, timezoneOffset) + eol, "utf8");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function configure(config, options) {
|
||||
@@ -76,7 +81,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, config.timezoneOffset);
|
||||
}
|
||||
|
||||
function shutdown(cb) {
|
||||
|
||||
@@ -127,8 +127,10 @@ RollingFileSync.prototype.write = function(chunk, encoding) {
|
||||
* if not provided then logs won't be rotated.
|
||||
* @param numBackups - the number of log files to keep after logSize
|
||||
* has been reached (default 5)
|
||||
* @param timezoneOffset - optional timezone offset in minutes
|
||||
* (default system local)
|
||||
*/
|
||||
function fileAppender (file, layout, logSize, numBackups) {
|
||||
function fileAppender (file, layout, logSize, numBackups, timezoneOffset) {
|
||||
debug("fileSync appender created");
|
||||
var bytesWritten = 0;
|
||||
file = path.normalize(file);
|
||||
@@ -166,7 +168,7 @@ function fileAppender (file, layout, logSize, numBackups) {
|
||||
var logFile = openTheStream(file, logSize, numBackups);
|
||||
|
||||
return function(loggingEvent) {
|
||||
logFile.write(layout(loggingEvent) + eol);
|
||||
logFile.write(layout(loggingEvent, timezoneOffset) + eol);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -180,7 +182,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.timezoneOffset);
|
||||
}
|
||||
|
||||
exports.appender = fileAppender;
|
||||
|
||||
@@ -85,6 +85,8 @@ function gelfAppender (layout, host, port, hostname, facility) {
|
||||
var firstData = data[0];
|
||||
|
||||
if (!firstData.GELF) return; // identify with GELF field defined
|
||||
// Remove the GELF key, some gelf supported logging systems drop the message with it
|
||||
delete firstData.GELF;
|
||||
Object.keys(firstData).forEach(function(key) {
|
||||
// skip _id field for graylog2, skip keys not starts with UNDERSCORE
|
||||
if (key.match(/^_/) || key !== "_id") {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
"use strict";
|
||||
var layouts = require("../layouts")
|
||||
, mailer = require("nodemailer")
|
||||
, os = require('os');
|
||||
, os = require('os')
|
||||
, async = require('async')
|
||||
, unsentCount = 0
|
||||
, shutdownTimeout;
|
||||
|
||||
/**
|
||||
* SMTP Appender. Sends logging events using SMTP protocol.
|
||||
@@ -11,6 +14,7 @@ var layouts = require("../layouts")
|
||||
* @param config appender configuration data
|
||||
* config.sendInterval time between log emails (in seconds), if 0
|
||||
* then every event sends an email
|
||||
* config.shutdownTimeout time to give up remaining emails (in seconds; defaults to 5).
|
||||
* @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
|
||||
*/
|
||||
function smtpAppender(config, layout) {
|
||||
@@ -21,22 +25,31 @@ function smtpAppender(config, layout) {
|
||||
var logEventBuffer = [];
|
||||
var sendTimer;
|
||||
|
||||
shutdownTimeout = ('shutdownTimeout' in config ? config.shutdownTimeout : 5) * 1000;
|
||||
|
||||
function sendBuffer() {
|
||||
if (logEventBuffer.length > 0) {
|
||||
|
||||
var transport = mailer.createTransport(config.transport, config[config.transport]);
|
||||
var transport = mailer.createTransport(config.SMTP);
|
||||
var firstEvent = logEventBuffer[0];
|
||||
var body = "";
|
||||
var count = logEventBuffer.length;
|
||||
while (logEventBuffer.length > 0) {
|
||||
body += layout(logEventBuffer.shift()) + "\n";
|
||||
body += layout(logEventBuffer.shift(), config.timezoneOffset) + "\n";
|
||||
}
|
||||
|
||||
var msg = {
|
||||
to: config.recipients,
|
||||
subject: config.subject || subjectLayout(firstEvent),
|
||||
text: body,
|
||||
headers: { "Hostname": os.hostname() }
|
||||
};
|
||||
|
||||
if (!config.html) {
|
||||
msg.text = body;
|
||||
} else {
|
||||
msg.html = body;
|
||||
}
|
||||
|
||||
if (config.sender) {
|
||||
msg.from = config.sender;
|
||||
}
|
||||
@@ -45,6 +58,7 @@ function smtpAppender(config, layout) {
|
||||
console.error("log4js.smtpAppender - Error happened", error);
|
||||
}
|
||||
transport.close();
|
||||
unsentCount -= count;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -59,6 +73,7 @@ function smtpAppender(config, layout) {
|
||||
}
|
||||
|
||||
return function(loggingEvent) {
|
||||
unsentCount++;
|
||||
logEventBuffer.push(loggingEvent);
|
||||
if (sendInterval > 0) {
|
||||
scheduleSend();
|
||||
@@ -76,7 +91,19 @@ function configure(config) {
|
||||
return smtpAppender(config, layout);
|
||||
}
|
||||
|
||||
function shutdown(cb) {
|
||||
if (shutdownTimeout > 0) {
|
||||
setTimeout(function() { unsentCount = 0; }, shutdownTimeout);
|
||||
}
|
||||
async.whilst(function() {
|
||||
return unsentCount > 0;
|
||||
}, function(done) {
|
||||
setTimeout(done, 100);
|
||||
}, cb);
|
||||
}
|
||||
|
||||
exports.name = "smtp";
|
||||
exports.appender = smtpAppender;
|
||||
exports.configure = configure;
|
||||
exports.shutdown = shutdown;
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"use strict";
|
||||
var levels = require("./levels");
|
||||
var DEFAULT_FORMAT = ':remote-addr - -' +
|
||||
' ":method :url HTTP/:http-version"' +
|
||||
' :status :content-length ":referrer"' +
|
||||
var _ = require('underscore');
|
||||
var DEFAULT_FORMAT = ':remote-addr - -' +
|
||||
' ":method :url HTTP/:http-version"' +
|
||||
' :status :content-length ":referrer"' +
|
||||
' ":user-agent"';
|
||||
/**
|
||||
* Log requests with the given `options` or a `format` string.
|
||||
@@ -52,7 +53,7 @@ function getLogger(logger4js, options) {
|
||||
// nologs
|
||||
if (nolog && nolog.test(req.originalUrl)) return next();
|
||||
if (thislogger.isLevelEnabled(level) || options.level === 'auto') {
|
||||
|
||||
|
||||
var start = new Date()
|
||||
, statusCode
|
||||
, writeHead = res.writeHead
|
||||
@@ -60,7 +61,7 @@ function getLogger(logger4js, options) {
|
||||
|
||||
// flag as logging
|
||||
req._logging = true;
|
||||
|
||||
|
||||
// proxy for statusCode.
|
||||
res.writeHead = function(code, headers){
|
||||
res.writeHead = writeHead;
|
||||
@@ -77,7 +78,7 @@ function getLogger(logger4js, options) {
|
||||
level = levels.toLevel(options.level, levels.INFO);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//hook on end request to emit the log entry of the HTTP request.
|
||||
res.on('finish', function() {
|
||||
res.responseTime = new Date() - start;
|
||||
@@ -88,21 +89,68 @@ function getLogger(logger4js, options) {
|
||||
if(res.statusCode >= 400) level = levels.ERROR;
|
||||
}
|
||||
if (thislogger.isLevelEnabled(level)) {
|
||||
var combined_tokens = assemble_tokens(req, res, options.tokens || []);
|
||||
if (typeof fmt === 'function') {
|
||||
var line = fmt(req, res, function(str){ return format(str, req, res); });
|
||||
var line = fmt(req, res, function(str){ return format(str, combined_tokens); });
|
||||
if (line) thislogger.log(level, line);
|
||||
} else {
|
||||
thislogger.log(level, format(fmt, req, res));
|
||||
thislogger.log(level, format(fmt, combined_tokens));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//ensure next gets always called
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom {token, replacement} objects to defaults, overwriting the defaults if any tokens clash
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @param {Array} custom_tokens [{ token: string-or-regexp, replacement: string-or-replace-function }]
|
||||
* @return {Array}
|
||||
*/
|
||||
function assemble_tokens(req, res, custom_tokens) {
|
||||
var array_unique_tokens = function(array) {
|
||||
var a = array.concat();
|
||||
for(var i=0; i<a.length; ++i) {
|
||||
for(var j=i+1; j<a.length; ++j) {
|
||||
if(a[i].token == a[j].token) { // not === because token can be regexp object
|
||||
a.splice(j--, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
var default_tokens = [];
|
||||
default_tokens.push({ token: ':url', replacement: req.originalUrl });
|
||||
default_tokens.push({ token: ':method', replacement: req.method });
|
||||
default_tokens.push({ token: ':status', replacement: res.__statusCode || res.statusCode });
|
||||
default_tokens.push({ token: ':response-time', replacement: res.responseTime });
|
||||
default_tokens.push({ token: ':date', replacement: new Date().toUTCString() });
|
||||
default_tokens.push({ token: ':referrer', replacement: req.headers.referer || req.headers.referrer || '' });
|
||||
default_tokens.push({ token: ':http-version', replacement: req.httpVersionMajor + '.' + req.httpVersionMinor });
|
||||
default_tokens.push({ token: ':remote-addr', replacement: req.headers['x-forwarded-for'] || req.ip || req._remoteAddress ||
|
||||
(req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))) });
|
||||
default_tokens.push({ token: ':user-agent', replacement: req.headers['user-agent'] });
|
||||
default_tokens.push({ token: ':content-length', replacement: (res._headers && res._headers['content-length']) ||
|
||||
(res.__headers && res.__headers['Content-Length']) || '-' });
|
||||
default_tokens.push({ token: /:req\[([^\]]+)\]/g, replacement: function(_, field) {
|
||||
return req.headers[field.toLowerCase()];
|
||||
} });
|
||||
default_tokens.push({ token: /:res\[([^\]]+)\]/g, replacement: function(_, field) {
|
||||
return res._headers ?
|
||||
(res._headers[field.toLowerCase()] || res.__headers[field])
|
||||
: (res.__headers && res.__headers[field]);
|
||||
} });
|
||||
|
||||
return array_unique_tokens(custom_tokens.concat(default_tokens));
|
||||
};
|
||||
|
||||
/**
|
||||
* Return formatted log line.
|
||||
*
|
||||
@@ -113,33 +161,10 @@ function getLogger(logger4js, options) {
|
||||
* @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.ip || req._remoteAddress || (
|
||||
req.socket &&
|
||||
(req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress))
|
||||
))
|
||||
.replace(':user-agent', req.headers['user-agent'] || '')
|
||||
.replace(
|
||||
':content-length',
|
||||
(res._headers && res._headers['content-length']) ||
|
||||
(res.__headers && res.__headers['Content-Length']) ||
|
||||
'-'
|
||||
)
|
||||
.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]);
|
||||
});
|
||||
function format(str, tokens) {
|
||||
return _.reduce(tokens, function(current_string, token) {
|
||||
return current_string.replace(token.token, token.replacement);
|
||||
}, str);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,9 +180,9 @@ function format(str, req, res) {
|
||||
* NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.gif?fuga
|
||||
* LOGGING http://example.com/hoge.agif
|
||||
* 1.2 in "\\.gif|\\.jpg$"
|
||||
* NOT LOGGING http://example.com/hoge.gif and
|
||||
* NOT LOGGING http://example.com/hoge.gif and
|
||||
* http://example.com/hoge.gif?fuga and http://example.com/hoge.jpg?fuga
|
||||
* LOGGING http://example.com/hoge.agif,
|
||||
* LOGGING http://example.com/hoge.agif,
|
||||
* http://example.com/hoge.ajpg and http://example.com/hoge.jpg?hoge
|
||||
* 1.3 in "\\.(gif|jpe?g|png)$"
|
||||
* NOT LOGGING http://example.com/hoge.gif and http://example.com/hoge.jpeg
|
||||
@@ -175,15 +200,15 @@ function createNoLogCondition(nolog) {
|
||||
if (nolog) {
|
||||
if (nolog instanceof RegExp) {
|
||||
regexp = nolog;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (typeof nolog === 'string') {
|
||||
regexp = new RegExp(nolog);
|
||||
}
|
||||
|
||||
|
||||
if (Array.isArray(nolog)) {
|
||||
var regexpsAsStrings = nolog.map(
|
||||
function convertToStrings(o) {
|
||||
function convertToStrings(o) {
|
||||
return o.source ? o.source : o;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -21,9 +21,9 @@ function addZero(vNumber) {
|
||||
* Thanks to http://www.svendtofte.com/code/date_format/
|
||||
* @private
|
||||
*/
|
||||
function offset(date) {
|
||||
function offset(timezoneOffset) {
|
||||
// Difference to Greenwich time (GMT) in hours
|
||||
var os = Math.abs(date.getTimezoneOffset());
|
||||
var os = Math.abs(timezoneOffset);
|
||||
var h = String(Math.floor(os/60));
|
||||
var m = String(os%60);
|
||||
if (h.length == 1) {
|
||||
@@ -32,26 +32,32 @@ function offset(date) {
|
||||
if (m.length == 1) {
|
||||
m = "0" + m;
|
||||
}
|
||||
return date.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
|
||||
return timezoneOffset < 0 ? "+"+h+m : "-"+h+m;
|
||||
}
|
||||
|
||||
exports.asString = function(/*format,*/ date) {
|
||||
exports.asString = function(/*format,*/ date, timezoneOffset) {
|
||||
var format = exports.ISO8601_FORMAT;
|
||||
if (typeof(date) === "string") {
|
||||
format = arguments[0];
|
||||
date = arguments[1];
|
||||
timezoneOffset = arguments[2];
|
||||
}
|
||||
|
||||
var vDay = addZero(date.getDate());
|
||||
var vMonth = addZero(date.getMonth()+1);
|
||||
var vYearLong = addZero(date.getFullYear());
|
||||
var vYearShort = addZero(date.getFullYear().toString().substring(2,4));
|
||||
// make the date independent of the system timezone by working with UTC
|
||||
if (timezoneOffset === undefined) {
|
||||
timezoneOffset = date.getTimezoneOffset();
|
||||
}
|
||||
date.setUTCMinutes(date.getUTCMinutes() - timezoneOffset);
|
||||
var vDay = addZero(date.getUTCDate());
|
||||
var vMonth = addZero(date.getUTCMonth()+1);
|
||||
var vYearLong = addZero(date.getUTCFullYear());
|
||||
var vYearShort = addZero(date.getUTCFullYear().toString().substring(2,4));
|
||||
var vYear = (format.indexOf("yyyy") > -1 ? vYearLong : vYearShort);
|
||||
var vHour = addZero(date.getHours());
|
||||
var vMinute = addZero(date.getMinutes());
|
||||
var vSecond = addZero(date.getSeconds());
|
||||
var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
|
||||
var vTimeZone = offset(date);
|
||||
var vHour = addZero(date.getUTCHours());
|
||||
var vMinute = addZero(date.getUTCMinutes());
|
||||
var vSecond = addZero(date.getUTCSeconds());
|
||||
var vMillisecond = padWithZeros(date.getUTCMilliseconds(), 3);
|
||||
var vTimeZone = offset(timezoneOffset);
|
||||
date.setUTCMinutes(date.getUTCMinutes() + timezoneOffset);
|
||||
var formatted = format
|
||||
.replace(/dd/g, vDay)
|
||||
.replace(/MM/g, vMonth)
|
||||
|
||||
@@ -71,11 +71,11 @@ function colorize (str, style) {
|
||||
return colorizeStart(style) + str + colorizeEnd(style);
|
||||
}
|
||||
|
||||
function timestampLevelAndCategory(loggingEvent, colour) {
|
||||
function timestampLevelAndCategory(loggingEvent, colour, timezoneOffest) {
|
||||
var output = colorize(
|
||||
formatLogData(
|
||||
'[%s] [%s] %s - '
|
||||
, dateFormat.asString(loggingEvent.startTime)
|
||||
, dateFormat.asString(loggingEvent.startTime, timezoneOffest)
|
||||
, loggingEvent.level
|
||||
, loggingEvent.categoryName
|
||||
)
|
||||
@@ -93,18 +93,19 @@ function timestampLevelAndCategory(loggingEvent, colour) {
|
||||
*
|
||||
* @author Stephan Strittmatter
|
||||
*/
|
||||
function basicLayout (loggingEvent) {
|
||||
return timestampLevelAndCategory(loggingEvent) + formatLogData(loggingEvent.data);
|
||||
function basicLayout (loggingEvent, timezoneOffset) {
|
||||
return timestampLevelAndCategory(loggingEvent, undefined, timezoneOffset) + formatLogData(loggingEvent.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* colouredLayout - taken from masylum's fork.
|
||||
* same as basicLayout, but with colours.
|
||||
*/
|
||||
function colouredLayout (loggingEvent) {
|
||||
function colouredLayout (loggingEvent, timezoneOffset) {
|
||||
return timestampLevelAndCategory(
|
||||
loggingEvent,
|
||||
colours[loggingEvent.level.toString()]
|
||||
colours[loggingEvent.level.toString()],
|
||||
timezoneOffset
|
||||
) + formatLogData(loggingEvent.data);
|
||||
}
|
||||
|
||||
@@ -139,13 +140,14 @@ function messagePassThroughLayout (loggingEvent) {
|
||||
* Takes a pattern string, array of tokens and returns a layout function.
|
||||
* @param {String} Log format pattern String
|
||||
* @param {object} map object of different tokens
|
||||
* @param {number} timezone offset in minutes
|
||||
* @return {Function}
|
||||
* @author Stephan Strittmatter
|
||||
* @author Jan Schmidle
|
||||
*/
|
||||
function patternLayout (pattern, tokens) {
|
||||
function patternLayout (pattern, tokens, timezoneOffset) {
|
||||
var TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";
|
||||
var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([\[\]cdhmnprzx%])(\{([^\}]+)\})?|([^%]+)/;
|
||||
var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([\[\]cdhmnprzxy%])(\{([^\}]+)\})?|([^%]+)/;
|
||||
|
||||
pattern = pattern || TTCC_CONVERSION_PATTERN;
|
||||
|
||||
@@ -177,7 +179,7 @@ function patternLayout (pattern, tokens) {
|
||||
}
|
||||
}
|
||||
// Format the date
|
||||
return dateFormat.asString(format, loggingEvent.startTime);
|
||||
return dateFormat.asString(format, loggingEvent.startTime, timezoneOffset);
|
||||
}
|
||||
|
||||
function hostname() {
|
||||
@@ -197,7 +199,7 @@ function patternLayout (pattern, tokens) {
|
||||
}
|
||||
|
||||
function startTime(loggingEvent) {
|
||||
return "" + loggingEvent.startTime.toLocaleTimeString();
|
||||
return dateFormat.asString('hh:mm:ss', loggingEvent.startTime, timezoneOffset);
|
||||
}
|
||||
|
||||
function startColour(loggingEvent) {
|
||||
@@ -212,8 +214,25 @@ function patternLayout (pattern, tokens) {
|
||||
return '%';
|
||||
}
|
||||
|
||||
function pid() {
|
||||
return process.pid;
|
||||
function pid(loggingEvent) {
|
||||
if (loggingEvent && loggingEvent.pid) {
|
||||
return loggingEvent.pid;
|
||||
} else {
|
||||
return process.pid;
|
||||
}
|
||||
}
|
||||
|
||||
function clusterInfo(loggingEvent, specifier) {
|
||||
if (loggingEvent.cluster && specifier) {
|
||||
return specifier
|
||||
.replace('%m', loggingEvent.cluster.master)
|
||||
.replace('%w', loggingEvent.cluster.worker)
|
||||
.replace('%i', loggingEvent.cluster.workerId);
|
||||
} else if (loggingEvent.cluster) {
|
||||
return loggingEvent.cluster.worker+'@'+loggingEvent.cluster.master;
|
||||
} else {
|
||||
return pid();
|
||||
}
|
||||
}
|
||||
|
||||
function userDefined(loggingEvent, specifier) {
|
||||
@@ -237,6 +256,7 @@ function patternLayout (pattern, tokens) {
|
||||
'r': startTime,
|
||||
'[': startColour,
|
||||
']': endColour,
|
||||
'y': clusterInfo,
|
||||
'z': pid,
|
||||
'%': percent,
|
||||
'x': userDefined
|
||||
@@ -295,9 +315,7 @@ function patternLayout (pattern, tokens) {
|
||||
} else {
|
||||
// Create a raw replacement string based on the conversion
|
||||
// character and specifier
|
||||
var replacement =
|
||||
replaceToken(conversionCharacter, loggingEvent, specifier) ||
|
||||
matchedString;
|
||||
var replacement = replaceToken(conversionCharacter, loggingEvent, specifier);
|
||||
|
||||
// Format the replacement according to any padding or
|
||||
// truncation specified
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
108
lib/log4js.js
108
lib/log4js.js
@@ -65,6 +65,8 @@ var events = require('events')
|
||||
replaceConsole: false
|
||||
};
|
||||
|
||||
require('./appenders/console');
|
||||
|
||||
function hasLogger(logger) {
|
||||
return loggers.hasOwnProperty(logger);
|
||||
}
|
||||
@@ -92,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.
|
||||
@@ -99,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];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -198,14 +241,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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,8 +284,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();
|
||||
@@ -253,12 +301,12 @@ function configureOnceOff(config, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function reloadConfiguration() {
|
||||
function reloadConfiguration(options) {
|
||||
var mtime = getMTime(configState.filename);
|
||||
if (!mtime) return;
|
||||
|
||||
|
||||
if (configState.lastMTime && (mtime.getTime() > configState.lastMTime.getTime())) {
|
||||
configureOnceOff(loadConfigurationFile(configState.filename));
|
||||
configureOnceOff(loadConfigurationFile(configState.filename), options);
|
||||
}
|
||||
configState.lastMTime = mtime;
|
||||
}
|
||||
@@ -280,7 +328,7 @@ function initReloadConfiguration(filename, options) {
|
||||
}
|
||||
configState.filename = filename;
|
||||
configState.lastMTime = getMTime(filename);
|
||||
configState.timerId = setInterval(reloadConfiguration, options.reloadSecs*1000);
|
||||
configState.timerId = setInterval(reloadConfiguration, options.reloadSecs*1000, options);
|
||||
}
|
||||
|
||||
function configure(configurationFileOrObject, options) {
|
||||
|
||||
@@ -51,7 +51,7 @@ Logger.prototype.removeLevel = function() {
|
||||
|
||||
Logger.prototype.log = function() {
|
||||
var args = Array.prototype.slice.call(arguments)
|
||||
, logLevel = levels.toLevel(args.shift())
|
||||
, logLevel = levels.toLevel(args.shift(), levels.INFO)
|
||||
, loggingEvent;
|
||||
if (this.isLevelEnabled(logLevel)) {
|
||||
loggingEvent = new LoggingEvent(this.category, logLevel, args, this);
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user