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.

/*jshint node:true*/
'use strict';

var zmq = require('zmq');
var socket = zmq.socket('pull');

// Instead of a Unix socket you can use 'tcp://...' etc.
var socketAddress = 'ipc://' + __dirname + '/logger.socket';

// internal message queue
var 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.

/*jshint node:true*/
'use strict';

var zmq = require('zmq');
var socket = zmq.socket('push');

// Instead of a Unix socket you can use 'tcp://...' etc.
var 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.