Package Exports
- tail-file
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (tail-file) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
tail-file
Node module for tailing files. Fast, easy, persistent, fault tolerant and flexible.
const Tail = require('tail-file');
const mytail = new Tail("myfile.log", line => {
console.log( line );
});Features
It will deliver new lines from a file.
- Without delay. It's using
fs.watch. No poll interval. - Even if you move the file, as with a log rotation.
- Even if you restart the program in the middle of the log rotation, by tailing the secondary file.
- When the file has been moved and new lines starts appearing in the original location, it will switch over to the new file.
- But it will always finish up reading the rest of the lines from the current file. Not getting distracted by empty files.
- When switching to a new file, it will start from the beginning, as to not miss any rows.
- except if the new file actually was copied or moved into place, with too many existing rows, in which case it will continue from the bottom.
- You can let tail-file search for the starting position, and it will continue at that position, even if it's in the secondary file.
- It will never throw exceptions. No matter what type of errors. All errors are emitted as messages.
- All the code is asynchronous. No waiting on file system. Tried to avoid all race conditions.
- And most of this is very configurable and hackable.
Events
With no callback provided, the tailing will not start until you tell it to. Here is longer example. Use the parts you need.
const Tail = require('tail-file');
const mytail = new Tail("myfile.log");
mytail.on('error', err => throw(err) );
mytail.on('line', line => console.log(line) );
mytail.on('ready', fd => console.log("All line are belong to us") );
mytail.on('eof', pos => console.log("Catched up to the last line") );
mytail.on('skip', pos => console.log("myfile.log suddenly got replaced with a large file") );
mytail.on('secondary', filename => console.log(`myfile.log is missing. Tailing ${filename} instead`) );
mytail.on('restart', reason => {
if( reason == 'PRIMEFOUND' ) console.log("Now we can finally start tailing. File has appeared");
if( reason == 'NEWPRIME' ) console.log("We will switch over to the new file now");
if( reason == 'TRUNCATE' ) console.log("The file got smaller. I will go up and continue");
});
mytail.start();Continue tail at last known position
If you want to start where you left of the tail and not miss any lines, even if the last known line has been log rotated, you can use findStart().
It will start the tail at the line matching the given regexp that passes the comparison test. Suitable for log files that has sorted values, like timestamps or number sequences.
If the first matching line of the file comes after the target position, it will look for the target line in the secondary file. If the line is found in the secondary file, the tail will start. After all the lines of the secondary file has been reported, the tail will continue with the primary file as usual.
Syntax
tailObj.findStart( match, cmp )Parameters
{RegExp} matchA regexp for finding starting line. The first captured substring will be sent to the comparison function. Lines not matching the regexp will be ignored.
{function} cmpA compare function for finding starting line. For each line matching the match regexp, the cmp function will be called with the first captured substring.
cmp must return a positive number if the target line comes after the current line.
Return value
Returns a promise that are resolved when the start was found and the tailing started.
If the log contains a line before the target, followed by a line after the target, we will start the tailing with the first line after the line before the target, that matches the regexp. You can set up any special logic for handling this case in the event handler for lines, after the tailing has started.
The promise will be rejected if there was an error reading the files or if the target line wasn't found in the primary or secondary file.
If the force option is set to true, the tail will start even if there was an error.
Example
This will continue the tail at the line matching the date. This example uses ISO Dates which can be compared as strings.
const timestamp = '2020-01-01 00:00:00';
mytail.findStart( /^(\d+-\d+-\d+ \d+:\d+:\d+)/, date => timestamp.localeCompare(date) );Options
All internals are exposed in the object. Use with care. :)
You can also set or replace any of the properties or methods by passing them in as a options parameter.
const mytail = new Tail( "filename", { ... options ... }, callback );secondary = ${filename}.1
The file to tail if the primary
filenameis not found.
startPos = 'end'
Where to start tailing. It can be
startorendor an actual byte position in the file.
cutoff = 5000
New files appearing after tailing started, will be tailed from the start, unless they are larger than this many bytes, in which case they will be tailed from the tail.
force = false
If force is true, it will start waiting for a file to tail even if it can't find the file and also can't find the secondary file. The default is to send an error message with
ENOENTtelling that it can't find the file.
sep = \n
The line separator. May be a regexp. For example
/\r?\n/.
encoding = utf8
Any encoding recognized by nodes StringDecoder. This includes ucs2, utf16le, latin1, base64 and more.
There are other properties that can be read or modified. Take a look in the source.
Finally
This module was partly inspired by always-tail
No care has been given to make this module work on older versions of node. Developed and tested on GNU/Linux. But it should work on other platforms.