rotating-file: auto rotate file on startup if needed

Fixes #239
This commit is contained in:
Paul Milham 2015-12-28 14:01:11 -07:00 committed by Trent Mick
parent bb1ab77c3e
commit 46d2be4642

View file

@ -1168,8 +1168,7 @@ if (mv) {
RotatingFileStream = function RotatingFileStream(options) { RotatingFileStream = function RotatingFileStream(options) {
this.path = options.path; this.path = options.path;
this.stream = fs.createWriteStream(this.path,
{flags: 'a', encoding: 'utf8'});
this.count = (options.count == null ? 10 : options.count); this.count = (options.count == null ? 10 : options.count);
assert.equal(typeof (this.count), 'number', assert.equal(typeof (this.count), 'number',
format('rotating-file stream "count" is not a number: %j (%s) in %j', format('rotating-file stream "count" is not a number: %j (%s) in %j',
@ -1206,6 +1205,22 @@ RotatingFileStream = function RotatingFileStream(options) {
this.periodScope = 'd'; 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 // TODO: template support for backup files
// template: <path to which to rotate> // template: <path to which to rotate>
// default is %P.%n // default is %P.%n
@ -1222,15 +1237,21 @@ RotatingFileStream = function RotatingFileStream(options) {
// prior art? Want to avoid ':' in // prior art? Want to avoid ':' in
// filenames (illegal on Windows for one). // filenames (illegal on Windows for one).
this.stream = fs.createWriteStream(this.path,
{flags: 'a', encoding: 'utf8'});
this.rotQueue = []; this.rotQueue = [];
this.rotating = false; this.rotating = false;
if (rotateAfterOpen) {
this.rotate();
}
this._setupNextRot(); this._setupNextRot();
} }
util.inherits(RotatingFileStream, EventEmitter); util.inherits(RotatingFileStream, EventEmitter);
RotatingFileStream.prototype._setupNextRot = function () { RotatingFileStream.prototype._setupNextRot = function () {
this.rotAt = this._nextRotTime(); this.rotAt = this._calcRotTime(1);
this._setRotationTimer(); 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; var _DEBUG = false;
if (_DEBUG) if (_DEBUG)
console.log('-- _nextRotTime: %s%s', this.periodNum, this.periodScope); console.log('-- _calcRotTime: %s%s', this.periodNum, this.periodScope);
var d = new Date(); var d = new Date();
if (_DEBUG) console.log(' now local: %s', d); if (_DEBUG) console.log(' now local: %s', d);
@ -1264,54 +1286,65 @@ RotatingFileStream.prototype._nextRotTime = function _nextRotTime(first) {
case 'ms': case 'ms':
// Hidden millisecond period for debugging. // Hidden millisecond period for debugging.
if (this.rotAt) { if (this.rotAt) {
rotAt = this.rotAt + this.periodNum; rotAt = this.rotAt + this.periodNum * periodOffset;
} else { } else {
rotAt = Date.now() + this.periodNum; rotAt = Date.now() + this.periodNum * periodOffset;
} }
break; break;
case 'h': case 'h':
if (this.rotAt) { if (this.rotAt) {
rotAt = this.rotAt + this.periodNum * 60 * 60 * 1000; rotAt = this.rotAt + this.periodNum * 60 * 60 * 1000 * periodOffset;
} else { } else {
// First time: top of the next hour. // First time: top of the next hour.
rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(),
d.getUTCDate(), d.getUTCHours() + 1); d.getUTCDate(), d.getUTCHours() + periodOffset);
} }
break; break;
case 'd': case 'd':
if (this.rotAt) { if (this.rotAt) {
rotAt = this.rotAt + this.periodNum * 24 * 60 * 60 * 1000; rotAt = this.rotAt + this.periodNum * 24 * 60 * 60 * 1000
* periodOffset;
} else { } else {
// First time: start of tomorrow (i.e. at the coming midnight) UTC. // First time: start of tomorrow (i.e. at the coming midnight) UTC.
rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(),
d.getUTCDate() + 1); d.getUTCDate() + periodOffset);
} }
break; break;
case 'w': case 'w':
// Currently, always on Sunday morning at 00:00:00 (UTC). // Currently, always on Sunday morning at 00:00:00 (UTC).
if (this.rotAt) { 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 { } else {
// First time: this coming Sunday. // 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(), rotAt = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(),
d.getUTCDate() + (7 - d.getUTCDay())); d.getUTCDate() + dayOffset);
} }
break; break;
case 'm': case 'm':
if (this.rotAt) { if (this.rotAt) {
rotAt = Date.UTC(d.getUTCFullYear(), rotAt = Date.UTC(d.getUTCFullYear(),
d.getUTCMonth() + this.periodNum, 1); d.getUTCMonth() + this.periodNum * periodOffset, 1);
} else { } else {
// First time: the start of the next month. // 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; break;
case 'y': case 'y':
if (this.rotAt) { if (this.rotAt) {
rotAt = Date.UTC(d.getUTCFullYear() + this.periodNum, 0, 1); rotAt = Date.UTC(d.getUTCFullYear() + this.periodNum * periodOffset,
0, 1);
} else { } else {
// First time: the start of the next year. // 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; break;
default: default: