61beac28d3
+ lib/appenders/clustered.js + test/clusteredAppender-test.js Instead os using sockets (like multiprocess) or dead and unmaintained hook.io, Clustered appender uses process.send(message) / worker.on('message', callback) mechanisms for transporting data between worker processes and master logger. Master logger takes an "appenders" array of actual appenders that are triggered when worker appenders send some data. This guarantees sequential writes to appenders, so the log messages are not mixed in single lines of log.
118 lines
3.2 KiB
JavaScript
Executable File
118 lines
3.2 KiB
JavaScript
Executable File
"use strict";
|
|
|
|
var cluster = require('cluster');
|
|
var log4js = require('../log4js');
|
|
|
|
/**
|
|
* Takes a loggingEvent object, returns string representation of it.
|
|
*/
|
|
function serializeLoggingEvent(loggingEvent) {
|
|
return JSON.stringify(loggingEvent);
|
|
}
|
|
|
|
/**
|
|
* Takes a string, returns an object with
|
|
* the correct log properties.
|
|
*
|
|
* This method has been "borrowed" from the `multiprocess` appender
|
|
* by `nomiddlename` (https://github.com/nomiddlename/log4js-node/blob/master/lib/appenders/multiprocess.js)
|
|
*
|
|
* Apparently, node.js serializes everything to strings when using `process.send()`,
|
|
* so we need smart deserialization that will recreate log date and level for further processing by log4js internals.
|
|
*/
|
|
function deserializeLoggingEvent(loggingEventString) {
|
|
|
|
var loggingEvent;
|
|
|
|
try {
|
|
|
|
loggingEvent = JSON.parse(loggingEventString);
|
|
loggingEvent.startTime = new Date(loggingEvent.startTime);
|
|
loggingEvent.level = log4js.levels.toLevel(loggingEvent.level.levelStr);
|
|
|
|
} catch (e) {
|
|
|
|
// JSON.parse failed, just log the contents probably a naughty.
|
|
loggingEvent = {
|
|
startTime: new Date(),
|
|
categoryName: 'log4js',
|
|
level: log4js.levels.ERROR,
|
|
data: [ 'Unable to parse log:', loggingEventString ]
|
|
};
|
|
}
|
|
return loggingEvent;
|
|
}
|
|
|
|
/**
|
|
* Creates an appender.
|
|
*
|
|
* If the current process is a master (`cluster.isMaster`), then this will be a "master appender".
|
|
* Otherwise this will be a worker appender, that just sends loggingEvents to the master process.
|
|
*
|
|
* If you are using this method directly, make sure to provide it with `config.actualAppenders` array
|
|
* of actual appender instances.
|
|
*
|
|
* Or better use `configure(config, options)`
|
|
*/
|
|
function createAppender(config) {
|
|
|
|
if (cluster.isMaster) {
|
|
|
|
var masterAppender = function(loggingEvent) {
|
|
|
|
if (config.actualAppenders) {
|
|
var size = config.actualAppenders.length;
|
|
for(var i = 0; i < size; i++) {
|
|
config.actualAppenders[i](loggingEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Listen on new workers
|
|
cluster.on('fork', function(worker) {
|
|
|
|
worker.on('message', function(message) {
|
|
if (message.type && message.type === '::log-message') {
|
|
// console.log("master : " + cluster.isMaster + " received message: " + JSON.stringify(message.event));
|
|
|
|
var loggingEvent = deserializeLoggingEvent(message.event);
|
|
masterAppender(loggingEvent);
|
|
}
|
|
});
|
|
|
|
});
|
|
|
|
return masterAppender;
|
|
|
|
} else {
|
|
|
|
return function(loggingEvent) {
|
|
// If inside the worker process, then send the logger event to master.
|
|
if (cluster.isWorker) {
|
|
// console.log("worker " + cluster.worker.id + " is sending message");
|
|
process.send({ type: '::log-message', event: serializeLoggingEvent(loggingEvent)});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function configure(config, options) {
|
|
|
|
if (config.appenders && cluster.isMaster) {
|
|
|
|
var size = config.appenders.length;
|
|
config.actualAppenders = new Array(size);
|
|
|
|
for(var i = 0; i < size; i++) {
|
|
|
|
log4js.loadAppender(config.appenders[i].type);
|
|
config.actualAppenders[i] = log4js.appenderMakers[config.appenders[i].type](config.appenders[i], options);
|
|
|
|
}
|
|
}
|
|
|
|
return createAppender(config);
|
|
}
|
|
|
|
exports.appender = createAppender;
|
|
exports.configure = configure;
|