Files
Zos/Skills/@be/be/node_modules/rotating-file-stream/README.md

384 lines
14 KiB
Markdown
Raw Normal View History

# rotating-file-stream
[![Build Status](https://travis-ci.org/iccicci/rotating-file-stream.png?branch=master)](https://travis-ci.org/iccicci/rotating-file-stream?branch=master)
[![Code Climate](https://codeclimate.com/github/iccicci/rotating-file-stream/badges/gpa.svg)](https://codeclimate.com/github/iccicci/rotating-file-stream)
[![Test Coverage](https://codeclimate.com/github/iccicci/rotating-file-stream/badges/coverage.svg)](https://codeclimate.com/github/iccicci/rotating-file-stream/coverage)
[![Donate](http://img.shields.io/donate/bitcoin.png?color=blue)](https://blockchain.info/address/12p1p5q7sK75tPyuesZmssiMYr4TKzpSCN)
[![NPM version](https://badge.fury.io/js/rotating-file-stream.svg)](https://www.npmjs.com/package/rotating-file-stream)
[![Dependencies](https://david-dm.org/iccicci/rotating-file-stream.svg)](https://david-dm.org/iccicci/rotating-file-stream)
[![Dev Dependencies](https://david-dm.org/iccicci/rotating-file-stream/dev-status.svg)](https://david-dm.org/iccicci/rotating-file-stream?type=dev)
[![NPM](https://nodei.co/npm/rotating-file-stream.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/rotating-file-stream/)
### Description
Creates a [stream.Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable) to a file which is rotated.
Rotation behaviour can be deeply customized; optionally, classical UNIX __logrotate__ behaviour can be used.
### Usage
```javascript
var rfs = require('rotating-file-stream');
var stream = rfs('file.log', {
size: '10M', // rotate every 10 MegaBytes written
interval: '1d', // rotate daily
compress: 'gzip' // compress rotated files
});
```
### Installation
With [npm](https://www.npmjs.com/package/rotating-file-stream):
```sh
$ npm install --save rotating-file-stream
```
# API
```javascript
require('rotating-file-stream');
```
Returns __RotatingFileStream__ constructor.
## Class: RotatingFileStream
Extends [stream.Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable).
## [new] RotatingFileStream(filename, options)
Returns a new __RotatingFileStream__ to _filename_ as
[fs.createWriteStream](https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options) 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 both rotation by interval is enabled and __options.rotationTime__ [(see below)](#rotationtime) is
__false__, 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:
```javascript
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 month + "/" + month +
day + "-" + hour + minute + "-" + index + "-file.log";
}
var rfs = require('rotating-file-stream');
var stream = rfs(generator, {
size: '10M',
interval: '30m'
});
```
__Note:__
if both rotation by interval and rotation by time are used, returned _rotated file name_ __must__ be function of both
parameters _time_ and _index_. Alternatively, __rotationTime__ _option_ can be used (to see below).
If classical __logrotate__ behaviour is enabled _rotated file name_ is only a function of _index_.
#### function filename(index)
* index {Number} The progressive index of rotation. If __null__, the _not-rotated file name_ must be returned.
__Note:__
The _not-rotated file name_ __must__ be only the _filename_, to specify a _path_ the appropriate option __must__ be used.
```javascript
rfs('path/to/file.log'); // wrong
rfs('file.log', { path: 'path/to' }); // OK
```
__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.
* highWaterMark: {Number} (default: null) Proxied to [new stream.Writable](https://nodejs.org/api/stream.html#stream_constructor_new_stream_writable_options)
* history: {String} (default: null) Specifies the _history filename_.
* immutable: {Boolean} (default: null) Never mutates file names.
* initialRotation: {Boolean} (default: null) Initial rotation based on _not-rotated file_ timestamp.
* interval: {String} (default: null) Specifies the time interval to rotate the file.
* maxFiles: {Integer} (default: null) Specifies the maximum number of rotated files to keep.
* maxSize: {String} (default: null) Specifies the maximum size of rotated files to keep.
* mode: {Integer} (default: null) Proxied to [fs.createWriteStream](https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options)
* path: {String} (default: null) Specifies the base path for files.
* rotate: {Integer} (default: null) Enables the classical UNIX __logrotate__ behaviour.
* rotationTime: {Boolean} (default: null) Makes rotated file name with time of rotation.
* size: {String} (default: null) Specifies the file size to rotate the file.
#### path
If present, it is prepended to generated file names as well as for history file.
#### size
Accepts a positive integer followed by one of these possible letters:
* __B__: Bites
* __K__: KiloBites
* __M__: MegaBytes
* __G__: GigaBytes
```javascript
size: '300B', // rotates the file when size exceeds 300 Bytes
// useful for tests
```
```javascript
size: '300K', // rotates the file when size exceeds 300 KiloBytes
```
```javascript
size: '100M', // rotates the file when size exceeds 100 MegaBytes
```
```javascript
size: '1G', // rotates the file when size exceeds a GigaByte
```
#### 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
```javascript
interval: '5s', // rotates at seconds 0, 5, 10, 15 and so on
// useful for tests
```
```javascript
interval: '5m', // rotates at minutes 0, 5, 10, 15 and so on
```
```javascript
interval: '2h', // rotates at midnight, 02:00, 04:00 and so on
```
```javascript
interval: '1d', // rotates at every midnight
```
#### 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:
```javascript
var rfs = require('rotating-file-stream');
var stream = rfs('file.log', {
size: '10M',
compress: true
});
```
```javascript
var rfs = require('rotating-file-stream');
var stream = rfs('file.log', {
size: '10M',
compress: function(source, dest) {
return "cat " + source + " | gzip -c9 > " + dest;
}
});
```
__Note:__
this option is ignored if __immutable__ is set to __true__.
__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.
#### initialRotation
When program stops in a rotation period then restarts in a new rotation period, logs of differente rotation period will
go in the next rotated file; in a few words: a rotation job is lost. If this option is set to __true__ an initial check
is performed against the _not-rotated file_ timestamp and, if it falls in a previous rotation period, an initial
rotation job is done as well.
__Note:__
this option is ignored if __rotationTime__ is set to __true__.
#### rotate
If specified, classical UNIX __logrotate__ behaviour is enabled and the value of this option has same effect in
_logrotate.conf_ file.
__Note:__
following options are ignored if __rotate__ option is specified.
#### immutable
If set to __true__, names of generated files never changes. In other words the _rotated file name generator_ is never
called with a __null__ _time_ parameter and new files are immediately generated with their rotated name.
__rotation__ _envet_ now has a _filename_ paramere with the newly created file name.
Usefull to send logs to logstash through filebeat.
__Note:__
if this option is set to __true__, __compress__ is ignored.
__Note:__
this option is ignored if __interval__ is not set.
#### rotationTime
As specified above, if rotation by interval is enabled, the parameter _time_ passed to _rotatle name generator_ is the
start time of rotation period. Setting this option to __true__, parameter _time_ passed is time when rotation job
started.
__Note:__
if this option is set to __true__, __initialRotation__ is ignored.
#### history
Due to the complexity that _rotated file names_ can have because of the _filename generator function_, if number or
size of rotated files should not exceed a given limit, the package needs a file where to store this information. This
option specifies the name of that file. This option takes effects only if at least one of __maxFiles__ or __maxSize__
is used. If __null__, the _not rotated filename_ with the '.txt' suffix is used.
#### maxFiles
If specified, it's value is the maximum number of _rotated files_ to be kept.
#### maxSize
If specified, it's value must respect same syntax of [size](#size) option and is the maximum size of _rotated files_
to be kept.
## Events
Custom _Events_ are emitted by the stream.
```javascript
var rfs = require('rotating-file-stream');
var stream = rfs(...);
stream.on('error', function(err) {
// here are reported blocking errors
// once this event is emitted, the stream will be closed as well
});
stream.on('open', function(filename) {
// no rotated file is open (emitted after each rotation as well)
// filename: useful if immutable option is true
});
stream.on('removed', function(filename, number) {
// rotation job removed the specified old rotated file
// number == true, the file was removed to not exceed maxFiles
// number == false, the file was removed to not exceed maxSize
});
stream.on('rotation', function() {
// rotation job started
});
stream.on('rotated', function(filename) {
// rotation job completed with success producing given filename
});
stream.on('warning', function(err) {
// here are reported non blocking errors
});
```
## Rotation logic
Regardless of when and why rotation happens, the content of a single
[stream.write](https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback)
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](https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback),
the same check is performed.
### by interval
The package sets a [Timeout](https://nodejs.org/api/timers.html#timers_settimeout_callback_delay_args)
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.
If requested by __maxFiles__ or __maxSize__ options, at the end of a rotation job, a check is performed to ensure that
given limits are respected. This means that __while rotation job is running both the limits could be not respected__,
the same can happend (if __maxFiles__ or __maxSize__ are changed) till the end of first _rotation job_.
The first check performed is the one against __maxFiles__, in case some files are removed, than the check against
__maxSize__ is performed, finally other files can be removed. When __maxFiles__ or __maxSize__ are enabled for first
time, an _history file_ can be created with one _rotated filename_ (as returned by _filename generator function_) at
each line.
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 is tested under
[several Node.js versions](https://travis-ci.org/iccicci/rotating-file-stream).
__Required: Node.js 0.11__
## Licence
[MIT Licence](https://github.com/iccicci/rotating-file-stream/blob/master/LICENSE)
## Bugs
Do not hesitate to report any bug or inconsistency [@github](https://github.com/iccicci/rotating-file-stream/issues).
## ChangeLog
[ChangeLog](https://github.com/iccicci/rotating-file-stream/blob/master/CHANGELOG.md)
## Donating
If you find useful this package, please consider the opportunity to donate some satoshis to this bitcoin address:
__12p1p5q7sK75tPyuesZmssiMYr4TKzpSCN__