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

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.