rotating-file-stream
Advanced tools
Comparing version 0.1.0 to 1.0.0
@@ -9,3 +9,3 @@ "use strict"; | ||
function compress(callback, tmp) { | ||
function compress(tmp) { | ||
var self = this; | ||
@@ -15,13 +15,18 @@ | ||
if(err) | ||
return callback(null, err); | ||
return self.emit("error", err); | ||
self.touch(name, function(err) { | ||
if(err) | ||
return callback(null, err); | ||
return self.emit("error", err); | ||
var done = function(err) { | ||
if(err) | ||
return callback(name, err); | ||
return self.emit("error", err); | ||
fs.unlink(tmp, callback.bind(null, name)); | ||
fs.unlink(tmp, function(err) { | ||
if(err) | ||
self.emit("warning", err); | ||
self.emit("rotated", name); | ||
}); | ||
}; | ||
@@ -84,5 +89,13 @@ | ||
var name = tmp ? this.name + "." + count + ".log": this.generator(this.options.interval ? new Date(this.prev) : this.rotation, count + 1); | ||
var name = this.name + "." + count + ".log"; | ||
var self = this; | ||
if(! tmp) | ||
try { | ||
name = this.generator(this.options.interval ? new Date(this.prev) : this.rotation, count + 1); | ||
} | ||
catch(err) { | ||
return process.nextTick(callback.bind(null, err)); | ||
} | ||
fs.stat(name, function(err) { | ||
@@ -103,6 +116,5 @@ if((! err) || err.code != "ENOENT" ) { | ||
function gzip(src, dst, callback) { | ||
var inp = fs.createReadStream(src); | ||
var out = fs.createWriteStream(dst); | ||
var zip = zlib.createGzip(); | ||
var inp = fs.createReadStream(src); | ||
var out = fs.createWriteStream(dst); | ||
var zip = zlib.createGzip(); | ||
var files = [inp, out, zip]; | ||
@@ -128,3 +140,3 @@ | ||
utils.makePath(name, err, function(err) { | ||
utils.makePath(name, function(err) { | ||
if(err) | ||
@@ -131,0 +143,0 @@ return callback(err); |
226
index.js
@@ -39,2 +39,3 @@ "use strict"; | ||
this.chunks = []; | ||
this.options = options; | ||
@@ -50,106 +51,109 @@ this.size = 0; | ||
RotatingFileStream.prototype._callback = function(err) { | ||
if(! this.callback) { | ||
if(err) | ||
process.nextTick(this.emit.bind(this, "error", err)); | ||
RotatingFileStream.prototype._clear = function(done) { | ||
if(this.timer) { | ||
clearTimeout(this.timer); | ||
this.timer = null; | ||
} | ||
}; | ||
return; | ||
RotatingFileStream.prototype._close = function(done) { | ||
if(this.stream) { | ||
this.stream.on("finish", done); | ||
this.stream.end(); | ||
this.stream = null; | ||
} | ||
if(err) | ||
process.nextTick(this.callback.bind(null, err)); | ||
else | ||
process.nextTick(this._rewrite.bind(this, this.chunks, this.index, this.callback)); | ||
this.callback = null; | ||
done(); | ||
}; | ||
RotatingFileStream.prototype._postrewrite = function(chunks, index, callback, next) { | ||
this.callback = callback; | ||
this.chunks = chunks; | ||
this.index = index; | ||
RotatingFileStream.prototype._rewrite = function() { | ||
var self = this; | ||
var callback = function() { | ||
if(self.ending) | ||
self._close(Writable.prototype.end.bind(self)); | ||
}; | ||
if(next) | ||
next(); | ||
}; | ||
if(this.err) { | ||
for(var i in this.chunks) | ||
if(this.chunks[i].cb) | ||
this.chunks[i].cb(); | ||
RotatingFileStream.prototype._rewrite = function(chunks, index, callback, err) { | ||
if(err) | ||
return callback(err); | ||
this.chunks = []; | ||
if(! this.stream) | ||
return this._postrewrite(chunks, index, callback); | ||
return callback(); | ||
} | ||
if(this.writing) | ||
return; | ||
if(this.options.size && this.size >= this.options.size) | ||
return this._postrewrite(chunks, index, callback, this.rotate.bind(this)); | ||
return this.rotate(); | ||
if(chunks.length == index) | ||
if(! this.stream) | ||
return; | ||
if(! this.chunks.length) | ||
return callback(); | ||
var buffer = new Buffer(0); | ||
var chunk; | ||
var chunk = this.chunks[0]; | ||
if(index + 1 == chunks.length) { | ||
chunk = chunks[index++].chunk; | ||
this.size += chunk.length; | ||
buffer = chunk; | ||
} | ||
else | ||
while(index < chunks.length && ((! this.options.size) || this.size < this.options.size)) { | ||
chunk = chunks[index++].chunk; | ||
this.size += chunk.length; | ||
buffer = Buffer.concat([buffer, chunk], buffer.length + chunk.length); | ||
} | ||
this.chunks.shift(); | ||
this.size += chunk.chunk.length; | ||
this.writing = true; | ||
this.stream.write(buffer, this._rewrite.bind(this, chunks, index, callback)); | ||
this.stream.write(chunk.chunk, function(err) { | ||
self.writing = false; | ||
if(err) | ||
self.emit("error", err); | ||
if(chunk.cb) | ||
chunk.cb(); | ||
process.nextTick(self._rewrite.bind(self)); | ||
}); | ||
}; | ||
RotatingFileStream.prototype._write = function(chunk, encoding, callback) { | ||
this._rewrite([{ chunk: chunk }], 0, callback); | ||
this.chunks.push({ chunk: chunk, cb: callback }); | ||
this._rewrite(); | ||
}; | ||
RotatingFileStream.prototype._writev = function(chunks, callback) { | ||
this._rewrite(chunks, 0, callback); | ||
chunks[chunks.length - 1].cb = callback; | ||
this.chunks = this.chunks.concat(chunks); | ||
this._rewrite(); | ||
}; | ||
RotatingFileStream.prototype.firstOpen = function() { | ||
var self = this; | ||
try { | ||
this.name = this.generator(null); | ||
} | ||
catch(e) { | ||
var err = new Error("Executing file name generator first time: " + e.message); | ||
err.source = e; | ||
throw err; | ||
catch(err) { | ||
return process.nextTick(function() { | ||
self.emit("error", err); | ||
process.nextTick(self._rewrite.bind(self)); | ||
}); | ||
} | ||
if(this.firstRotation()) | ||
this.open(); | ||
}; | ||
fs.stat(this.name, function(err, stats) { | ||
if(err) { | ||
if(err.code == "ENOENT") | ||
return self.open(); | ||
RotatingFileStream.prototype.firstRotation = function() { | ||
var stats; | ||
return self.emit("error", err); | ||
} | ||
try { | ||
stats = fs.statSync(this.name); | ||
} | ||
catch(e) { | ||
if(e.code == "ENOENT") | ||
return true; | ||
if(! stats.isFile()) | ||
return self.emit("error", new Error("Can't write on: " + self.name + " (it is not a file)")); | ||
throw e; | ||
} | ||
self.size = stats.size; | ||
if(! stats.isFile()) | ||
throw new Error("Can't write on: " + this.name + " (it is not a file)"); | ||
this.size = stats.size; | ||
if((! this.options.size) || stats.size < this.options.size) | ||
return true; | ||
process.nextTick(this.rotate.bind(this)); | ||
return false; | ||
if((! self.options.size) || stats.size < self.options.size) | ||
self.open(); | ||
else | ||
self.rotate(); | ||
}); | ||
}; | ||
@@ -209,17 +213,10 @@ | ||
if(err) | ||
return self._callback(err); | ||
return self.emit("error", err); | ||
self.open(); | ||
var done = function(name, err) { | ||
if(err) | ||
self.emit("error", err); | ||
else | ||
self.emit("rotated", name); | ||
}; | ||
if(self.options.compress) | ||
self.compress(done, name); | ||
self.compress(name); | ||
else | ||
done(name); | ||
self.emit("rotated", name); | ||
}; | ||
@@ -240,3 +237,3 @@ | ||
utils.makePath(name, err, function(err) { | ||
utils.makePath(name, function(err) { | ||
if(err) | ||
@@ -253,59 +250,44 @@ return callback(err); | ||
var fd; | ||
var self = this; | ||
var self = this; | ||
var options = { flags: "a" }; | ||
var callback = function(err) { | ||
self._callback(err); | ||
if(err) | ||
self.emit("error", err); | ||
if(! err) | ||
self.interval(); | ||
process.nextTick(self._rewrite.bind(self)); | ||
}; | ||
try { | ||
var options = { flags: "a" }; | ||
if("mode" in this.options) | ||
options.mode = this.options.mode; | ||
if("mode" in this.options) | ||
options.mode = this.options.mode; | ||
var stream = fs.createWriteStream(this.name, options); | ||
var stream = fs.createWriteStream(this.name, options); | ||
stream.once("open", function() { | ||
self.stream = stream; | ||
self.emit("open"); | ||
self.interval(); | ||
stream.once("open", function() { | ||
self.stream = stream; | ||
callback(); | ||
self.emit("ready"); | ||
}); | ||
callback(); | ||
}); | ||
stream.once("error", function(err) { | ||
if(err.code != "ENOENT" && ! retry) | ||
stream.once("error", function(err) { | ||
if(err.code != "ENOENT" && ! retry) | ||
return callback(err); | ||
utils.makePath(self.name, function(err) { | ||
if(err) | ||
return callback(err); | ||
utils.makePath(self.name, err, function(err) { | ||
if(err) | ||
return callback(err); | ||
self.open(true); | ||
}); | ||
self.open(true); | ||
}); | ||
} | ||
catch(e) { | ||
return callback(e); | ||
} | ||
}); | ||
}; | ||
RotatingFileStream.prototype.rotate = function() { | ||
if(this.timer) { | ||
clearTimeout(this.timer); | ||
this.timer = null; | ||
} | ||
this.size = 0; | ||
this.rotation = new Date(); | ||
process.nextTick(this.emit.bind(this, "rotation")); | ||
if(this.stream) { | ||
this.stream.on("finish", this.move.bind(this)); | ||
this.stream.end(); | ||
this.stream = null; | ||
} | ||
else | ||
this.move(); | ||
this._clear(); | ||
this._close(this.move.bind(this)); | ||
this.emit("rotation"); | ||
}; | ||
@@ -312,0 +294,0 @@ |
{ | ||
"name": "rotating-file-stream", | ||
"version": "0.1.0", | ||
"version": "1.0.0", | ||
"description": "Opens a stream.Writable to a file rotated by interval and/or size. A logrotate alternative.", | ||
@@ -5,0 +5,0 @@ "engines": { |
@@ -194,6 +194,7 @@ # rotating-file-stream | ||
// here are reported errors occurred while rotating as well write errors | ||
// once this event is fired, the error can't be recovered and the stream will be closed | ||
}); | ||
stream.on('ready', function() { | ||
// no rotated file is open and ready to be written | ||
stream.on('open', function() { | ||
// no rotated file is open (fired after each rotation as well) | ||
}); | ||
@@ -210,2 +211,8 @@ | ||
stream.on('warning', function(err) { | ||
// here are reported non blocking errors | ||
// the only one possible at this version is error while unlinking file after compression | ||
}); | ||
``` | ||
### Rotation logic | ||
@@ -261,2 +268,4 @@ | ||
* 2015-10-08 - v1.0.0 | ||
* Async error reporting refactory | ||
* 2015-10-07 - v0.1.0 | ||
@@ -263,0 +272,0 @@ * Internal gzip compression |
28
utils.js
@@ -152,3 +152,3 @@ "use strict"; | ||
function makePath(name, err, callback) { | ||
function makePath(name, callback) { | ||
var dir = path.parse(name).dir; | ||
@@ -159,3 +159,3 @@ | ||
if(e.code == "ENOENT") | ||
return makePath(dir, err, callback); | ||
return makePath(dir, callback); | ||
@@ -170,25 +170,17 @@ return callback(e); | ||
function setEvents(self) { | ||
var finish = true; | ||
self.once("error", function(err) { | ||
self.err = err; | ||
self.end(); | ||
if(self.stream) | ||
self.stream.end(); | ||
process.nextTick(function() { | ||
if(finish) | ||
self.emit("finish"); | ||
}); | ||
}); | ||
self.once("finish", function() { | ||
finish = false; | ||
self.once("finish", self._clear.bind(self)); | ||
if(self.timer) | ||
clearTimeout(self.timer); | ||
self.end = function(chunk, encoding, callback) { | ||
self.ending = true; | ||
self.timer = null; | ||
}); | ||
if(chunk) | ||
self.write(chunk, encoding, callback); | ||
else | ||
self._rewrite(); | ||
}; | ||
} | ||
@@ -195,0 +187,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1
284
24541
485