3 var cluster = require('cluster');
4 var log4js = require('../log4js');
7 * Takes a loggingEvent object, returns string representation of it.
9 function serializeLoggingEvent(loggingEvent) {
10 // JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
11 // The following allows us to serialize errors correctly.
12 for (var i = 0; i < loggingEvent.data.length; i++) {
13 var item = loggingEvent.data[i];
14 // Validate that we really are in this case
15 if (item && item.stack && JSON.stringify(item) === '{}') {
16 loggingEvent.data[i] = {stack : item.stack};
19 return JSON.stringify(loggingEvent);
23 * Takes a string, returns an object with
24 * the correct log properties.
26 * This method has been "borrowed" from the `multiprocess` appender
28 * (https://github.com/nomiddlename/log4js-node/blob/master/lib/appenders/multiprocess.js)
30 * Apparently, node.js serializes everything to strings when using `process.send()`,
31 * so we need smart deserialization that will recreate log date and level for further
32 * processing by log4js internals.
34 function deserializeLoggingEvent(loggingEventString) {
40 loggingEvent = JSON.parse(loggingEventString);
41 loggingEvent.startTime = new Date(loggingEvent.startTime);
42 loggingEvent.level = log4js.levels.toLevel(loggingEvent.level.levelStr);
43 // Unwrap serialized errors
44 for (var i = 0; i < loggingEvent.data.length; i++) {
45 var item = loggingEvent.data[i];
46 if (item && item.stack) {
47 loggingEvent.data[i] = item.stack;
53 // JSON.parse failed, just log the contents probably a naughty.
55 startTime: new Date(),
56 categoryName: 'log4js',
57 level: log4js.levels.ERROR,
58 data: [ 'Unable to parse log:', loggingEventString ]
65 * Creates an appender.
67 * If the current process is a master (`cluster.isMaster`), then this will be a "master appender".
68 * Otherwise this will be a worker appender, that just sends loggingEvents to the master process.
70 * If you are using this method directly, make sure to provide it with `config.actualAppenders`
71 * array of actual appender instances.
73 * Or better use `configure(config, options)`
75 function createAppender(config) {
77 if (cluster.isMaster) {
79 var masterAppender = function(loggingEvent) {
81 if (config.actualAppenders) {
82 var size = config.actualAppenders.length;
83 for(var i = 0; i < size; i++) {
85 !config.appenders[i].category ||
86 config.appenders[i].category === loggingEvent.categoryName
88 // Relying on the index is not a good practice but otherwise
89 // the change would have been bigger.
90 config.actualAppenders[i](loggingEvent);
96 // Listen on new workers
97 cluster.on('fork', function(worker) {
99 worker.on('message', function(message) {
100 if (message.type && message.type === '::log-message') {
101 var loggingEvent = deserializeLoggingEvent(message.event);
103 // Adding PID metadata
104 loggingEvent.pid = worker.process.pid;
105 loggingEvent.cluster = {
107 worker: worker.process.pid,
111 masterAppender(loggingEvent);
117 return masterAppender;
121 return function(loggingEvent) {
122 // If inside the worker process, then send the logger event to master.
123 if (cluster.isWorker) {
124 // console.log("worker " + cluster.worker.id + " is sending message");
125 process.send({ type: '::log-message', event: serializeLoggingEvent(loggingEvent)});
131 function configure(config, options) {
133 if (config.appenders && cluster.isMaster) {
135 var size = config.appenders.length;
136 config.actualAppenders = new Array(size);
138 for(var i = 0; i < size; i++) {
140 log4js.loadAppender(config.appenders[i].type);
141 config.actualAppenders[i] = log4js.appenderMakers[config.appenders[i].type](
149 return createAppender(config);
152 exports.appender = createAppender;
153 exports.configure = configure;