From 46d2be46422963f38a1c45ec11735b48a07ce8e3 Mon Sep 17 00:00:00 2001 From: Paul Milham Date: Mon, 28 Dec 2015 14:01:11 -0700 Subject: [PATCH] rotating-file: auto rotate file on startup if needed Fixes #239 --- lib/bunyan.js | 67 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/lib/bunyan.js b/lib/bunyan.js index 87cb911..f454f43 100644 --- a/lib/bunyan.js +++ b/lib/bunyan.js @@ -1168,8 +1168,7 @@ if (mv) { RotatingFileStream = function RotatingFileStream(options) { this.path = options.path; - this.stream = fs.createWriteStream(this.path, - {flags: 'a', encoding: 'utf8'}); + this.count = (options.count == null ? 10 : options.count); assert.equal(typeof (this.count), 'number', format('rotating-file stream "count" is not a number: %j (%s) in %j', @@ -1206,6 +1205,22 @@ RotatingFileStream = function RotatingFileStream(options) { this.periodScope = 'd'; } + var lastModified = null; + try { + var fileInfo = fs.statSync(this.path); + lastModified = fileInfo.mtime.getTime(); + } + catch (err) { + // file doesn't exist + } + var rotateAfterOpen = false; + if (lastModified) { + var lastRotTime = this._calcRotTime(0); + if (lastModified < lastRotTime) { + rotateAfterOpen = true; + } + } + // TODO: template support for backup files // template: // default is %P.%n @@ -1222,15 +1237,21 @@ RotatingFileStream = function RotatingFileStream(options) { // prior art? Want to avoid ':' in // filenames (illegal on Windows for one). + this.stream = fs.createWriteStream(this.path, + {flags: 'a', encoding: 'utf8'}); + this.rotQueue = []; this.rotating = false; + if (rotateAfterOpen) { + this.rotate(); + } this._setupNextRot(); } util.inherits(RotatingFileStream, EventEmitter); RotatingFileStream.prototype._setupNextRot = function () { - this.rotAt = this._nextRotTime(); + this.rotAt = this._calcRotTime(1); this._setRotationTimer(); } @@ -1251,10 +1272,11 @@ RotatingFileStream.prototype._setRotationTimer = function () { } } -RotatingFileStream.prototype._nextRotTime = function _nextRotTime(first) { +RotatingFileStream.prototype._calcRotTime = +function _calcRotTime(periodOffset) { var _DEBUG = false; if (_DEBUG) - console.log('-- _nextRotTime: %s%s', this.periodNum, this.periodScope); + console.log('-- _calcRotTime: %s%s', this.periodNum, this.periodScope); var d = new Date(); if (_DEBUG) console.log(' now local: %s', d); @@ -1264,54 +1286,65 @@ RotatingFileStream.prototype._nextRotTime = function _nextRotTime(first) { case 'ms': // Hidden millisecond period for debugging. if (this.rotAt) { - rotAt = this.rotAt + this.periodNum; + rotAt = this.rotAt + this.periodNum * periodOffset; } else { - rotAt = Date.now() + this.periodNum; + rotAt = Date.now() + this.periodNum * periodOffset; } break; case 'h': if (this.rotAt) { - rotAt = this.rotAt + this.periodNum * 60 * 60 * 1000; + rotAt = this.rotAt + this.periodNum * 60 * 60 * 1000 * periodOffset; } else { // First time: top of the next hour. rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), - d.getUTCDate(), d.getUTCHours() + 1); + d.getUTCDate(), d.getUTCHours() + periodOffset); } break; case 'd': if (this.rotAt) { - rotAt = this.rotAt + this.periodNum * 24 * 60 * 60 * 1000; + rotAt = this.rotAt + this.periodNum * 24 * 60 * 60 * 1000 + * periodOffset; } else { // First time: start of tomorrow (i.e. at the coming midnight) UTC. rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), - d.getUTCDate() + 1); + d.getUTCDate() + periodOffset); } break; case 'w': // Currently, always on Sunday morning at 00:00:00 (UTC). if (this.rotAt) { - rotAt = this.rotAt + this.periodNum * 7 * 24 * 60 * 60 * 1000; + rotAt = this.rotAt + this.periodNum * 7 * 24 * 60 * 60 * 1000 + * periodOffset; } else { // First time: this coming Sunday. + var dayOffset = (7 - d.getUTCDay()); + if (periodOffset < 1) { + dayOffset = -d.getUTCDay(); + } + if (periodOffset > 1 || periodOffset < -1) { + dayOffset += 7 * periodOffset; + } rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), - d.getUTCDate() + (7 - d.getUTCDay())); + d.getUTCDate() + dayOffset); } break; case 'm': if (this.rotAt) { rotAt = Date.UTC(d.getUTCFullYear(), - d.getUTCMonth() + this.periodNum, 1); + d.getUTCMonth() + this.periodNum * periodOffset, 1); } else { // First time: the start of the next month. - rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1); + rotAt = Date.UTC(d.getUTCFullYear(), + d.getUTCMonth() + periodOffset, 1); } break; case 'y': if (this.rotAt) { - rotAt = Date.UTC(d.getUTCFullYear() + this.periodNum, 0, 1); + rotAt = Date.UTC(d.getUTCFullYear() + this.periodNum * periodOffset, + 0, 1); } else { // First time: the start of the next year. - rotAt = Date.UTC(d.getUTCFullYear() + 1, 0, 1); + rotAt = Date.UTC(d.getUTCFullYear() + periodOffset, 0, 1); } break; default: