Writing to the syslog with Winston[source]
xml
<glacius:metadata> | |
<title>Writing to the syslog with Winston</title> | |
<description>NodeJS logging with Winston and syslog</description> | |
<category>Legacy blog posts</category> | |
<category>Programming</category> | |
<category>JavaScript</category> | |
<category>Node.js</category> | |
</glacius:metadata> | |
<glacius:macro name="legacy blargh banner"> | |
<properties> | |
<originalUrl>https://tmont.com/blargh/2013/12/writing-to-the-syslog-with-winston</originalUrl> | |
<originalDate>2013-12-24T04:05:46.000Z</originalDate> | |
</properties> | |
</glacius:macro> | |
<p> | |
<strong>Update:</strong> this code is now in its own | |
<a href="https://github.com/tmont/winston-syslog">GitHub repository</a>. | |
</p> | |
<hr /> | |
<p> | |
Many log aggregators (such as <a href="https://papertrailapp.com/">Papertrail</a> | |
or <a href="https://www.loggly.com/">Loggly</a>) 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. | |
</p> | |
<p> | |
I use <a href="https://github.com/flatiron/winston">Winston</a> as my logging library | |
for Node. It works pretty well inasmuch as it lets you log stuff. Winston exposes a | |
<code>Transport</code> 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. | |
</p> | |
<p> | |
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 <a href="https://github.com/melor/node-posix">node-posix</a> and just | |
use the OS to write to the syslog rather than UDP. Plus <code>syslogd</code> 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. | |
</p> | |
<p> | |
Anyway, here's some sample code to write to the syslog using the OS's POSIX functions. | |
</p> | |
<glacius:code lang="javascript"><![CDATA[ | |
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; | |
]]></glacius:code> | |
<p> | |
And you could use it like so: | |
</p> | |
<glacius:code lang="javascript"><![CDATA[ | |
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'); | |
]]></glacius:code> | |
<p> | |
And then if you run <code>tail /var/log/syslog</code> (<code>/var/log/messages</code> | |
on OS X, I think), you should see something like this: | |
</p> | |
<glacius:code lang="plaintext"><![CDATA[ | |
Dec 23 12:01:50 mesia hello syslog[17605]: [info] hello world | |
]]></glacius:code> | |