Created
June 8, 2012 02:41
-
-
Save fengmk2/2893211 to your computer and use it in GitHub Desktop.
可以自动切割的日志stream
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Log file stream | |
*/ | |
var fs = require('fs'); | |
var path = require('path'); | |
var Stream = require('stream').Stream; | |
var util = require('util'); | |
var ONE_MINUTE = 60000; | |
var ONE_HOUR = 60 * ONE_MINUTE; | |
var ONE_DAY = 24 * ONE_HOUR; | |
// format datetime, demo: new Date().format("yyyy-MM-dd hh:mm:ss W"); | |
var WEEK_DAYS = [ '周日', '周一', '周二', '周三', '周四', '周五', '周六' ]; | |
Date.prototype.format = function(format) { | |
format = format || "yyyy-MM-dd hh:mm:ss"; | |
var day = this.getDay(); | |
var weeken = (day === 0 || day === 6) ? WEEK_DAYS[day] : ''; | |
var o = { | |
"M+" : this.getMonth() + 1, //month | |
"d+" : this.getDate(), //day | |
"h+" : this.getHours(), //hour | |
"m+" : this.getMinutes(), //minute | |
"s+" : this.getSeconds(), //second | |
"q+" : Math.floor((this.getMonth() + 3) / 3), //quarter | |
"W" : WEEK_DAYS[day], // weekday | |
"E" : weeken, // end of week | |
"S" : this.getMilliseconds() //millisecond | |
}; | |
if (/(y+)/.test(format)) { | |
format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)); | |
} | |
for (var k in o) { | |
if (new RegExp("("+ k +")").test(format)) { | |
format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length)); | |
} | |
} | |
return format; | |
}; | |
/** | |
* Log stream, auto cut the log file. | |
* | |
* @param {Object} options | |
* - {String} logdir | |
* - {String} filename, if set `filename`, logstream will not auto cut. | |
* - {String} nameformat, default is 'yyyy-MM-dd.hhmmss.{pid}.log' | |
* - {Number} duration, default is one houre(24 * 3600000 ms), must >= 60s. | |
* return {LogStream} | |
*/ | |
exports.createStream = function (options) { | |
return new LogStream(options); | |
}; | |
function LogStream(options) { | |
if (!(this instanceof LogStream)) { | |
return new LogStream(options); | |
} | |
options = options || {}; | |
this.logdir = options.logdir || './logs'; | |
if (!path.existsSync(this.logdir)) { | |
fs.mkdirSync(this.logdir, '0777'); | |
} | |
this.filename = options.filename; | |
this.nameformat = options.nameformat; | |
if (this.nameformat === null || this.nameformat === undefined) { | |
this.nameformat = 'yyyy-MM-dd.hhmmss.{pid}.log'; | |
} | |
this.nameformat = this.nameformat.replace('{pid}', process.pid); | |
this.duration = options.duration || ONE_HOUR; | |
// must >= one second | |
if (this.duration < 60000) { | |
this.duration = 60000; | |
} | |
this.cut(); | |
this.startTimer(this.firstDuration()); | |
} | |
util.inherits(LogStream, Stream); | |
LogStream.prototype.firstDuration = function () { | |
var now = new Date(); | |
var firstDuration = this.duration; | |
var end = new Date(now + this.duration); | |
if (this.duration > ONE_MINUTE) { | |
if (this.duration < ONE_HOUR) { // in minute | |
firstDuration = new Date(new Date(now.getTime() + this.duration).format('yyyy-MM-dd hh:mm:00')) - now; | |
} else if (this.duration < ONE_DAY) { // in hour | |
firstDuration = new Date(new Date(now.getTime() + this.duration).format('yyyy-MM-dd hh:00:00')) - now; | |
} else { // in day | |
firstDuration = new Date(new Date(now.getTime() + this.duration).format('yyyy-MM-dd 00:00:00')) - now; | |
} | |
} | |
return firstDuration; | |
}; | |
LogStream.prototype.startTimer = function (duration) { | |
if (this._timer) { | |
clearTimeout(this._timer); | |
} | |
this._timer = setTimeout(function (self) { | |
this._timer = null; | |
self.cut(); | |
self.startTimer(self.duration); | |
}, duration || this.duration, this); | |
}; | |
LogStream.prototype.cut = function () { | |
if (this.stream) { | |
this.stream.end(); | |
this.stream.destroySoon(); | |
this.stream = null; | |
} | |
var now = new Date(); | |
var name = (this.filename || ''); | |
if (this.nameformat) { | |
name += now.format(this.nameformat); | |
} | |
var logpath = path.join(this.logdir, name); | |
this._reopening = true; | |
this.stream = fs.createWriteStream(logpath, { flags: 'a', mode: '0666' }); | |
this.stream | |
.on("error", this.emit.bind(this, "error")) | |
.on("pipe", this.emit.bind(this, "pipe")) | |
.on("drain", this.emit.bind(this, "drain")) | |
.on("open", function () { | |
this._reopening = false; | |
}.bind(this)) | |
.on("close", function () { | |
if (!this._reopening) { | |
this.emit("close"); | |
} | |
}.bind(this)); | |
}; | |
LogStream.prototype.write = function (string, encoding) { | |
this.stream.write(string, encoding); | |
}; | |
LogStream.prototype.end = function () { | |
if (this._timer) { | |
clearTimeout(this._timer); | |
this._timer = null; | |
} | |
if (this.stream) { | |
this.stream.end(); | |
this.stream.destroySoon(); | |
this.stream = null; | |
} | |
}; | |
exports.LogStream = LogStream; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment