158 lines
4.3 KiB
JavaScript
158 lines
4.3 KiB
JavaScript
|
"use strict";
|
||
|
var log4js = require('../log4js')
|
||
|
, debug = require('debug')('log4js:multiprocess')
|
||
|
, net = require('net')
|
||
|
, END_MSG = '__LOG4JS__'
|
||
|
, servers = [];
|
||
|
|
||
|
/**
|
||
|
* Creates a server, listening on config.loggerPort, config.loggerHost.
|
||
|
* Output goes to config.actualAppender (config.appender is used to
|
||
|
* set up that appender).
|
||
|
*/
|
||
|
function logServer(config) {
|
||
|
|
||
|
/**
|
||
|
* Takes a utf-8 string, returns an object with
|
||
|
* the correct log properties.
|
||
|
*/
|
||
|
function deserializeLoggingEvent(clientSocket, msg) {
|
||
|
var loggingEvent;
|
||
|
try {
|
||
|
loggingEvent = JSON.parse(msg);
|
||
|
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:', msg ]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
loggingEvent.remoteAddress = clientSocket.remoteAddress;
|
||
|
loggingEvent.remotePort = clientSocket.remotePort;
|
||
|
|
||
|
return loggingEvent;
|
||
|
}
|
||
|
|
||
|
var actualAppender = config.actualAppender,
|
||
|
server = net.createServer(function serverCreated(clientSocket) {
|
||
|
clientSocket.setEncoding('utf8');
|
||
|
var logMessage = '';
|
||
|
|
||
|
function logTheMessage(msg) {
|
||
|
if (logMessage.length > 0) {
|
||
|
actualAppender(deserializeLoggingEvent(clientSocket, msg));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function chunkReceived(chunk) {
|
||
|
var event;
|
||
|
logMessage += chunk || '';
|
||
|
if (logMessage.indexOf(END_MSG) > -1) {
|
||
|
event = logMessage.substring(0, logMessage.indexOf(END_MSG));
|
||
|
logTheMessage(event);
|
||
|
logMessage = logMessage.substring(event.length + END_MSG.length) || '';
|
||
|
//check for more, maybe it was a big chunk
|
||
|
chunkReceived();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
clientSocket.on('data', chunkReceived);
|
||
|
clientSocket.on('end', chunkReceived);
|
||
|
});
|
||
|
|
||
|
server.listen(config.loggerPort || 5000, config.loggerHost || 'localhost', function() {
|
||
|
servers.push(server);
|
||
|
//allow the process to exit, if this is the only socket active
|
||
|
server.unref();
|
||
|
});
|
||
|
|
||
|
return actualAppender;
|
||
|
}
|
||
|
|
||
|
function workerAppender(config) {
|
||
|
var canWrite = false,
|
||
|
buffer = [],
|
||
|
socket;
|
||
|
|
||
|
createSocket();
|
||
|
|
||
|
function createSocket() {
|
||
|
socket = net.createConnection(config.loggerPort || 5000, config.loggerHost || 'localhost');
|
||
|
socket.on('connect', function() {
|
||
|
emptyBuffer();
|
||
|
canWrite = true;
|
||
|
});
|
||
|
socket.on('timeout', socket.end.bind(socket));
|
||
|
//don't bother listening for 'error', 'close' gets called after that anyway
|
||
|
socket.on('close', createSocket);
|
||
|
}
|
||
|
|
||
|
function emptyBuffer() {
|
||
|
var evt;
|
||
|
while ((evt = buffer.shift())) {
|
||
|
write(evt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function write(loggingEvent) {
|
||
|
// JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
|
||
|
// The following allows us to serialize errors correctly.
|
||
|
// Validate that we really are in this case
|
||
|
if (loggingEvent && loggingEvent.stack && JSON.stringify(loggingEvent) === '{}') {
|
||
|
loggingEvent = {stack : loggingEvent.stack};
|
||
|
}
|
||
|
socket.write(JSON.stringify(loggingEvent), 'utf8');
|
||
|
socket.write(END_MSG, 'utf8');
|
||
|
}
|
||
|
|
||
|
return function log(loggingEvent) {
|
||
|
if (canWrite) {
|
||
|
write(loggingEvent);
|
||
|
} else {
|
||
|
buffer.push(loggingEvent);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function createAppender(config) {
|
||
|
if (config.mode === 'master') {
|
||
|
return logServer(config);
|
||
|
} else {
|
||
|
return workerAppender(config);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function configure(config, options) {
|
||
|
var actualAppender;
|
||
|
if (config.appender && config.mode === 'master') {
|
||
|
log4js.loadAppender(config.appender.type);
|
||
|
actualAppender = log4js.appenderMakers[config.appender.type](config.appender, options);
|
||
|
config.actualAppender = actualAppender;
|
||
|
}
|
||
|
return createAppender(config);
|
||
|
}
|
||
|
|
||
|
function shutdown(done) {
|
||
|
var toBeClosed = servers.length;
|
||
|
debug("multiprocess shutdown with ", toBeClosed, " servers to close.");
|
||
|
servers.forEach(function(server) {
|
||
|
server.close(function() {
|
||
|
debug("server closed.");
|
||
|
toBeClosed--;
|
||
|
if (toBeClosed < 1) {
|
||
|
debug("all servers closed.");
|
||
|
done();
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
exports.appender = createAppender;
|
||
|
exports.configure = configure;
|
||
|
exports.shutdown = shutdown;
|