Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bf2bade32 | ||
|
|
0c74fbbf7d | ||
|
|
8dff114b49 | ||
|
|
c76fe098ae | ||
|
|
1454ae5350 | ||
|
|
3cf1d697e8 | ||
|
|
9fe32d06e3 | ||
|
|
b8e1d03928 | ||
|
|
ebfcf94db3 | ||
|
|
adeb714243 | ||
|
|
1cdd37c488 | ||
|
|
eb87ccb78d | ||
|
|
8360bb732c | ||
|
|
085a88d6fc | ||
|
|
957d5d369d | ||
|
|
57fc9e7aa0 | ||
|
|
435f4f320f | ||
|
|
af69eddd1c | ||
|
|
4dfe14a0c2 | ||
|
|
4a217afc37 | ||
|
|
41504a755d | ||
|
|
f22621199f | ||
|
|
25c543f8ae | ||
|
|
24268422cf | ||
|
|
ba80dc1588 | ||
|
|
adfad9ad20 | ||
|
|
35067af550 | ||
|
|
d31521bac0 | ||
|
|
6d7cab343d | ||
|
|
c624aef282 | ||
|
|
0ae72ee424 | ||
|
|
a4be20f8e1 | ||
|
|
d10d40b572 | ||
|
|
51ab2963d0 | ||
|
|
1f1442cb7c | ||
|
|
f987990339 | ||
|
|
6b029e98fc | ||
|
|
1629e01df9 | ||
|
|
ec72c03f81 | ||
|
|
3300dfae60 | ||
|
|
b694fd1d8d | ||
|
|
e07adf2ca4 | ||
|
|
ec5f4485f8 | ||
|
|
2f44dbf53e | ||
|
|
9da158f945 | ||
|
|
cd3971cc03 | ||
|
|
176d44833e | ||
|
|
988e9a41f6 | ||
|
|
39ce97d140 | ||
|
|
c753fe37bb | ||
|
|
a7a0964803 | ||
|
|
82950eb965 | ||
|
|
1e999f36d7 | ||
|
|
17c9b29ca5 | ||
|
|
492c45d055 | ||
|
|
ebbbea198d | ||
|
|
cacade0a37 | ||
|
|
02ea4831ea | ||
|
|
39a73586ed | ||
|
|
036293db41 | ||
|
|
6fa998408a | ||
|
|
7558a3c367 | ||
|
|
fb072dd70d | ||
|
|
af1ce2933b | ||
|
|
ade6dd8ea0 | ||
|
|
00c62c7fa6 | ||
|
|
ae04cc9a4a | ||
|
|
70a9444f4d | ||
|
|
3e78fcb630 | ||
|
|
44687e1bd1 | ||
|
|
8e5754371a | ||
|
|
feef9975c7 | ||
|
|
93695fbfc4 | ||
|
|
0571089a8b | ||
|
|
ab77895555 | ||
|
|
9637be8a41 | ||
|
|
0ecd729f49 | ||
|
|
f9c2e78055 | ||
|
|
e7267ecf46 | ||
|
|
c03185b563 | ||
|
|
c0aa8c5c86 | ||
|
|
59a6703549 | ||
|
|
ceffdf92e4 | ||
|
|
c9e72d0f00 | ||
|
|
a27345461b |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ node_modules
|
||||
.bob/
|
||||
test/streams/test-rolling-file-stream*
|
||||
test/streams/test-rolling-stream-with-existing-files*
|
||||
.idea
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.12"
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ Out of the box it supports the following features:
|
||||
* GELF appender
|
||||
* hook.io appender
|
||||
* Loggly appender
|
||||
* Logstash UDP appender
|
||||
* multiprocess appender (useful when you've got worker processes)
|
||||
* a logger for connect/express servers
|
||||
* configurable log message layout/patterns
|
||||
@@ -107,8 +108,9 @@ For FileAppender you can also pass the path to the log directory as an option wh
|
||||
log4js.configure('my_log4js_configuration.json', { cwd: '/absolute/path/to/log/dir' });
|
||||
```
|
||||
If you have already defined an absolute path for one of the FileAppenders in the configuration file, you could add a "absolute": true to the particular FileAppender to override the cwd option passed. Here is an example configuration file:
|
||||
```json
|
||||
|
||||
#### my_log4js_configuration.json ####
|
||||
```json
|
||||
{
|
||||
"appenders": [
|
||||
{
|
||||
|
||||
@@ -35,11 +35,13 @@ logger.setLevel('ERROR');
|
||||
//console logging methods have been replaced with log4js ones.
|
||||
//so this will get coloured output on console, and appear in cheese.log
|
||||
console.error("AAArgh! Something went wrong", { some: "otherObject", useful_for: "debug purposes" });
|
||||
console.log("This should appear as info output");
|
||||
|
||||
//these will not appear (logging level beneath error)
|
||||
logger.trace('Entering cheese testing');
|
||||
logger.debug('Got cheese.');
|
||||
logger.info('Cheese is Gouda.');
|
||||
logger.log('Something funny about cheese.');
|
||||
logger.warn('Cheese is quite smelly.');
|
||||
//these end up on the console and in cheese.log
|
||||
logger.error('Cheese %s is too ripe!', "gouda");
|
||||
|
||||
39
examples/logstashUDP.js
Normal file
39
examples/logstashUDP.js
Normal file
@@ -0,0 +1,39 @@
|
||||
var log4js = require('../lib/log4js');
|
||||
|
||||
/*
|
||||
Sample logstash config:
|
||||
udp {
|
||||
codec => json
|
||||
port => 10001
|
||||
queue_size => 2
|
||||
workers => 2
|
||||
type => myAppType
|
||||
}
|
||||
*/
|
||||
|
||||
log4js.configure({
|
||||
"appenders": [
|
||||
{
|
||||
type: "console",
|
||||
category: "myLogger"
|
||||
},
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": 10001,
|
||||
"type": "logstashUDP",
|
||||
"logType": "myAppType", // Optional, defaults to 'category'
|
||||
"fields": { // Optional, will be added to the 'fields' object in logstash
|
||||
"field1": "value1",
|
||||
"field2": "value2"
|
||||
},
|
||||
"layout": {
|
||||
"type": "pattern",
|
||||
"pattern": "%m"
|
||||
},
|
||||
"category": "myLogger"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var logger = log4js.getLogger("myLogger");
|
||||
logger.info("Test log message %s", "arg1", "arg2");
|
||||
@@ -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,11 +53,11 @@ 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) {
|
||||
async.forEach(openFiles, function(file, done) {
|
||||
async.each(openFiles, function(file, done) {
|
||||
if (!file.write(eol, "utf-8")) {
|
||||
file.once('drain', function() {
|
||||
file.end(done);
|
||||
|
||||
@@ -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,11 +81,11 @@ 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) {
|
||||
async.forEach(openFiles, function(file, done) {
|
||||
async.each(openFiles, function(file, done) {
|
||||
if (!file.write(eol, "utf-8")) {
|
||||
file.once('drain', function() {
|
||||
file.end(done);
|
||||
|
||||
@@ -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,76 +0,0 @@
|
||||
"use strict";
|
||||
var log4js = require('../log4js')
|
||||
, layouts = require('../layouts')
|
||||
, Hook = require('hook.io').Hook
|
||||
, util = require('util');
|
||||
|
||||
var Logger = function createLogger(options) {
|
||||
var self = this;
|
||||
var actualAppender = options.actualAppender;
|
||||
Hook.call(self, options);
|
||||
self.on('hook::ready', function hookReady() {
|
||||
self.on('*::' + options.name + '::log', function log(loggingEvent) {
|
||||
deserializeLoggingEvent(loggingEvent);
|
||||
actualAppender(loggingEvent);
|
||||
});
|
||||
});
|
||||
};
|
||||
util.inherits(Logger, Hook);
|
||||
|
||||
function deserializeLoggingEvent(loggingEvent) {
|
||||
loggingEvent.startTime = new Date(loggingEvent.startTime);
|
||||
loggingEvent.level.toString = function levelToString() {
|
||||
return loggingEvent.level.levelStr;
|
||||
};
|
||||
}
|
||||
|
||||
function initHook(hookioOptions) {
|
||||
var loggerHook;
|
||||
if (hookioOptions.mode === 'master') {
|
||||
// Start the master hook, handling the actual logging
|
||||
loggerHook = new Logger(hookioOptions);
|
||||
} else {
|
||||
// Start a worker, just emitting events for a master
|
||||
loggerHook = new Hook(hookioOptions);
|
||||
}
|
||||
loggerHook.start();
|
||||
return loggerHook;
|
||||
}
|
||||
|
||||
function getBufferedHook(hook, eventName) {
|
||||
var hookBuffer = [];
|
||||
var hookReady = false;
|
||||
hook.on('hook::ready', function emptyBuffer() {
|
||||
hookBuffer.forEach(function logBufferItem(loggingEvent) {
|
||||
hook.emit(eventName, loggingEvent);
|
||||
});
|
||||
hookReady = true;
|
||||
});
|
||||
|
||||
return function log(loggingEvent) {
|
||||
if (hookReady) {
|
||||
hook.emit(eventName, loggingEvent);
|
||||
} else {
|
||||
hookBuffer.push(loggingEvent);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createAppender(hookioOptions) {
|
||||
var loggerHook = initHook(hookioOptions);
|
||||
var loggerEvent = hookioOptions.name + '::log';
|
||||
return getBufferedHook(loggerHook, loggerEvent);
|
||||
}
|
||||
|
||||
function configure(config) {
|
||||
var actualAppender;
|
||||
if (config.appender && config.mode === 'master') {
|
||||
log4js.loadAppender(config.appender.type);
|
||||
actualAppender = log4js.appenderMakers[config.appender.type](config.appender);
|
||||
config.actualAppender = actualAppender;
|
||||
}
|
||||
return createAppender(config);
|
||||
}
|
||||
|
||||
exports.appender = createAppender;
|
||||
exports.configure = configure;
|
||||
@@ -2,19 +2,21 @@
|
||||
var levels = require('../levels')
|
||||
, log4js = require('../log4js');
|
||||
|
||||
function logLevelFilter (levelString, appender) {
|
||||
var level = levels.toLevel(levelString);
|
||||
function logLevelFilter (minLevelString, maxLevelString, appender) {
|
||||
var minLevel = levels.toLevel(minLevelString);
|
||||
var maxLevel = levels.toLevel(maxLevelString, levels.FATAL);
|
||||
return function(logEvent) {
|
||||
if (logEvent.level.isGreaterThanOrEqualTo(level)) {
|
||||
var eventLevel = logEvent.level;
|
||||
if (eventLevel.isGreaterThanOrEqualTo(minLevel) && eventLevel.isLessThanOrEqualTo(maxLevel)) {
|
||||
appender(logEvent);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function configure(config) {
|
||||
function configure(config, options) {
|
||||
log4js.loadAppender(config.appender.type);
|
||||
var appender = log4js.appenderMakers[config.appender.type](config.appender);
|
||||
return logLevelFilter(config.level, appender);
|
||||
var appender = log4js.appenderMakers[config.appender.type](config.appender, options);
|
||||
return logLevelFilter(config.level, config.maxLevel, appender);
|
||||
}
|
||||
|
||||
exports.appender = logLevelFilter;
|
||||
|
||||
@@ -18,24 +18,17 @@ var layouts = require('../layouts')
|
||||
*/
|
||||
function logglyAppender(config, layout) {
|
||||
var client = loggly.createClient(config);
|
||||
if(!layout) layout = passThrough;
|
||||
|
||||
function packageMessage(loggingEvent) {
|
||||
function BaseItem(level, msg) {
|
||||
this.level = level || loggingEvent.level.toString();
|
||||
this.category = loggingEvent.categoryName;
|
||||
this.hostname = os.hostname().toString();
|
||||
if (typeof msg !== 'undefined')
|
||||
this.msg = msg;
|
||||
};
|
||||
|
||||
var formattedMsg = passThrough(loggingEvent);
|
||||
return new BaseItem(formattedMsg);
|
||||
};
|
||||
|
||||
return function(loggingEvent) {
|
||||
var a = layout ? layout(loggingEvent) : packageMessage(loggingEvent);
|
||||
client.log(a, config.tags);
|
||||
};
|
||||
return function(loggingEvent) {
|
||||
var msg = layout(loggingEvent);
|
||||
client.log({
|
||||
msg: msg,
|
||||
level: loggingEvent.level.levelStr,
|
||||
category: loggingEvent.categoryName,
|
||||
hostname: os.hostname().toString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function configure(config) {
|
||||
|
||||
50
lib/appenders/logstashUDP.js
Normal file
50
lib/appenders/logstashUDP.js
Normal file
@@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
var layouts = require('../layouts')
|
||||
, dgram = require('dgram')
|
||||
, util = require('util');
|
||||
|
||||
function logstashUDP (config, layout) {
|
||||
var udp = dgram.createSocket('udp4');
|
||||
var type = config.logType ? config.logType : config.category;
|
||||
layout = layout || layouts.colouredLayout;
|
||||
if(!config.fields) {
|
||||
config.fields = {};
|
||||
}
|
||||
return function(loggingEvent) {
|
||||
var logMessage = layout(loggingEvent);
|
||||
var fields = {};
|
||||
for(var i in config.fields) {
|
||||
fields[i] = config.fields[i];
|
||||
}
|
||||
fields['level'] = loggingEvent.level.levelStr;
|
||||
var logObject = {
|
||||
'@timestamp': (new Date(loggingEvent.startTime)).toISOString(),
|
||||
type: type,
|
||||
message: logMessage,
|
||||
fields: fields
|
||||
};
|
||||
sendLog(udp, config.host, config.port, logObject);
|
||||
};
|
||||
}
|
||||
|
||||
function sendLog(udp, host, port, logObject) {
|
||||
var buffer = new Buffer(JSON.stringify(logObject));
|
||||
udp.send(buffer, 0, buffer.length, port, host, function(err, bytes) {
|
||||
if(err) {
|
||||
console.error(
|
||||
"log4js.logstashUDP - %s:%p Error: %s", host, port, util.inspect(err)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function configure(config) {
|
||||
var layout;
|
||||
if (config.layout) {
|
||||
layout = layouts.layout(config.layout.type, config.layout);
|
||||
}
|
||||
return logstashUDP(config, layout);
|
||||
}
|
||||
|
||||
exports.appender = logstashUDP;
|
||||
exports.configure = configure;
|
||||
@@ -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,16 +53,15 @@ 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
|
||||
, end = res.end
|
||||
, url = req.originalUrl;
|
||||
|
||||
// flag as logging
|
||||
req._logging = true;
|
||||
|
||||
|
||||
// proxy for statusCode.
|
||||
res.writeHead = function(code, headers){
|
||||
res.writeHead = writeHead;
|
||||
@@ -78,11 +78,9 @@ function getLogger(logger4js, options) {
|
||||
level = levels.toLevel(options.level, levels.INFO);
|
||||
}
|
||||
};
|
||||
|
||||
// proxy end to output a line to the provided logger.
|
||||
res.end = function(chunk, encoding) {
|
||||
res.end = end;
|
||||
res.end(chunk, encoding);
|
||||
|
||||
//hook on end request to emit the log entry of the HTTP request.
|
||||
res.on('finish', function() {
|
||||
res.responseTime = new Date() - start;
|
||||
//status code response level handling
|
||||
if(res.statusCode && options.level === 'auto'){
|
||||
@@ -91,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.
|
||||
*
|
||||
@@ -116,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,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
|
||||
@@ -178,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);
|
||||
}
|
||||
|
||||
@@ -125,6 +126,7 @@ function messagePassThroughLayout (loggingEvent) {
|
||||
* - %d date in various formats
|
||||
* - %% %
|
||||
* - %n newline
|
||||
* - %z pid
|
||||
* - %x{<tokenname>} add dynamic tokens to your log. Tokens are specified in the tokens parameter
|
||||
* You can use %[ and %] to define a colored block.
|
||||
*
|
||||
@@ -138,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]+)?([\[\]cdhmnprx%])(\{([^\}]+)\})?|([^%]+)/;
|
||||
var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([\[\]cdhmnprzxy%])(\{([^\}]+)\})?|([^%]+)/;
|
||||
|
||||
pattern = pattern || TTCC_CONVERSION_PATTERN;
|
||||
|
||||
@@ -176,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() {
|
||||
@@ -196,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) {
|
||||
@@ -211,6 +214,27 @@ function patternLayout (pattern, tokens) {
|
||||
return '%';
|
||||
}
|
||||
|
||||
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) {
|
||||
if (typeof(tokens[specifier]) !== 'undefined') {
|
||||
if (typeof(tokens[specifier]) === 'function') {
|
||||
@@ -232,6 +256,8 @@ function patternLayout (pattern, tokens) {
|
||||
'r': startTime,
|
||||
'[': startColour,
|
||||
']': endColour,
|
||||
'y': clusterInfo,
|
||||
'z': pid,
|
||||
'%': percent,
|
||||
'x': userDefined
|
||||
};
|
||||
@@ -289,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
|
||||
};
|
||||
|
||||
134
lib/log4js.js
134
lib/log4js.js
@@ -65,43 +65,103 @@ var events = require('events')
|
||||
replaceConsole: false
|
||||
};
|
||||
|
||||
require('./appenders/console');
|
||||
|
||||
function hasLogger(logger) {
|
||||
return loggers.hasOwnProperty(logger);
|
||||
}
|
||||
|
||||
|
||||
function getBufferedLogger(categoryName) {
|
||||
var base_logger = getLogger(categoryName);
|
||||
var logger = {};
|
||||
logger.temp = [];
|
||||
logger.target = base_logger;
|
||||
logger.flush = function () {
|
||||
for (var i = 0; i < logger.temp.length; i++) {
|
||||
var log = logger.temp[i];
|
||||
logger.target[log.level](log.message);
|
||||
delete logger.temp[i];
|
||||
}
|
||||
};
|
||||
logger.trace = function (message) { logger.temp.push({level: 'trace', message: message}); };
|
||||
logger.debug = function (message) { logger.temp.push({level: 'debug', message: message}); };
|
||||
logger.info = function (message) { logger.temp.push({level: 'info', message: message}); };
|
||||
logger.warn = function (message) { logger.temp.push({level: 'warn', message: message}); };
|
||||
logger.error = function (message) { logger.temp.push({level: 'error', message: message}); };
|
||||
logger.fatal = function (message) { logger.temp.push({level: 'fatal', message: message}); };
|
||||
|
||||
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.
|
||||
* @param {String} categoryName name of category to log to.
|
||||
* @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];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -170,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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,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();
|
||||
@@ -225,12 +296,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;
|
||||
}
|
||||
@@ -252,7 +323,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) {
|
||||
@@ -365,7 +436,7 @@ function shutdown(cb) {
|
||||
}, []);
|
||||
|
||||
// Call each of the shutdown functions.
|
||||
async.forEach(
|
||||
async.each(
|
||||
shutdownFunctions,
|
||||
function(shutdownFn, done) {
|
||||
shutdownFn(done);
|
||||
@@ -375,6 +446,7 @@ function shutdown(cb) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getBufferedLogger: getBufferedLogger,
|
||||
getLogger: getLogger,
|
||||
getDefaultLogger: getDefaultLogger,
|
||||
hasLogger: hasLogger,
|
||||
|
||||
@@ -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();
|
||||
@@ -71,7 +100,7 @@ RollingFileStream.prototype.roll = function(filename, callback) {
|
||||
//roll the backups (rename file.n to file.n+1, where n <= numBackups)
|
||||
debug("Renaming the old files");
|
||||
fs.readdir(path.dirname(filename), function (err, files) {
|
||||
async.forEachSeries(
|
||||
async.eachSeries(
|
||||
files.filter(justTheseFiles).sort(byIndex).reverse(),
|
||||
increaseFileIndex,
|
||||
cb
|
||||
|
||||
11
package.json
11
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "log4js",
|
||||
"version": "0.6.17",
|
||||
"version": "0.6.25",
|
||||
"description": "Port of Log4js to work with node.",
|
||||
"keywords": [
|
||||
"logging",
|
||||
@@ -8,6 +8,7 @@
|
||||
"log4j",
|
||||
"node"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/log4js",
|
||||
"author": "Gareth Jones <gareth.nomiddlename@gmail.com>",
|
||||
"repository": {
|
||||
@@ -28,14 +29,14 @@
|
||||
"lib": "lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "0.1.15",
|
||||
"semver": "~1.1.4",
|
||||
"readable-stream": "~1.0.2"
|
||||
"async": "~0.2.0",
|
||||
"readable-stream": "~1.0.2",
|
||||
"semver": "~4.3.3",
|
||||
"underscore": "1.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vows": "0.7.0",
|
||||
"sandboxed-module": "0.1.3",
|
||||
"hook.io": "0.8.10",
|
||||
"underscore": "1.2.1"
|
||||
},
|
||||
"browser": {
|
||||
|
||||
@@ -16,24 +16,24 @@ function remove(filename) {
|
||||
vows.describe('log4js categoryFilter').addBatch({
|
||||
'appender': {
|
||||
topic: function() {
|
||||
|
||||
|
||||
var log4js = require('../lib/log4js'), logEvents = [], webLogger, appLogger;
|
||||
log4js.clearAppenders();
|
||||
var appender = require('../lib/appenders/categoryFilter')
|
||||
.appender(
|
||||
['app'],
|
||||
['app'],
|
||||
function(evt) { logEvents.push(evt); }
|
||||
);
|
||||
log4js.addAppender(appender, ["app","web"]);
|
||||
|
||||
|
||||
webLogger = log4js.getLogger("web");
|
||||
appLogger = log4js.getLogger("app");
|
||||
|
||||
|
||||
webLogger.debug('This should get logged');
|
||||
appLogger.debug('This should not');
|
||||
webLogger.debug('Hello again');
|
||||
log4js.getLogger('db').debug('This shouldn\'t be included by the appender anyway');
|
||||
|
||||
|
||||
return logEvents;
|
||||
},
|
||||
'should only pass matching category' : function(logEvents) {
|
||||
@@ -42,25 +42,25 @@ vows.describe('log4js categoryFilter').addBatch({
|
||||
assert.equal(logEvents[1].data[0], 'Hello again');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'configure': {
|
||||
topic: function() {
|
||||
var log4js = require('../lib/log4js')
|
||||
, logger, weblogger;
|
||||
|
||||
|
||||
remove(__dirname + '/categoryFilter-web.log');
|
||||
remove(__dirname + '/categoryFilter-noweb.log');
|
||||
|
||||
|
||||
log4js.configure('test/with-categoryFilter.json');
|
||||
logger = log4js.getLogger("app");
|
||||
weblogger = log4js.getLogger("web");
|
||||
|
||||
|
||||
logger.info('Loading app');
|
||||
logger.debug('Initialising indexes');
|
||||
weblogger.info('00:00:00 GET / 200');
|
||||
weblogger.warn('00:00:00 GET / 500');
|
||||
//wait for the file system to catch up
|
||||
setTimeout(this.callback, 100);
|
||||
setTimeout(this.callback, 500);
|
||||
},
|
||||
'tmp-tests.log': {
|
||||
topic: function() {
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
"use strict";
|
||||
var vows = require('vows')
|
||||
, assert = require('assert')
|
||||
, util = require('util')
|
||||
, EE = require('events').EventEmitter
|
||||
, levels = require('../lib/levels');
|
||||
|
||||
function MockLogger() {
|
||||
|
||||
var that = this;
|
||||
this.messages = [];
|
||||
|
||||
|
||||
this.log = function(level, message, exception) {
|
||||
that.messages.push({ level: level, message: message });
|
||||
};
|
||||
@@ -16,7 +18,7 @@ function MockLogger() {
|
||||
this.isLevelEnabled = function(level) {
|
||||
return level.isGreaterThanOrEqualTo(that.level);
|
||||
};
|
||||
|
||||
|
||||
this.level = levels.TRACE;
|
||||
|
||||
}
|
||||
@@ -37,15 +39,19 @@ function MockRequest(remoteAddr, method, originalUrl, headers) {
|
||||
}
|
||||
|
||||
function MockResponse() {
|
||||
|
||||
this.end = function(chunk, encoding) {
|
||||
var r = this;
|
||||
this.end = function(chunk, encoding) {
|
||||
r.emit('finish');
|
||||
};
|
||||
|
||||
this.writeHead = function(code, headers) {
|
||||
this.statusCode = code;
|
||||
this._headers = headers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
util.inherits(MockResponse, EE);
|
||||
|
||||
function request(cl, method, url, code, reqHeaders, resHeaders) {
|
||||
var req = new MockRequest('my.remote.addr', method, url, reqHeaders);
|
||||
var res = new MockResponse();
|
||||
@@ -60,7 +66,7 @@ vows.describe('log4js connect logger').addBatch({
|
||||
var clm = require('../lib/connect-logger');
|
||||
return clm;
|
||||
},
|
||||
|
||||
|
||||
'should return a "connect logger" factory' : function(clm) {
|
||||
assert.isObject(clm);
|
||||
},
|
||||
@@ -71,18 +77,21 @@ vows.describe('log4js connect logger').addBatch({
|
||||
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 cb = this.callback;
|
||||
request(cl, 'GET', 'http://url', 200);
|
||||
return ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
|
||||
'check message': function(messages) {
|
||||
@@ -104,7 +113,7 @@ vows.describe('log4js connect logger').addBatch({
|
||||
request(cl, 'GET', 'http://url', 200);
|
||||
return ml.messages;
|
||||
},
|
||||
|
||||
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
assert.isEmpty(messages);
|
||||
@@ -114,12 +123,14 @@ vows.describe('log4js connect logger').addBatch({
|
||||
'log events with non-default level and custom format' : {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, { level: levels.INFO, format: ':method :url' } );
|
||||
request(cl, 'GET', 'http://url', 200);
|
||||
return ml.messages;
|
||||
},
|
||||
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10); },
|
||||
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
assert.equal(messages.length, 1);
|
||||
@@ -131,10 +142,13 @@ vows.describe('log4js connect logger').addBatch({
|
||||
'logger with options as string': {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, ':method :url');
|
||||
request(cl, 'POST', 'http://meh', 200);
|
||||
return ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
'should use the passed in format': function(messages) {
|
||||
assert.equal(messages[0].message, 'POST http://meh');
|
||||
@@ -144,6 +158,7 @@ vows.describe('log4js connect logger').addBatch({
|
||||
'auto log levels': {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, { level: 'auto', format: ':method :url' });
|
||||
request(cl, 'GET', 'http://meh', 200);
|
||||
@@ -151,7 +166,9 @@ vows.describe('log4js connect logger').addBatch({
|
||||
request(cl, 'GET', 'http://meh', 302);
|
||||
request(cl, 'GET', 'http://meh', 404);
|
||||
request(cl, 'GET', 'http://meh', 500);
|
||||
return ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
|
||||
'should use INFO for 2xx': function(messages) {
|
||||
@@ -175,10 +192,13 @@ vows.describe('log4js connect logger').addBatch({
|
||||
'format using a function': {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, function(req, res, formatFn) { return "I was called"; });
|
||||
request(cl, 'GET', 'http://blah', 200);
|
||||
return ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
|
||||
'should call the format function': function(messages) {
|
||||
@@ -189,14 +209,17 @@ vows.describe('log4js connect logger').addBatch({
|
||||
'format that includes request headers': {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, ':req[Content-Type]');
|
||||
request(
|
||||
cl,
|
||||
'GET', 'http://blah', 200,
|
||||
cl,
|
||||
'GET', 'http://blah', 200,
|
||||
{ 'Content-Type': 'application/json' }
|
||||
);
|
||||
return ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
'should output the request header': function(messages) {
|
||||
assert.equal(messages[0].message, 'application/json');
|
||||
@@ -206,6 +229,7 @@ vows.describe('log4js connect logger').addBatch({
|
||||
'format that includes response headers': {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, ':res[Content-Type]');
|
||||
request(
|
||||
@@ -214,13 +238,58 @@ vows.describe('log4js connect logger').addBatch({
|
||||
null,
|
||||
{ 'Content-Type': 'application/cheese' }
|
||||
);
|
||||
return ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
|
||||
'should output the response header': function(messages) {
|
||||
assert.equal(messages[0].message, 'application/cheese');
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
'log events with custom token' : {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, { level: levels.INFO, format: ':method :url :custom_string', tokens: [{
|
||||
token: ':custom_string', replacement: 'fooBAR'
|
||||
}] } );
|
||||
request(cl, 'GET', 'http://url', 200);
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
assert.equal(messages.length, 1);
|
||||
assert.ok(levels.INFO.isEqualTo(messages[0].level));
|
||||
assert.equal(messages[0].message, 'GET http://url fooBAR');
|
||||
}
|
||||
},
|
||||
|
||||
'log events with custom override token' : {
|
||||
topic: function(clm) {
|
||||
var ml = new MockLogger();
|
||||
var cb = this.callback;
|
||||
ml.level = levels.INFO;
|
||||
var cl = clm.connectLogger(ml, { level: levels.INFO, format: ':method :url :date', tokens: [{
|
||||
token: ':date', replacement: "20150310"
|
||||
}] } );
|
||||
request(cl, 'GET', 'http://url', 200);
|
||||
setTimeout(function() {
|
||||
cb(null, ml.messages);
|
||||
},10);
|
||||
},
|
||||
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
assert.equal(messages.length, 1);
|
||||
assert.ok(levels.INFO.isEqualTo(messages[0].level));
|
||||
assert.equal(messages[0].message, 'GET http://url 20150310');
|
||||
}
|
||||
}
|
||||
}
|
||||
}).export(module);
|
||||
|
||||
@@ -3,11 +3,13 @@ var vows = require('vows')
|
||||
, assert = require('assert')
|
||||
, dateFormat = require('../lib/date_format');
|
||||
|
||||
function createFixedDate() {
|
||||
return new Date(2010, 0, 11, 14, 31, 30, 5);
|
||||
}
|
||||
|
||||
vows.describe('date_format').addBatch({
|
||||
'Date extensions': {
|
||||
topic: function() {
|
||||
return new Date(2010, 0, 11, 14, 31, 30, 5);
|
||||
},
|
||||
topic: createFixedDate,
|
||||
'should format a date as string using a pattern': function(date) {
|
||||
assert.equal(
|
||||
dateFormat.asString(dateFormat.DATETIME_FORMAT, date),
|
||||
@@ -20,13 +22,16 @@ vows.describe('date_format').addBatch({
|
||||
'2010-01-11 14:31:30.005'
|
||||
);
|
||||
},
|
||||
'should provide a ISO8601 with timezone offset format': function(date) {
|
||||
'should provide a ISO8601 with timezone offset format': function() {
|
||||
var date = createFixedDate();
|
||||
date.setMinutes(date.getMinutes() - date.getTimezoneOffset() - 660);
|
||||
date.getTimezoneOffset = function() { return -660; };
|
||||
assert.equal(
|
||||
dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, date),
|
||||
"2010-01-11T14:31:30+1100"
|
||||
);
|
||||
|
||||
date = createFixedDate();
|
||||
date.setMinutes(date.getMinutes() - date.getTimezoneOffset() + 120);
|
||||
date.getTimezoneOffset = function() { return 120; };
|
||||
assert.equal(
|
||||
dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, date),
|
||||
@@ -40,7 +45,9 @@ vows.describe('date_format').addBatch({
|
||||
'14:31:30.005'
|
||||
);
|
||||
},
|
||||
'should provide a custom format': function(date) {
|
||||
'should provide a custom format': function() {
|
||||
var date = createFixedDate();
|
||||
date.setMinutes(date.getMinutes() - date.getTimezoneOffset() + 120);
|
||||
date.getTimezoneOffset = function() { return 120; };
|
||||
assert.equal(
|
||||
dateFormat.asString("O.SSS.ss.mm.hh.dd.MM.yy", date),
|
||||
|
||||
@@ -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' : {
|
||||
|
||||
@@ -244,6 +244,7 @@ vows.describe('log4js gelfAppender').addBatch({
|
||||
},
|
||||
'should pick up the options': function(message) {
|
||||
assert.equal(message.host, 'cheese');
|
||||
assert.isUndefined(message.GELF); // make sure flag was removed
|
||||
assert.equal(message._facility, 'nonsense');
|
||||
assert.equal(message._every1, 'Hello every one'); // the default value
|
||||
assert.equal(message._every2, 'Overwritten!'); // the overwritten value
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
"use strict";
|
||||
var vows = require('vows')
|
||||
, assert = require('assert')
|
||||
, sandbox = require('sandboxed-module');
|
||||
|
||||
function fancyResultingHookioAppender(hookNotReady) {
|
||||
var emitHook = !hookNotReady
|
||||
, result = { ons: {}, emissions: {}, logged: [], configs: [] };
|
||||
|
||||
var fakeLog4Js = {
|
||||
appenderMakers: {}
|
||||
};
|
||||
fakeLog4Js.loadAppender = function (appender) {
|
||||
fakeLog4Js.appenderMakers[appender] = function (config) {
|
||||
result.actualLoggerConfig = config;
|
||||
return function log(logEvent) {
|
||||
result.logged.push(logEvent);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
var fakeHookIo = { Hook: function(config) { result.configs.push(config); } };
|
||||
fakeHookIo.Hook.prototype.start = function () {
|
||||
result.startCalled = true;
|
||||
};
|
||||
fakeHookIo.Hook.prototype.on = function (eventName, functionToExec) {
|
||||
result.ons[eventName] = { functionToExec: functionToExec };
|
||||
if (emitHook && eventName === 'hook::ready') {
|
||||
functionToExec();
|
||||
}
|
||||
};
|
||||
fakeHookIo.Hook.prototype.emit = function (eventName, data) {
|
||||
result.emissions[eventName] = result.emissions[eventName] || [];
|
||||
result.emissions[eventName].push({data: data});
|
||||
var on = '*::' + eventName;
|
||||
if (eventName !== 'hook::ready' && result.ons[on]) {
|
||||
result.ons[on].callingCount =
|
||||
result.ons[on].callingCount ? result.ons[on].callingCount += 1 : 1;
|
||||
result.ons[on].functionToExec(data);
|
||||
}
|
||||
};
|
||||
|
||||
return { theResult: result,
|
||||
theModule: sandbox.require('../lib/appenders/hookio', {
|
||||
requires: {
|
||||
'../log4js': fakeLog4Js,
|
||||
'hook.io': fakeHookIo
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
vows.describe('log4js hookioAppender').addBatch({
|
||||
'master': {
|
||||
topic: function() {
|
||||
var fancy = fancyResultingHookioAppender();
|
||||
var logger = fancy.theModule.configure(
|
||||
{
|
||||
name: 'ohno',
|
||||
mode: 'master',
|
||||
'hook-port': 5001,
|
||||
appender: { type: 'file' }
|
||||
}
|
||||
);
|
||||
logger(
|
||||
{
|
||||
level: { levelStr: 'INFO' },
|
||||
data: "ALRIGHTY THEN",
|
||||
startTime: '2011-10-27T03:53:16.031Z'
|
||||
}
|
||||
);
|
||||
logger(
|
||||
{
|
||||
level: { levelStr: 'DEBUG' },
|
||||
data: "OH WOW",
|
||||
startTime: '2011-10-27T04:53:16.031Z'
|
||||
}
|
||||
);
|
||||
return fancy.theResult;
|
||||
},
|
||||
|
||||
'should write to the actual appender': function (result) {
|
||||
assert.isTrue(result.startCalled);
|
||||
assert.equal(result.configs.length, 1);
|
||||
assert.equal(result.configs[0]['hook-port'], 5001);
|
||||
assert.equal(result.logged.length, 2);
|
||||
assert.equal(result.emissions['ohno::log'].length, 2);
|
||||
assert.equal(result.ons['*::ohno::log'].callingCount, 2);
|
||||
},
|
||||
|
||||
'data written should be formatted correctly': function (result) {
|
||||
assert.equal(result.logged[0].level.toString(), 'INFO');
|
||||
assert.equal(result.logged[0].data, 'ALRIGHTY THEN');
|
||||
assert.isTrue(typeof(result.logged[0].startTime) === 'object');
|
||||
assert.equal(result.logged[1].level.toString(), 'DEBUG');
|
||||
assert.equal(result.logged[1].data, 'OH WOW');
|
||||
assert.isTrue(typeof(result.logged[1].startTime) === 'object');
|
||||
},
|
||||
|
||||
'the actual logger should get the right config': function (result) {
|
||||
assert.equal(result.actualLoggerConfig.type, 'file');
|
||||
}
|
||||
},
|
||||
'worker': {
|
||||
'should emit logging events to the master': {
|
||||
topic: function() {
|
||||
var fancy = fancyResultingHookioAppender();
|
||||
var logger = fancy.theModule.configure({
|
||||
name: 'ohno',
|
||||
mode: 'worker',
|
||||
appender: { type: 'file' }
|
||||
});
|
||||
logger({
|
||||
level: { levelStr: 'INFO' },
|
||||
data: "ALRIGHTY THEN",
|
||||
startTime: '2011-10-27T03:53:16.031Z'
|
||||
});
|
||||
logger({
|
||||
level: { levelStr: 'DEBUG' },
|
||||
data: "OH WOW",
|
||||
startTime: '2011-10-27T04:53:16.031Z'
|
||||
});
|
||||
return fancy.theResult;
|
||||
},
|
||||
|
||||
'should not write to the actual appender': function (result) {
|
||||
assert.isTrue(result.startCalled);
|
||||
assert.equal(result.logged.length, 0);
|
||||
assert.equal(result.emissions['ohno::log'].length, 2);
|
||||
assert.isUndefined(result.ons['*::ohno::log']);
|
||||
}
|
||||
}
|
||||
},
|
||||
'when hook not ready': {
|
||||
topic: function() {
|
||||
var fancy = fancyResultingHookioAppender(true)
|
||||
, logger = fancy.theModule.configure({
|
||||
name: 'ohno',
|
||||
mode: 'worker'
|
||||
});
|
||||
|
||||
logger({
|
||||
level: { levelStr: 'INFO' },
|
||||
data: "something",
|
||||
startTime: '2011-10-27T03:45:12.031Z'
|
||||
});
|
||||
return fancy;
|
||||
},
|
||||
'should buffer the log events': function(fancy) {
|
||||
assert.isUndefined(fancy.theResult.emissions['ohno::log']);
|
||||
},
|
||||
},
|
||||
'when hook ready': {
|
||||
topic: function() {
|
||||
var fancy = fancyResultingHookioAppender(true)
|
||||
, logger = fancy.theModule.configure({
|
||||
name: 'ohno',
|
||||
mode: 'worker'
|
||||
});
|
||||
|
||||
logger({
|
||||
level: { levelStr: 'INFO' },
|
||||
data: "something",
|
||||
startTime: '2011-10-27T03:45:12.031Z'
|
||||
});
|
||||
|
||||
fancy.theResult.ons['hook::ready'].functionToExec();
|
||||
return fancy;
|
||||
},
|
||||
'should emit the buffered events': function(fancy) {
|
||||
assert.equal(fancy.theResult.emissions['ohno::log'].length, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}).exportTo(module);
|
||||
@@ -179,7 +179,7 @@ vows.describe('log4js layouts').addBatch({
|
||||
topic: function() {
|
||||
var event = {
|
||||
data: ['this is a test'],
|
||||
startTime: new Date(2010, 11, 5, 14, 18, 30, 45),
|
||||
startTime: new Date('2010-12-05T14:18:30.045Z'), //new Date(2010, 11, 5, 14, 18, 30, 45),
|
||||
categoryName: "multiple.levels.of.tests",
|
||||
level: {
|
||||
toString: function() { return "DEBUG"; }
|
||||
@@ -217,6 +217,9 @@ vows.describe('log4js layouts').addBatch({
|
||||
'%h should output hostname' : function(args) {
|
||||
test(args, '%h', os.hostname().toString());
|
||||
},
|
||||
'%z should output pid' : function(args) {
|
||||
test(args, '%z', process.pid);
|
||||
},
|
||||
'%c should handle category names like java-style package names': function(args) {
|
||||
test(args, '%c{1}', 'tests');
|
||||
test(args, '%c{2}', 'of.tests');
|
||||
@@ -279,14 +282,14 @@ vows.describe('log4js layouts').addBatch({
|
||||
test(args, '%x{testFunction}', 'testFunctionToken');
|
||||
},
|
||||
'%x{doesNotExist} should output the string stored in tokens': function(args) {
|
||||
test(args, '%x{doesNotExist}', '%x{doesNotExist}');
|
||||
test(args, '%x{doesNotExist}', 'null');
|
||||
},
|
||||
'%x{fnThatUsesLogEvent} should be able to use the logEvent': function(args) {
|
||||
test(args, '%x{fnThatUsesLogEvent}', 'DEBUG');
|
||||
},
|
||||
'%x should output the string stored in tokens': function(args) {
|
||||
test(args, '%x', '%x');
|
||||
},
|
||||
test(args, '%x', 'null');
|
||||
}
|
||||
},
|
||||
'layout makers': {
|
||||
topic: require('../lib/layouts'),
|
||||
|
||||
@@ -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': {
|
||||
|
||||
@@ -21,12 +21,13 @@ vows.describe('log4js logLevelFilter').addBatch({
|
||||
log4js.addAppender(
|
||||
require('../lib/appenders/logLevelFilter')
|
||||
.appender(
|
||||
'ERROR',
|
||||
'ERROR',
|
||||
undefined,
|
||||
function(evt) { logEvents.push(evt); }
|
||||
),
|
||||
),
|
||||
"logLevelTest"
|
||||
);
|
||||
|
||||
|
||||
logger = log4js.getLogger("logLevelTest");
|
||||
logger.debug('this should not trigger an event');
|
||||
logger.warn('neither should this');
|
||||
@@ -45,18 +46,21 @@ vows.describe('log4js logLevelFilter').addBatch({
|
||||
topic: function() {
|
||||
var log4js = require('../lib/log4js')
|
||||
, logger;
|
||||
|
||||
|
||||
remove(__dirname + '/logLevelFilter.log');
|
||||
remove(__dirname + '/logLevelFilter-warnings.log');
|
||||
|
||||
remove(__dirname + '/logLevelFilter-debugs.log');
|
||||
|
||||
log4js.configure('test/with-logLevelFilter.json');
|
||||
logger = log4js.getLogger("tests");
|
||||
logger.info('main');
|
||||
logger.error('both');
|
||||
logger.warn('both');
|
||||
logger.debug('main');
|
||||
logger.debug('debug');
|
||||
logger.info('info');
|
||||
logger.error('error');
|
||||
logger.warn('warn');
|
||||
logger.debug('debug');
|
||||
logger.trace('trace');
|
||||
//wait for the file system to catch up
|
||||
setTimeout(this.callback, 100);
|
||||
setTimeout(this.callback, 500);
|
||||
},
|
||||
'tmp-tests.log': {
|
||||
topic: function() {
|
||||
@@ -64,7 +68,7 @@ vows.describe('log4js logLevelFilter').addBatch({
|
||||
},
|
||||
'should contain all log messages': function (contents) {
|
||||
var messages = contents.trim().split(EOL);
|
||||
assert.deepEqual(messages, ['main','both','both','main']);
|
||||
assert.deepEqual(messages, ['debug','info','error','warn','debug','trace']);
|
||||
}
|
||||
},
|
||||
'tmp-tests-warnings.log': {
|
||||
@@ -73,7 +77,16 @@ vows.describe('log4js logLevelFilter').addBatch({
|
||||
},
|
||||
'should contain only error and warning log messages': function(contents) {
|
||||
var messages = contents.trim().split(EOL);
|
||||
assert.deepEqual(messages, ['both','both']);
|
||||
assert.deepEqual(messages, ['error','warn']);
|
||||
}
|
||||
},
|
||||
'tmp-tests-debugs.log': {
|
||||
topic: function() {
|
||||
fs.readFile(__dirname + '/logLevelFilter-debugs.log','utf8',this.callback);
|
||||
},
|
||||
'should contain only trace and debug log messages': function(contents) {
|
||||
var messages = contents.trim().split(EOL);
|
||||
assert.deepEqual(messages, ['debug','debug','trace']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,72 @@ function setupConsoleTest() {
|
||||
}
|
||||
|
||||
vows.describe('log4js').addBatch({
|
||||
|
||||
'getBufferedLogger': {
|
||||
topic: function () {
|
||||
var log4js = require('../lib/log4js');
|
||||
log4js.clearAppenders();
|
||||
var logger = log4js.getBufferedLogger('tests');
|
||||
return logger;
|
||||
},
|
||||
|
||||
'should take a category and return a logger': function (logger) {
|
||||
assert.equal(logger.target.category, 'tests');
|
||||
assert.isFunction(logger.flush);
|
||||
assert.isFunction(logger.trace);
|
||||
assert.isFunction(logger.debug);
|
||||
assert.isFunction(logger.info);
|
||||
assert.isFunction(logger.warn);
|
||||
assert.isFunction(logger.error);
|
||||
assert.isFunction(logger.fatal);
|
||||
},
|
||||
|
||||
'cache events': {
|
||||
topic: function () {
|
||||
var log4js = require('../lib/log4js');
|
||||
log4js.clearAppenders();
|
||||
var logger = log4js.getBufferedLogger('tests1');
|
||||
var events = [];
|
||||
logger.target.addListener("log", function (logEvent) { events.push(logEvent); });
|
||||
logger.debug("Debug event");
|
||||
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;
|
||||
},
|
||||
|
||||
'should not emit log events if .flush() is not called.': function (events) {
|
||||
assert.equal(events.length, 0);
|
||||
}
|
||||
},
|
||||
|
||||
'log events after flush() is called': {
|
||||
topic: function () {
|
||||
var log4js = require('../lib/log4js');
|
||||
log4js.clearAppenders();
|
||||
var logger = log4js.getBufferedLogger('tests2');
|
||||
logger.target.setLevel("TRACE");
|
||||
var events = [];
|
||||
logger.target.addListener("log", function (logEvent) { events.push(logEvent); });
|
||||
logger.debug("Debug event");
|
||||
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" });
|
||||
logger.flush();
|
||||
return events;
|
||||
},
|
||||
|
||||
'should emit log events when .flush() is called.': function (events) {
|
||||
assert.equal(events.length, 6);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
'getLogger': {
|
||||
topic: function() {
|
||||
var log4js = require('../lib/log4js');
|
||||
|
||||
106
test/logstashUDP-test.js
Normal file
106
test/logstashUDP-test.js
Normal file
@@ -0,0 +1,106 @@
|
||||
"use strict";
|
||||
var sys = require("sys");
|
||||
var vows = require('vows')
|
||||
, assert = require('assert')
|
||||
, log4js = require('../lib/log4js')
|
||||
, sandbox = require('sandboxed-module')
|
||||
;
|
||||
|
||||
function setupLogging(category, options) {
|
||||
var udpSent = {};
|
||||
|
||||
var fakeDgram = {
|
||||
createSocket: function (type) {
|
||||
return {
|
||||
send: function(buffer, offset, length, port, host, callback) {
|
||||
udpSent.date = new Date();
|
||||
udpSent.host = host;
|
||||
udpSent.port = port;
|
||||
udpSent.length = length;
|
||||
udpSent.offset = 0;
|
||||
udpSent.buffer = buffer;
|
||||
callback(undefined, length);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var logstashModule = sandbox.require('../lib/appenders/logstashUDP', {
|
||||
requires: {
|
||||
'dgram': fakeDgram
|
||||
}
|
||||
});
|
||||
log4js.clearAppenders();
|
||||
log4js.addAppender(logstashModule.configure(options), category);
|
||||
|
||||
return {
|
||||
logger: log4js.getLogger(category),
|
||||
results: udpSent
|
||||
};
|
||||
}
|
||||
|
||||
vows.describe('logstashUDP appender').addBatch({
|
||||
'when logging with logstash via UDP': {
|
||||
topic: function() {
|
||||
var setup = setupLogging('logstashUDP', {
|
||||
"host": "127.0.0.1",
|
||||
"port": 10001,
|
||||
"type": "logstashUDP",
|
||||
"logType": "myAppType",
|
||||
"category": "myLogger",
|
||||
"fields": {
|
||||
"field1": "value1",
|
||||
"field2": "value2"
|
||||
},
|
||||
"layout": {
|
||||
"type": "pattern",
|
||||
"pattern": "%m"
|
||||
}
|
||||
});
|
||||
setup.logger.log('trace', 'Log event #1');
|
||||
return setup;
|
||||
},
|
||||
'an UDP packet should be sent': function (topic) {
|
||||
assert.equal(topic.results.host, "127.0.0.1");
|
||||
assert.equal(topic.results.port, 10001);
|
||||
assert.equal(topic.results.offset, 0);
|
||||
var json = JSON.parse(topic.results.buffer.toString());
|
||||
assert.equal(json.type, 'myAppType');
|
||||
var fields = {
|
||||
field1: 'value1',
|
||||
field2: 'value2',
|
||||
level: 'TRACE'
|
||||
};
|
||||
assert.equal(JSON.stringify(json.fields), JSON.stringify(fields));
|
||||
assert.equal(json.message, 'Log event #1');
|
||||
// Assert timestamp, up to hours resolution.
|
||||
var date = new Date(json['@timestamp']);
|
||||
assert.equal(
|
||||
date.toISOString().substring(0, 14),
|
||||
topic.results.date.toISOString().substring(0, 14)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
'when missing some options': {
|
||||
topic: function() {
|
||||
var setup = setupLogging('myLogger', {
|
||||
"host": "127.0.0.1",
|
||||
"port": 10001,
|
||||
"type": "logstashUDP",
|
||||
"category": "myLogger",
|
||||
"layout": {
|
||||
"type": "pattern",
|
||||
"pattern": "%m"
|
||||
}
|
||||
});
|
||||
setup.logger.log('trace', 'Log event #1');
|
||||
return setup;
|
||||
},
|
||||
'it sets some defaults': function (topic) {
|
||||
var json = JSON.parse(topic.results.buffer.toString());
|
||||
assert.equal(json.type, 'myLogger');
|
||||
assert.equal(JSON.stringify(json.fields), JSON.stringify({'level': 'TRACE'}));
|
||||
}
|
||||
}
|
||||
}).export(module);
|
||||
@@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
var vows = require('vows')
|
||||
, assert = require('assert')
|
||||
, util = require('util')
|
||||
, EE = require('events').EventEmitter
|
||||
, levels = require('../lib/levels');
|
||||
|
||||
function MockLogger() {
|
||||
@@ -31,13 +33,14 @@ function MockRequest(remoteAddr, method, originalUrl) {
|
||||
}
|
||||
|
||||
function MockResponse(statusCode) {
|
||||
|
||||
var r = this;
|
||||
this.statusCode = statusCode;
|
||||
|
||||
this.end = function(chunk, encoding) {
|
||||
|
||||
r.emit('finish');
|
||||
};
|
||||
}
|
||||
util.inherits(MockResponse, EE);
|
||||
|
||||
vows.describe('log4js connect logger').addBatch({
|
||||
'getConnectLoggerModule': {
|
||||
@@ -61,9 +64,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d){
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.png'); // not gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages);
|
||||
},10);
|
||||
},
|
||||
'check message': function(messages){
|
||||
assert.isArray(messages);
|
||||
@@ -81,9 +87,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d) {
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.gif'); // gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages);
|
||||
},10);
|
||||
},
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
@@ -103,9 +112,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d){
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.png'); // not gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages){
|
||||
assert.isArray(messages);
|
||||
@@ -123,9 +135,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d) {
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.gif'); // gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
@@ -136,9 +151,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d) {
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.jpeg'); // gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
@@ -157,9 +175,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d){
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.png'); // not gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages){
|
||||
assert.isArray(messages);
|
||||
@@ -177,9 +198,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d) {
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.gif'); // gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
@@ -191,9 +215,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d) {
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.jpeg'); // gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
@@ -212,9 +239,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d){
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.png'); // not gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages){
|
||||
assert.isArray(messages);
|
||||
@@ -232,9 +262,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d) {
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.gif'); // gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
@@ -246,9 +279,12 @@ vows.describe('log4js connect logger').addBatch({
|
||||
topic: function(d) {
|
||||
var req = new MockRequest('my.remote.addr', 'GET', 'http://url/hoge.jpeg'); // gif
|
||||
var res = new MockResponse(200);
|
||||
var cb = this.callback;
|
||||
d.cl(req, res, function() { });
|
||||
res.end('chunk', 'encoding');
|
||||
return d.ml.messages;
|
||||
setTimeout(function() {
|
||||
cb(null, d.ml.messages)
|
||||
}, 10);
|
||||
},
|
||||
'check message': function(messages) {
|
||||
assert.isArray(messages);
|
||||
|
||||
@@ -7,7 +7,7 @@ var vows = require('vows')
|
||||
|
||||
function setupLogging(category, options) {
|
||||
var msgs = [];
|
||||
|
||||
|
||||
var fakeMailer = {
|
||||
createTransport: function (name, options) {
|
||||
return {
|
||||
@@ -49,7 +49,7 @@ function setupLogging(category, options) {
|
||||
});
|
||||
|
||||
log4js.addAppender(smtpModule.configure(options), category);
|
||||
|
||||
|
||||
return {
|
||||
logger: log4js.getLogger(category),
|
||||
mailer: fakeMailer,
|
||||
@@ -74,7 +74,6 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
topic: function() {
|
||||
var setup = setupLogging('minimal config', {
|
||||
recipients: 'recipient@domain.com',
|
||||
transport: "SMTP",
|
||||
SMTP: {
|
||||
port: 25,
|
||||
auth: {
|
||||
@@ -98,7 +97,6 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
recipients: 'recipient@domain.com',
|
||||
sender: 'sender@domain.com',
|
||||
subject: 'This is subject',
|
||||
transport: "SMTP",
|
||||
SMTP: {
|
||||
port: 25,
|
||||
auth: {
|
||||
@@ -134,7 +132,6 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
var self = this;
|
||||
var setup = setupLogging('separate email for each event', {
|
||||
recipients: 'recipient@domain.com',
|
||||
transport: "SMTP",
|
||||
SMTP: {
|
||||
port: 25,
|
||||
auth: {
|
||||
@@ -150,10 +147,10 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
}, 500);
|
||||
setTimeout(function () {
|
||||
setup.logger.info('Log event #3');
|
||||
}, 1050);
|
||||
}, 1100);
|
||||
setTimeout(function () {
|
||||
self.callback(null, setup);
|
||||
}, 2100);
|
||||
}, 3000);
|
||||
},
|
||||
'there should be three messages': function (result) {
|
||||
assert.equal(result.results.length, 3);
|
||||
@@ -168,7 +165,6 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
var setup = setupLogging('multiple events in one email', {
|
||||
recipients: 'recipient@domain.com',
|
||||
sendInterval: 1,
|
||||
transport: "SMTP",
|
||||
SMTP: {
|
||||
port: 25,
|
||||
auth: {
|
||||
@@ -181,13 +177,13 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
}, 0);
|
||||
setTimeout(function () {
|
||||
setup.logger.info('Log event #2');
|
||||
}, 500);
|
||||
}, 100);
|
||||
setTimeout(function () {
|
||||
setup.logger.info('Log event #3');
|
||||
}, 1050);
|
||||
}, 1500);
|
||||
setTimeout(function () {
|
||||
self.callback(null, setup);
|
||||
}, 2100);
|
||||
}, 3000);
|
||||
},
|
||||
'there should be two messages': function (result) {
|
||||
assert.equal(result.results.length, 2);
|
||||
@@ -206,7 +202,6 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
var setup = setupLogging('error when sending email', {
|
||||
recipients: 'recipient@domain.com',
|
||||
sendInterval: 0,
|
||||
transport: 'SMTP',
|
||||
SMTP: { port: 25, auth: { user: 'user@domain.com' } }
|
||||
});
|
||||
|
||||
@@ -218,7 +213,7 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
close: function() { }
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
setup.logger.info("This will break");
|
||||
return setup.console;
|
||||
},
|
||||
@@ -228,6 +223,4 @@ vows.describe('log4js smtpAppender').addBatch({
|
||||
assert.equal(cons.errors[0].value.message, 'oh noes');
|
||||
}
|
||||
}
|
||||
|
||||
}).export(module);
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ vows.describe('RollingFileStream').addBatch({
|
||||
__dirname + "/test-rolling-file-stream-write-more",
|
||||
45
|
||||
);
|
||||
async.forEach(
|
||||
async.each(
|
||||
[0, 1, 2, 3, 4, 5, 6],
|
||||
function(i, cb) {
|
||||
stream.write(i +".cheese\n", "utf8", cb);
|
||||
@@ -183,7 +183,7 @@ vows.describe('RollingFileStream').addBatch({
|
||||
45,
|
||||
5
|
||||
);
|
||||
async.forEach(
|
||||
async.each(
|
||||
[0, 1, 2, 3, 4, 5, 6],
|
||||
function(i, cb) {
|
||||
stream.write(i +".cheese\n", "utf8", cb);
|
||||
|
||||
86
test/subcategories-test.js
Normal file
86
test/subcategories-test.js
Normal file
@@ -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);
|
||||
@@ -12,6 +12,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": "tests",
|
||||
"type": "logLevelFilter",
|
||||
"level": "TRACE",
|
||||
"maxLevel": "DEBUG",
|
||||
"appender": {
|
||||
"type": "file",
|
||||
"filename": "test/logLevelFilter-debugs.log",
|
||||
"layout": {
|
||||
"type": "messagePassThrough"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"category": "tests",
|
||||
"type": "file",
|
||||
@@ -23,6 +36,6 @@
|
||||
],
|
||||
|
||||
"levels": {
|
||||
"tests": "DEBUG"
|
||||
"tests": "TRACE"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user