const { test } = require('tap'); const cluster = require('cluster'); const debug = require('debug')('log4js:pm2-test'); // PM2 runs everything as workers // - no master in the cluster (PM2 acts as master itself) // - we will simulate that here (avoid having to include PM2 as a dev dep) if (cluster.isMaster) { // create two worker forks // PASS IN NODE_APP_INSTANCE HERE const appEvents = {}; ['0', '1'].forEach((i) => { cluster.fork({ NODE_APP_INSTANCE: i }); }); const messageHandler = (worker, msg) => { if (worker.type || worker.topic) { msg = worker; } if (msg.type === 'testing') { debug( `Received testing message from ${msg.instance} with events ${msg.events}` ); appEvents[msg.instance] = msg.events; } // we have to do the re-broadcasting that the pm2-intercom module would do. if (msg.topic === 'log4js:message') { debug(`Received log message ${msg}`); for (const id in cluster.workers) { cluster.workers[id].send(msg); } } }; cluster.on('message', messageHandler); let count = 0; cluster.on('exit', () => { count += 1; if (count === 2) { // wait for any IPC messages still to come, because it seems they are slooooow. setTimeout(() => { test('PM2 Support', (batch) => { batch.test('should not get any events when turned off', (t) => { t.notOk( appEvents['0'].filter( (e) => e && e.data[0].indexOf('will not be logged') > -1 ).length ); t.notOk( appEvents['1'].filter( (e) => e && e.data[0].indexOf('will not be logged') > -1 ).length ); t.end(); }); batch.test('should get events on app instance 0', (t) => { t.equal(appEvents['0'].length, 2); t.equal(appEvents['0'][0].data[0], 'this should now get logged'); t.equal(appEvents['0'][1].data[0], 'this should now get logged'); t.end(); }); batch.test('should not get events on app instance 1', (t) => { t.equal(appEvents['1'].length, 0); t.end(); }); batch.end(); cluster.removeListener('message', messageHandler); }); }, 1000); } }); } else { const recorder = require('../../lib/appenders/recording'); const log4js = require('../../lib/log4js'); log4js.configure({ appenders: { out: { type: 'recording' } }, categories: { default: { appenders: ['out'], level: 'info' } }, }); const logger = log4js.getLogger('test'); logger.info( 'this is a test, but without enabling PM2 support it will not be logged' ); // IPC messages can take a while to get through to start with. setTimeout(() => { log4js.shutdown(() => { log4js.configure({ appenders: { out: { type: 'recording' } }, categories: { default: { appenders: ['out'], level: 'info' } }, pm2: true, }); const anotherLogger = log4js.getLogger('test'); setTimeout(() => { anotherLogger.info('this should now get logged'); }, 1000); // if we're the pm2-master we should wait for the other process to send its log messages setTimeout(() => { log4js.shutdown(() => { const events = recorder.replay(); debug( `Sending test events ${events} from ${process.env.NODE_APP_INSTANCE}` ); process.send( { type: 'testing', instance: process.env.NODE_APP_INSTANCE, events, }, () => { setTimeout(() => { cluster.worker.disconnect(); }, 1000); } ); }); }, 3000); }); }, 2000); }