2 var debug = require('../debug')('fileSync')
3 , layouts = require('../layouts')
4 , path = require('path')
6 , streams = require('../streams')
11 function RollingFileSync (filename, size, backups, options) {
12 debug("In RollingFileStream");
14 function throwErrorIfArgumentsAreNotValid() {
15 if (!filename || !size || size <= 0) {
16 throw new Error("You must specify a filename and file size");
20 throwErrorIfArgumentsAreNotValid();
22 this.filename = filename;
24 this.backups = backups || 1;
25 this.options = options || { encoding: 'utf8', mode: parseInt('0644', 8), flags: 'a' };
28 function currentFileSize(file) {
31 fileSize = fs.statSync(file).size;
33 // file does not exist
34 fs.appendFileSync(filename, '');
39 this.currentSize = currentFileSize(this.filename);
42 RollingFileSync.prototype.shouldRoll = function() {
43 debug("should roll with current size %d, and max size %d", this.currentSize, this.size);
44 return this.currentSize >= this.size;
47 RollingFileSync.prototype.roll = function(filename) {
49 nameMatcher = new RegExp('^' + path.basename(filename));
51 function justTheseFiles (item) {
52 return nameMatcher.test(item);
55 function index(filename_) {
56 return parseInt(filename_.substring((path.basename(filename) + '.').length), 10) || 0;
59 function byIndex(a, b) {
60 if (index(a) > index(b)) {
62 } else if (index(a) < index(b) ) {
69 function increaseFileIndex (fileToRename) {
70 var idx = index(fileToRename);
71 debug('Index of ' + fileToRename + ' is ' + idx);
72 if (idx < that.backups) {
73 //on windows, you can get a EEXIST error if you rename a file to an existing file
74 //so, we'll try to delete the file we're renaming to first
76 fs.unlinkSync(filename + '.' + (idx+1));
78 //ignore err: if we could not delete, it's most likely that it doesn't exist
81 debug('Renaming ' + fileToRename + ' -> ' + filename + '.' + (idx+1));
82 fs.renameSync(path.join(path.dirname(filename), fileToRename), filename + '.' + (idx + 1));
86 function renameTheFiles() {
87 //roll the backups (rename file.n to file.n+1, where n <= numBackups)
88 debug("Renaming the old files");
90 var files = fs.readdirSync(path.dirname(filename));
91 files.filter(justTheseFiles).sort(byIndex).reverse().forEach(increaseFileIndex);
94 debug("Rolling, rolling, rolling");
98 RollingFileSync.prototype.write = function(chunk, encoding) {
102 function writeTheChunk() {
103 debug("writing the chunk to the file");
104 that.currentSize += chunk.length;
105 fs.appendFileSync(that.filename, chunk);
111 if (this.shouldRoll()) {
112 this.currentSize = 0;
113 this.roll(this.filename);
121 * File Appender writing the logs to a text file. Supports rolling of logs by size.
123 * @param file file log messages will be written to
124 * @param layout a function that takes a logevent and returns a string
125 * (defaults to basicLayout).
126 * @param logSize - the maximum size (in bytes) for a log file,
127 * if not provided then logs won't be rotated.
128 * @param numBackups - the number of log files to keep after logSize
129 * has been reached (default 5)
130 * @param timezoneOffset - optional timezone offset in minutes
131 * (default system local)
133 function fileAppender (file, layout, logSize, numBackups, timezoneOffset) {
134 debug("fileSync appender created");
135 var bytesWritten = 0;
136 file = path.normalize(file);
137 layout = layout || layouts.basicLayout;
138 numBackups = numBackups === undefined ? 5 : numBackups;
139 //there has to be at least one backup if logSize has been specified
140 numBackups = numBackups === 0 ? 1 : numBackups;
142 function openTheStream(file, fileSize, numFiles) {
146 stream = new RollingFileSync(
152 stream = (function(f) {
153 // create file if it doesn't exist
154 if (!fs.existsSync(f))
155 fs.appendFileSync(f, '');
158 write: function(data) {
159 fs.appendFileSync(f, data);
168 var logFile = openTheStream(file, logSize, numBackups);
170 return function(loggingEvent) {
171 logFile.write(layout(loggingEvent, timezoneOffset) + eol);
175 function configure(config, options) {
178 layout = layouts.layout(config.layout.type, config.layout);
181 if (options && options.cwd && !config.absolute) {
182 config.filename = path.join(options.cwd, config.filename);
190 config.timezoneOffset
194 exports.appender = fileAppender;
195 exports.configure = configure;