cluster-to-winston is an extension to winston for sharing primary Logger instances among multiple worker processes in a cluster.
It can be considered as complete rewrite of the winston-cluster module with another API.
const winston = require ('winston')
require ('cluster-to-winston') // no typo here
const logger = winston.createLogger ({
transports: //... for the primary process: e. g. DailyRotateFile
format: //... for both primary and workers
})
.enableCluster ({ // all the necessary setup is done here
// key : 'WorkerProcessLogMessage', // change this in case of collision
// listenerName : 'onWorkerProcessLogMessage', // same, for a `Logger` property
// listen : true, // set `false` to install listeners manually
})
/* // application code:
if (cluster.isPrimary) {
cluster.fork ()
// using `logger` in the primary process
}
else {
// using apparently the same `logger` in workers
}
*/Calling require ('cluster-to-winston') augments the previously loaded Logger class with a new method: .enableCluster () that is supposed to be called right after the initialization and returns the Logger instance to support chaining.
What .enableCluster () does, depends on the context:
- called in the primary process, it
- wraps
this.formatto avoid reformattinginfoobjects received from workers; - defines
this.onWorkerProcessLogMessage ()that routes messages containing the magicWorkerProcessLogMessage(name configurable) property to this logger as info objects; - registers this method as a handler for
cluster' s'message'event (unless prohibited by settinglisten: falsefor advanced use);
- wraps
- in a worker process, it forcibly replaces all
transportswith a single, that stores the finalMESSAGEas the magicWorkerProcessLogMessageand publishes the info object as a'message'event.
In the sample code above, the logger looks created once, before branching and forking. But because of the way cluster.fork and require work, effectively, .enableCluster () is called with final cluster.isWorker values, so Logger instances will be properly initialized in each process. And, unlike in winston-cluster, the logger set up at application start can be then used everywhere, in a transparent way. Moreover, formatting is not postponed, so Timestamps in workers are applied immediately.
IPC message bodies a plain (JSON) strings, so Symbols cannot be delivered from worker to primary process. This is the reason why the MESSAGE from winston's triple-beam had to be backed by a workaround magic string.
Sure, when using cluster IPC may be used for a lot of things aside logging, that poses some risk of data interference. The logger.onWorkerProcessLogMessage method processes only objects with WorkerProcessLogMessage field ignoring all other, so it can act as one of multiple simultaneous message handlers. But application developers are free to bypass the automatic handler setting with the listen: false option and to build custom routers based on the provided one.