diff --git a/lib/winston/transports/file.js b/lib/winston/transports/file.js index 96a38ca9f..6797580ad 100644 --- a/lib/winston/transports/file.js +++ b/lib/winston/transports/file.js @@ -365,6 +365,13 @@ File.prototype.close = function () { File.prototype.flush = function () { var self = this; + // If nothing to flush, there will be no "flush" event from native stream + // Thus, the "open" event will never be fired (see _createStream.createAndFlush function) + // That means, self.opening will never set to false and no logs will be written to disk + if (!this._buffer.length) { + return self.emit('flush'); + } + // // Iterate over the `_buffer` of enqueued messaged // and then write them to the newly created stream. @@ -434,6 +441,11 @@ File.prototype._createStream = function () { // and thus can emit the `open` event. // self.once('flush', function () { + // Because "flush" event is based on native stream "drain" event, + // logs could be written inbetween "self.flush()" and here + // Therefore, we need to flush again to make sure everything is flushed + self.flush(); + self.opening = false; self.emit('open', fullname); }); diff --git a/test/transports/file-open-test.js b/test/transports/file-open-test.js new file mode 100644 index 000000000..7fd4ed638 --- /dev/null +++ b/test/transports/file-open-test.js @@ -0,0 +1,61 @@ +/* + * file-open-test.js: Tests for File transport "open" event + * + * (C) 2014 William Wong + * MIT LICENSE + * + */ + +!function (assert, fs, os, path, vows, winston) { + 'use strict'; + + vows.describe('winston/transports/file').addBatch({ + 'An instance of the File Transport': { + topic: function () { + var callback = this.callback.bind(this), + logPath = path.resolve(__dirname, '../fixtures/logs/file-open-test.log'); + + try { + fs.unlinkSync(logPath); + } catch (ex) { + if (ex && ex.code !== 'ENOENT') { return callback(ex); } + } + + var fileTransport = new (winston.transports.File)({ + filename: logPath + }), + logger = new (winston.Logger)({ + transports: [fileTransport] + }), + timeline = {}; + + fileTransport.open(function () { + timeline.open = Date.now(); + + setTimeout(function () { + logger.info('Hello, World!', function () { + timeline.logged = Date.now(); + }); + }, 100); + + setTimeout(function () { + callback(null, timeline); + }, 1000); + }); + }, + 'should fire "open" event': function (results) { + assert.isTrue(!!results.open); + }, + 'should fire "logged" event': function (results) { + assert.isTrue(!!results.logged); + } + } + }).export(module); +}( + require('assert'), + require('fs'), + require('os'), + require('path'), + require('vows'), + require('../../lib/winston') +); \ No newline at end of file diff --git a/test/transports/file-stress-test.js b/test/transports/file-stress-test.js new file mode 100644 index 000000000..519b12c02 --- /dev/null +++ b/test/transports/file-stress-test.js @@ -0,0 +1,76 @@ +/* + * file-stress-test.js: Tests for stressing File transport + * + * (C) 2014 William Wong + * MIT LICENSE + * + */ + +!function (assert, fs, os, path, vows, winston) { + 'use strict'; + + vows.describe('winston/transports/file').addBatch({ + 'A stressed instance of the File Transport': { + topic: function () { + var callback = this.callback.bind(this), + logPath = path.resolve(__dirname, '../fixtures/logs/file-stress-test.log'); + + try { + fs.unlinkSync(logPath); + } catch (ex) { + if (ex && ex.code !== 'ENOENT') { return callback(ex); } + } + + var fileTransport = new (winston.transports.File)({ + filename: logPath + }), + logger = new (winston.Logger)({ + transports: [fileTransport] + }); + + fileTransport.on('open', function () { + setTimeout(function () { + clearInterval(interval); + + logger.query({ order: 'asc' }, function (err, results) { + callback(null, results); + }); + }, 100); + }); + + var logIndex = 0, + interval = setInterval(function () { + logger.info(++logIndex); + stress(200); + }, 0); + + logger.info(++logIndex); + stress(200); + + function stress(duration) { + var startTime = Date.now(); + + while (Date.now() - startTime < duration) { + Math.sqrt(Math.PI); + } + } + }, + 'should not skip any log lines': function (results) { + var testIndex = 0; + + results.file.forEach(function (log) { + if (+log.message !== ++testIndex) { + throw new Error('Number skipped'); + } + }); + } + } + }).export(module); +}( + require('assert'), + require('fs'), + require('os'), + require('path'), + require('vows'), + require('../../lib/winston') +); \ No newline at end of file