A node.js extension for systemd

A few weeks ago Pantheon sponsored a code sprint at their offices in San Francisco, the purpose of which was to extend support for the systemd journal. In attendance were the two maintainers of systemd: Lennart Poettering and Kay Sievers. We worked on creating native language bindings, and I headed up the JavaScript work - specifically creating a library that would allow asyncronous logging directly to the journal from node.js.

You can now do this in your application code:

var journald = require('journald').Log;
journald.log({
    MESSAGE: 'Hello world',
    ARG1: '<useful string here>',
    ARG2: '<another useful string here>',
    ARG3: '<yet another useful string here>'
 });

Systemd is the new default system manager in many major distributions. It handles starting and stopping services, provides socket activation capabilities, control over processes using cgroups, and much more. One of the new features it provides is the journal - a replacement for syslog that brings logging into the 21st century. There are many improvements over syslog, but one of the most obvious is the use of structured log entries, providing key/value fields instead of a string blob that often needs to be parsed again using regexes.

To add an entry to the journal from JavaScript, we need to break out of the interpreted world and call a C function that’s provided by the systemd API: sd_journal_sendv(). To do this, we create a V8 extension in C++, and implement the required functions to expose our new calls to JavaScript.

V8 provides neatly wrapped implementations of all JavaScript language components, so there’s a C++ version of the Function object, and a Number object, and every other piece you may require. You can easily build your JavaScript code from within C++, and return it back to JavaScript land for execution - an experience that feels something like being a backstage director at an elaborate costumed production.

The second part of the node.js API is the ability to hand off tasks to libuv, so that the main event loop doesn’t become blocked waiting for I/O. To do this, the uv_queue_work() function must be called with data about the job, a function to call to do the work, and a function to call once it’s completed. Since the V8 API isn’t available in the libuv worker threads, this part requires pure C++/C code.

The journald package is now available on npm, and it comes with a Winston transport plugin, allowing you to use Winston’s logging API to send to multiple places at once. The source is available on Github.

I found the following resources useful:

Commenting on this Blog post is closed.