Writing to the syslog with Winston
This article was originally published in my blog (affectionately referred to as blargh) on . The original blog no longer exists as I've migrated everything to this wiki.
The original URL of this post was at https://tmont.com/blargh/2013/12/writing-to-the-syslog-with-winston. Hopefully that link redirects back to this page.
Update: this code is now in its own GitHub repository.
Many log aggregators (such as Papertrail or Loggly) have the ability to parse data from the syslog. This is often more convenient than writing to a file, handling rotation of said log file, handling archival of said rotated log file, and a myriad of other annoyances. Plus, many other system programs (ssh, cron, etc.) already log stuff to the syslog, so most things are already aggregated.
I use Winston as my logging library
for Node. It works pretty well inasmuch as it lets you log stuff. Winston exposes a
Transport
object, which is an interface to a logging destination (a file,
the console, a webhook, etc.). You can use this to log to the syslog.
Note that there are other modules for Winston that expose a syslog transport, but
they all made me nervous, in that they weren't tested, and after glancing through
the code, I wasn't convinced they were doing proper socket management. And the last
thing I wanted was my logging library to create hundreds of undisposed file descriptors.
So I decided to use node-posix and just
use the OS to write to the syslog rather than UDP. Plus syslogd
doesn't
have datagram support enabled by default, so you need to tweak the configuration to make
it accept UDP packets, and I don't know enough about syslog to feel confident in messing
with the configuration. And also I didn't feel like spending an hour learning about it.
Because I'm weak and stupid.
Anyway, here's some sample code to write to the syslog using the OS's POSIX functions.
var winston = require('winston'),
util = require('util'),
posix = require('posix');
function SyslogTransport(options) {
options = options || {};
winston.Transport.call(this, options);
this.id = options.id || process.title;
this.facility = options.facility || 'local0';
this.showPid = !!options.showPid;
}
util.inherits(SyslogTransport, winston.Transport);
util._extend(SyslogTransport.prototype, {
name: 'syslog',
log: function(level, msg, meta, callback) {
if (this.silent) {
callback(null, true);
return;
}
if (level === 'error') {
level = 'err';
} else if (level === 'warn') {
level = 'warning';
}
var message = '[' + level + '] ' + msg;
if (typeof(meta) === 'string') {
message += ' ' + meta;
} else if (meta && typeof(meta) === 'object' && Object.keys(meta).length > 0) {
message += ' ' + util.inspect(meta, false, null, false);
}
message = message.replace(/\u001b\[(\d+(;\d+)*)?m/g, '');
var options = {
cons: true,
pid: this.showPid
};
posix.openlog(this.id, options, this.facility);
posix.syslog(level, message);
posix.closelog();
callback(null, true);
}
});
module.exports = SyslogTransport;
And you could use it like so:
var transport = new SyslogTransport({
level: 'debug',
id: 'hello syslog',
facility: 'user',
showPid: true
});
var log = new winston.Logger({
level: 'debug',
transports: [ transport ]
});
log.info('hello world');
And then if you run tail /var/log/syslog
(/var/log/messages
on OS X, I think), you should see something like this:
Dec 23 12:01:50 mesia hello syslog[17605]: [info] hello world