| const cluster = require('cluster'); | |
| const debug = require('debug')('log4js:clustering'); | |
| const LoggingEvent = require('./LoggingEvent'); | |
| const configuration = require('./configuration'); | |
| const listeners = []; | |
| let disabled = false; | |
| let pm2 = false; | |
| let pm2InstanceVar = 'NODE_APP_INSTANCE'; | |
| const isPM2Master = () => pm2 && process.env[pm2InstanceVar] === '0'; | |
| const isMaster = () => disabled || cluster.isMaster || isPM2Master(); | |
| const sendToListeners = (logEvent) => { | |
| listeners.forEach(l => l(logEvent)); | |
| }; | |
| // in a multi-process node environment, worker loggers will use | |
| // process.send | |
| const receiver = (worker, message) => { | |
| // prior to node v6, the worker parameter was not passed (args were message, handle) | |
| debug('cluster message received from worker ', worker, ': ', message); | |
| if (worker.topic && worker.data) { | |
| message = worker; | |
| worker = undefined; | |
| } | |
| if (message && message.topic && message.topic === 'log4js:message') { | |
| debug('received message: ', message.data); | |
| const logEvent = LoggingEvent.deserialise(message.data); | |
| sendToListeners(logEvent); | |
| } | |
| }; | |
| configuration.addListener((config) => { | |
| // clear out the listeners, because configure has been called. | |
| listeners.length = 0; | |
| disabled = config.disableClustering; | |
| pm2 = config.pm2; | |
| pm2InstanceVar = config.pm2InstanceVar || 'NODE_APP_INSTANCE'; | |
| debug(`clustering disabled ? ${disabled}`); | |
| debug(`cluster.isMaster ? ${cluster.isMaster}`); | |
| debug(`pm2 enabled ? ${pm2}`); | |
| debug(`pm2InstanceVar = ${pm2InstanceVar}`); | |
| debug(`process.env[${pm2InstanceVar}] = ${process.env[pm2InstanceVar]}`); | |
| // just in case configure is called after shutdown | |
| if (pm2) { | |
| process.removeListener('message', receiver); | |
| } | |
| if (cluster.removeListener) { | |
| cluster.removeListener('message', receiver); | |
| } | |
| if (config.disableClustering) { | |
| debug('Not listening for cluster messages, because clustering disabled.'); | |
| } else if (isPM2Master()) { | |
| // PM2 cluster support | |
| // PM2 runs everything as workers - install pm2-intercom for this to work. | |
| // we only want one of the app instances to write logs | |
| debug('listening for PM2 broadcast messages'); | |
| process.on('message', receiver); | |
| } else if (cluster.isMaster) { | |
| debug('listening for cluster messages'); | |
| cluster.on('message', receiver); | |
| } else { | |
| debug('not listening for messages, because we are not a master process'); | |
| } | |
| }); | |
| module.exports = { | |
| onlyOnMaster: (fn, notMaster) => (isMaster() ? fn() : notMaster), | |
| isMaster: isMaster, | |
| send: (msg) => { | |
| if (isMaster()) { | |
| sendToListeners(msg); | |
| } else { | |
| if (!pm2) { | |
| msg.cluster = { | |
| workerId: cluster.worker.id, | |
| worker: process.pid | |
| }; | |
| } | |
| process.send({ topic: 'log4js:message', data: msg.serialise() }); | |
| } | |
| }, | |
| onMessage: (listener) => { | |
| listeners.push(listener); | |
| } | |
| }; |