What is rotating-file-stream?
The rotating-file-stream npm package is used to create a stream that writes to a file and rotates the file based on a specified condition, such as file size or time interval. This is particularly useful for logging purposes where you want to manage log file sizes and avoid having a single, ever-growing log file.
What are rotating-file-stream's main functionalities?
Time-based rotation
This feature allows you to rotate the log file based on a time interval. In this example, the log file 'access.log' will be rotated daily and stored in the '/var/log' directory.
const rfs = require('rotating-file-stream');
const stream = rfs.createStream('access.log', {
interval: '1d', // rotate daily
path: '/var/log'
});
Size-based rotation
This feature allows you to rotate the log file based on its size. In this example, the log file 'access.log' will be rotated every time it reaches 10MB and stored in the '/var/log' directory.
const rfs = require('rotating-file-stream');
const stream = rfs.createStream('access.log', {
size: '10M', // rotate every 10 MegaBytes written
path: '/var/log'
});
Compression
This feature allows you to compress the rotated log files. In this example, the log file 'access.log' will be rotated daily and compressed using gzip, then stored in the '/var/log' directory.
const rfs = require('rotating-file-stream');
const stream = rfs.createStream('access.log', {
interval: '1d', // rotate daily
compress: 'gzip', // compress rotated files
path: '/var/log'
});
Custom rotation
This feature allows you to specify a custom rotation policy. In this example, the log file 'access.log' will be rotated and up to 7 rotated files will be kept in the '/var/log' directory.
const rfs = require('rotating-file-stream');
const stream = rfs.createStream('access.log', {
rotate: 7, // keep 7 rotated files
path: '/var/log'
});
Other packages similar to rotating-file-stream
winston-daily-rotate-file
The winston-daily-rotate-file package is a transport for the winston logging library that allows you to rotate log files based on a time interval. It is similar to rotating-file-stream in that it supports time-based rotation and compression, but it is specifically designed to work with the winston logging library.
logrotate-stream
The logrotate-stream package provides a writable stream that rotates log files based on size or time. It is similar to rotating-file-stream in terms of functionality, but it offers a simpler API and fewer configuration options.
file-stream-rotator
The file-stream-rotator package is another option for rotating log files based on size or time. It offers similar features to rotating-file-stream, including time-based and size-based rotation, as well as compression. However, it is less actively maintained compared to rotating-file-stream.
rotating-file-stream
Usage
var rfs = require('rotating-file-stream');
var stream = rfs('file.log', {
size: '10M',
interval: '1d',
compress: 'gzip'
});
Installation
With npm:
npm install rotating-file-stream
API
require('rotating-file-stream');
Returns RotatingFileStream constructor.
Class: RotatingFileStream
Extends stream.Writable.
[new] RotatingFileStream(filename, options)
Returns a new RotatingFileStream to filename as
fs.createWriteStream does.
The file is rotated following options rules.
filename {String|Function}
The most complex problem about file name is: "how to call the rotated file name?"
The answer to this question may vary in many forms depending on application requirements and/or specifications.
If there are no requirements, a String can be used and default rotated file name generator will be used;
otherwise a Function which returns the rotated file name can be used.
function filename(time, index)
- time: {Date} If rotation by interval is enabled, the start time of rotation period, otherwise the time when rotation job started. If null, the not-rotated file name must be returned.
- index {Number} The progressive index of rotation by size in the same rotation period.
An example of a complex rotated file name generator function could be:
function pad(num) {
return (num > 9 ? "" : "0") + num;
}
function generator(time, index) {
if(! time)
return "file.log";
var month = time.getFullYear() + "" + pad(time.getMonth() + 1);
var day = pad(time.getDate());
var hour = pad(time.getHours());
var minute = pad(time.getMinutes());
return "/storage/" + month + "/" +
month + day + "-" + hour + minute + "-" + index + "-" + filename;
}
var rfs = require('rotating-file-stream');
var stream = rfs(generator, {
size: '10M',
interval: '1d'
});
Note:
If part of returned destination path does not exists, the rotation job will try to create it.
options {Object}
- compress: {String|Function|True} (default: null) Specifies compression method of rotated files.
- interval: {String} (default: null) Specifies the time interval to rotate the file.
- path: {String} (default: null) Specifies the base path for files.
- size: {String} (default: null) Specifies the file size to rotate the file.
- highWaterMark: {Number} (default: 16K) Proxied to new stream.Writable
- mode: {Integer} (default: 0o666) Proxied to fs.createWriteStream
path
If present, it is prepended to generated file names.
size
Accepts a positive integer followed by one of these possible letters:
- B: Bites
- K: KiloBites
- M: MegaBytes
- G: GigaBytes
size: '300B',
size: '300K',
size: '100M',
size: '1G',
interval
Accepts a positive integer followed by one of these possible letters:
- s: seconds. Accepts integer divider of 60.
- m: minutes. Accepts integer divider of 60.
- h: hours. Accepts integer divider of 24.
- d: days
interval: '5s',
interval: '5m',
interval: '2h',
interval: '1d',
compress
Due the nature of Node.js compression may be done with an external command (to use other CPUs than the one used
by Node.js) or with internal code (to use the CPU used by Node.js). This decision is left to you.
Following fixed strings are allowed to compress the files with internal libraries:
- bzip2 (not implemented yet)
- gzip
To enable external compression, a function can be used or simply the boolean true value to use default
external compression.
The function should accept source and dest file names and must return the shell command to be executed to
compress the file.
The two following code snippets have exactly the same effect:
var rfs = require('rotating-file-stream');
var stream = rfs('file.log', {
size: '10M',
compress: true
});
var rfs = require('rotating-file-stream');
var stream = rfs('file.log', {
size: '10M',
compress: function(source, dest) {
return "cat " + source + " | gzip -c9 > " + dest;
}
});
Note:
The shell command to compress the rotated file should not remove the source file, it will be removed by the package
if rotation job complete with success.
Events
Custom Events are emitted by the stream.
var rfs = require('rotating-file-stream');
var stream = rfs(...);
stream.on('error', function(err) {
});
stream.on('open', function() {
});
stream.on('rotation', function() {
});
stream.on('rotated', function(filename) {
});
stream.on('warning', function(err) {
});
Rotation logic
Regardless of when and why rotation happens, the content of a single
stream.write
will never be split among two files.
by size
Once the not-rotated file is opened first time, its size is checked and if it is greater or equal to
size limit, a first rotation happens. After each
stream.write,
the same check is performed.
by interval
The package sets a Timeout
to start a rotation job at the right moment.
Under the hood
Logs should be handled so carefully, so this package tries to never overwrite files.
At stream creation, if the not-rotated log file already exists and its size exceeds the rotation size,
an initial rotation attempt is done.
At each rotation attempt a check is done to verify that destination rotated file does not exists yet;
if this is not the case a new destination rotated file name is generated and the same check is
performed before going on. This is repeated until a not existing destination file name is found or the
package is exhausted. For this reason the rotated file name generator function may be called several
times for each rotation job.
Once an error event is emitted, nothing more can be done: the stream is closed as well.
Compatibility
This package is written following Node.js 4.0 specifications always taking care about backward
compatibility. The package it tested under following versions:
Required: Node.js 0.11
Licence
MIT Licence
Bugs
Do not hesitate to report any bug or inconsistency @github.
ChangeLog
- 2015-10-09 - v1.0.2
- 2015-10-08 - v1.0.1
- 2015-10-08 - v1.0.0
- Async error reporting refactory
- 2015-10-07 - v0.1.0
- Internal gzip compression
- 2015-10-06 - v0.0.5
- 2015-09-30 - v0.0.4
- Added path option
- Missing path creation
- 2015-09-29 - v0.0.3
- Rotation by interval
- Buffer optimization (thanks to allevo)
- 2015-09-17 - v0.0.2
- 2015-09-14 - v0.0.1
- 2015-09-10 - v0.0.0