I realized yesterday that most of the logging libraries for Node.js seem to use blocking/synchronous calls. Logging is normally an I/O operation, and with Node.js we are supposed to use non-blocking/asynchronous I/O everywhere possible.
console.log
(process.stdout.write) has been a synchronous operation since Node.js 0.6, TMK
It occurred to me, for servers that do a lot of logging statements, to use blocking I/O for these might be a big performance penalty.
I ran "logging" statements with Redis, fs, Bunyan and Winston, and I get these results on a Macbook Pro:
redis: 16ms
fs-write-stream: 90ms
bunyan: 414ms
winston: 491ms
so it seems that just using a Redis client to send out a message over network I/O is the fastest way to get data out of the Node.js event loop.
Here are the tests:
// fs
var fs = require('fs');
// redis
var redis = require('redis');
var client = redis.createClient(); //connect to local redis db
// bunyan
var bunyan = require('bunyan');
var bunyanLogger = bunyan.createLogger({
name: 'benchmark',
streams: [
{
level: 'info',
path: '../bunyan_log.txt' // log ERROR and above to this file
}
]
});
// winston
var winston = require('winston');
var winstonLogger = new (winston.Logger)({
transports: [
new (winston.transports.File)({ filename: '../winston_log.txt' })
]
});
////////////////////////////////////////////////////////////////////////////
console.time('redis-time');
for (var i = 0; i < 12000; i++) {
client.set('key' + i, 'value' + i + 'aegeggaiojigfeijoagreoiraegioagrijogerawijogerwijogerijoegwoijegwijoegwjio');
}
console.timeEnd('redis-time');
////////////////////////////////////////////////////////////////////
console.time('fs-write-stream-time');
var wstream = fs.createWriteStream('../fs_log.txt');
for (var i = 0; i < 12000; i++) {
wstream.write('key' + i + 'value' + i + 'aegeggaiojigfeijoagreoiraegioagrijogerawijogerwijogerijoegwoijegwijoegwjio' + '\n');
}
wstream.end();
console.timeEnd('fs-write-stream-time');
///////////////////////////////////////////////////////////////
console.time('bunyan-time');
for (var i = 0; i < 12000; i++) {
bunyanLogger.info('bunyan' + i);
}
console.timeEnd('bunyan-time');
/////////////////////////////////////////////////////////////
console.time('winston-time');
for (var i = 0; i < 12000; i++) {
winstonLogger.info('bunyan' + i);
}
console.timeEnd('winston-time');
////////////////////////////////////////////////////////////////
am I on to something or do I have something wrong?
Ideally it seems with Node.js servers you would use Redis to send logging requests to a logging server somewhere, which would process a queue.