Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Adding support for time-based Log Rotation #13

Closed
wants to merge 6 commits into from

2 participants

@thakkar-rushikesh

In my project there was a requirement to rotate logs at 4:00 AM every morning. As you know, It is a common use-case to rotate the logs. So I implemented the same and committing it back to repository. Please go through the changes I've made and see if it can be merged along with your master (w/ or w/o modifications).

I have modified the Readme & also added an example of how to make use of this feature at: https://github.com/thakkar-rushikesh/log.js/blob/master/examples/file-rotate.js.

Please review and provide your suggestions if any.

@tj
Owner
tj commented

logrotate(1)

@thakkar-rushikesh

Sorry, I didn't get you.

If you are suggesting to use Linux's logrotate command, then let me tell you I already tried it. It doesn't work, because of some issue with file-handle. Moreover, logrotate is not available on all the flavours of Linux, even if we ignore Windows.

@tj
Owner
tj commented

different lib or tool

@tj tj closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 7, 2012
  1. @thakkar-rushikesh
Commits on Mar 13, 2012
  1. @thakkar-rushikesh
Commits on Apr 4, 2012
  1. @thakkar-rushikesh
Commits on Apr 6, 2012
  1. @thakkar-rushikesh
  2. @thakkar-rushikesh
Commits on Apr 9, 2012
  1. @thakkar-rushikesh
This page is out of date. Refresh to see the latest.
Showing with 126 additions and 12 deletions.
  1. +10 −0 Readme.md
  2. +43 −0 examples/file-rotate.js
  3. +73 −12 lib/log.js
View
10 Readme.md
@@ -33,6 +33,16 @@ Instead of the log level constants, you may also supply a string:
We can also use `%s` much like `console.log()` to pass arguments:
log.error('oh no, failed to send mail to %s.', user.email);
+
+When using file stream, you can specify rotation-time (as hour-of-the-day in 24hrs format) to rotate the log file:
+
+ var fs = require('fs')
+ , Log = require('log')
+ var stream = fs.createWriteStream('/path/to/my-node.log');
+ var log = new Log('debug', stream, {rotate:true, rotationTime:23});
+
+This will emit `rotate` event at the specified hour of the day. In the above example, `rotate` event will be emitted at 11:00 PM.
+You need to handle `rotate` event to actually rotate the file. An example is provided here: `examples\file-rotate.js`.
## Reader
View
43 examples/file-rotate.js
@@ -0,0 +1,43 @@
+var fs = require('fs');
+var Log = require('log');
+var logger;
+
+function formatDate(dt) {
+ var month = dt.getMonth() + 1;
+ month = (month < 10) ? ('0'+month) : month;
+ var date = dt.getDate();
+ date = (date < 10) ? ('0'+date) : date;
+ var strDate = dt.getFullYear() + '-' + month + '-' + date; //yyyy-MM-dd
+ return strDate;
+}
+
+function initializeLog(logFileName) {
+ var stream = fs.createWriteStream(logFileName, {flags: 'a+', mode:0777});
+ logger = new Log('debug', stream, {rotate:true, rotationTime:20});
+ logger.on('rotate', function (rotateTime) {
+ logger.info('Time to Rotate the log file: ' + rotateTime);
+ strDate = formatDate(rotateTime);
+ console.log(strDate);
+ stream.destroy();
+
+ stream.on('close', function(){
+ fs.rename(logFileName, logFileName+'.'+strDate, function(){
+ console.log('Re-initializing logger.');
+ initializeLog(logFileName);
+ });
+ });
+ stream.on('error', function(err){
+ console.log('Error: ' + err);
+ });
+ });
+}
+
+initializeLog('/var/log/node/node.log');
+
+logger.debug('Counting Stars on this bright sunny day!');
+var i = 1;
+setInterval(function() {
+ console.log('Star: ' + i);
+ logger.debug('Star: ' + i);
+ i++;
+}, 2000);
View
85 lib/log.js
@@ -5,25 +5,72 @@
*/
/**
- * Module dependencies.
+ * Returns the next date of the given date
+ *
+ * @author thakkar.rushikesh
+ * @param Date
+ * @type Date
+ */
+function getNextDate(dt) {
+ var nxt = new Date();
+ nxt.setDate(dt.getDate()+1);
+ return nxt;
+}
+
+/**
+ * Returns the number of milliseconds remaining for rotation.
+ *
+ * @author thakkar.rushikesh
+ * @param {Number} hourOfTheDay - in 24hrs format
+ * @type Number
*/
+function calculateTimeToRotate(rotationTime) {
+ var milliSeconds;
+ if (rotationTime) {
+ var now = new Date;
+ var rotateAt = new Date;
+ if (now.getHours() >= rotationTime) {
+ rotateAt = getNextDate(now);
+ }
+ rotateAt.setHours(rotationTime);
+ rotateAt.setMinutes(0);
+ rotateAt.setSeconds(0);
+ milliSeconds = rotateAt.getTime()-now.getTime();
+ }
+ return milliSeconds;
+}
+/**
+ * Module dependencies.
+ */
var EventEmitter = require('events').EventEmitter;
/**
- * Initialize a `Loggeer` with the given log `level` defaulting
+ * Initialize a `Logger` with the given log `level` defaulting
* to __DEBUG__ and `stream` defaulting to _stdout_.
*
+ * Initialize the `rotate` flag with the given value, defaulting to `false` meaning it will NOT emit `rotate` event.
+ *
* @param {Number} level
* @param {Object} stream
* @api public
*/
+var Log = exports = module.exports = function Log(level, stream, userPrefs){
-var Log = exports = module.exports = function Log(level, stream){
if ('string' == typeof level) level = exports[level.toUpperCase()];
this.level = level || exports.DEBUG;
this.stream = stream || process.stdout;
if (this.stream.readable) this.read();
+
+ this.rotate = false;
+ if(stream && userPrefs) {
+ this.rotate = userPrefs.rotate || false;
+ if (this.rotate == true) {
+ this.rotationTime = userPrefs.rotationTime || 0;
+ this.timeToRotate = calculateTimeToRotate(this.rotationTime);
+ this.initRotation(this.timeToRotate);
+ }
+ }
};
/**
@@ -95,7 +142,18 @@ exports.DEBUG = 7;
*/
Log.prototype = {
-
+ /**
+ * @author thakkar.rushikesh
+ * @param {Number} Number of milliseconds to wait before emitting `rotate` event.
+ * Initiates Log rotation timer. Emits `rotate` event after waiting till specified time.
+ */
+ initRotation: function(waitTime) {
+ var self = this;
+ setTimeout(function(){
+ self.emit('rotate', new Date);
+ }, waitTime);
+ },
+
/**
* Start emitting "line" events.
*
@@ -136,24 +194,27 @@ Log.prototype = {
/**
* Log output message.
- *
* @param {String} levelStr
* @param {Array} args
* @api private
*/
-
log: function(levelStr, args) {
if (exports[levelStr] <= this.level) {
var i = 1;
var msg = args[0].replace(/%s/g, function(){
return args[i++];
});
- this.stream.write(
- '[' + new Date + ']'
- + ' ' + levelStr
- + ' ' + msg
- + '\n'
- );
+ var logTime = new Date;
+ try {
+ this.stream.write(
+ '[' + logTime.toLocaleString() + ']'
+ + ' ' + levelStr
+ + ' ' + msg
+ + '\n'
+ );
+ } catch(err) {
+ console.log(err);
+ }
}
},
Something went wrong with that request. Please try again.