A simple Node.js log server using ZeroMQ
This post walks through building a simple Node.js log server that uses ZeroMQ to accept messages. Such a server could then be shared by multiple applications (or modules within a single application).
In this example the log server is launched as a stand alone process, but in practice you could launch it as a thread from a parent application using require('child_process').fork()
.
Installing ZeroMQ
Before you can use ZeroMQ with node you need to install its C header files and Node.js bindings.
If you are running Debian Wheezy (the stable release at the time of writing) then you will need to add the wheezy-backports repository first:
echo 'deb http://http.debian.net/debian wheezy-backports main' > /etc/apt/sources.list.d/wheezy-backports.list
aptitude -q update
Assuming that you run Debian, libzmq3-dev is the package you are looking for:
aptitude -q install libzmq3-dev
Now you can install the bindings:
npm install zmq
The Logger
This is the code for logger.js
. The logger accepts messages into its own internal queue and then a worker periodically goes through the queue and gets the messages out.
"use strict";
const zmq = require("zmq");
const socket = zmq.socket("pull");
// Instead of a Unix socket you can use 'tcp://...' etc.
const socketAddress = "ipc://" + __dirname + "/logger.socket";
// internal message queue
const messages = [];
// function to log the message
function log(message) {
// in practice this can be much more fancy
console.log(message);
}
// message queue worker loop
(function loop() {
setTimeout(function () {
while (messages.length) {
log(messages.shift());
}
loop();
}, 1000);
})();
// multi-part message parts go in separate arguments
socket.on("message", function (level, data) {
level = level.toString();
data = data.toString();
messages.push({
level: level,
data: data,
time: new Date().getTime(),
});
});
// Once everything is ready start listening for messages
socket.bind(socketAddress);
console.log("Logger is ready");
The App
This is the code for app.js – nothing fancy here.
"use strict";
const zmq = require("zmq");
const socket = zmq.socket("push");
// Instead of a Unix socket you can use 'tcp://...' etc.
const socketAddress = "ipc://" + __dirname + "/logger.socket";
socket.connect(socketAddress);
console.log("App is ready");
// send some multi-part messages
socket.send(["info", "Message #1"]);
socket.send(["info", "Message #2"]);
socket.send(["info", "Message #3"]);
Testing
Launch the two scripts in separate terminals:
$ node app.js
App is ready
$ node logger.js
Logger is ready
{ level: 'info', data: 'Message #1', time: 1424348906861 }
{ level: 'info', data: 'Message #2', time: 1424348906861 }
{ level: 'info', data: 'Message #3', time: 1424348906861 }
Looks good. :)
Further reading
- Examples from the Node.js bindings package
- A very nice series on Node.js + ZeroMQ: Part 1, Part 2, Part 3 and Part 4
- The excellent ZeroMQ documentation
Disclaimer
The information above is accurate to my knowledge, however I provide no guarantees to this effect and consequently accept no liability whatsoever for any bad things that may happen as a result of the reader using this information in practice. Use at your own risk. Oh, and backup your data while you’re at it.