RollingFileStream.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. "use strict";
  2. var BaseRollingFileStream = require('./BaseRollingFileStream')
  3. , debug = require('../debug')('RollingFileStream')
  4. , util = require('util')
  5. , path = require('path')
  6. , fs = require('fs')
  7. , async = require('async');
  8. module.exports = RollingFileStream;
  9. function RollingFileStream (filename, size, backups, options) {
  10. this.size = size;
  11. this.backups = backups || 1;
  12. function throwErrorIfArgumentsAreNotValid() {
  13. if (!filename || !size || size <= 0) {
  14. throw new Error("You must specify a filename and file size");
  15. }
  16. }
  17. throwErrorIfArgumentsAreNotValid();
  18. RollingFileStream.super_.call(this, filename, options);
  19. }
  20. util.inherits(RollingFileStream, BaseRollingFileStream);
  21. RollingFileStream.prototype.shouldRoll = function() {
  22. debug("should roll with current size %d, and max size %d", this.currentSize, this.size);
  23. return this.currentSize >= this.size;
  24. };
  25. RollingFileStream.prototype.roll = function(filename, callback) {
  26. var that = this,
  27. nameMatcher = new RegExp('^' + path.basename(filename));
  28. function justTheseFiles (item) {
  29. return nameMatcher.test(item);
  30. }
  31. function index(filename_) {
  32. return parseInt(filename_.substring((path.basename(filename) + '.').length), 10) || 0;
  33. }
  34. function byIndex(a, b) {
  35. if (index(a) > index(b)) {
  36. return 1;
  37. } else if (index(a) < index(b) ) {
  38. return -1;
  39. } else {
  40. return 0;
  41. }
  42. }
  43. function increaseFileIndex (fileToRename, cb) {
  44. var idx = index(fileToRename);
  45. debug('Index of ' + fileToRename + ' is ' + idx);
  46. if (idx < that.backups) {
  47. //on windows, you can get a EEXIST error if you rename a file to an existing file
  48. //so, we'll try to delete the file we're renaming to first
  49. fs.unlink(filename + '.' + (idx+1), function (err) {
  50. //ignore err: if we could not delete, it's most likely that it doesn't exist
  51. debug('Renaming ' + fileToRename + ' -> ' + filename + '.' + (idx+1));
  52. fs.rename(path.join(path.dirname(filename), fileToRename), filename + '.' + (idx + 1), cb);
  53. });
  54. } else {
  55. cb();
  56. }
  57. }
  58. function renameTheFiles(cb) {
  59. //roll the backups (rename file.n to file.n+1, where n <= numBackups)
  60. debug("Renaming the old files");
  61. fs.readdir(path.dirname(filename), function (err, files) {
  62. async.forEachSeries(
  63. files.filter(justTheseFiles).sort(byIndex).reverse(),
  64. increaseFileIndex,
  65. cb
  66. );
  67. });
  68. }
  69. debug("Rolling, rolling, rolling");
  70. async.series([
  71. this.closeTheStream.bind(this),
  72. renameTheFiles,
  73. this.openTheStream.bind(this)
  74. ], callback);
  75. };