Using a simple stand-in for logdump
#! /usr/bin/perl
use warnings;
use strict;
open my $fh, ">", "log" or die "$0: open: $!";
select $fh;
$| = 1; # disable buffering
for (1 .. 10) {
print $fh "message $_\n" or warn "$0: print: $!";
sleep rand 5;
}
and the skeleton for extract
below to get the processing you want. When logfile
encounters end-of-file, logfile.eof()
is true. Calling logfile.clear()
resets all the error state, and then we sleep and try again.
#include <iostream>
#include <fstream>
#include <cerrno>
#include <cstring>
#include <unistd.h>
int main(int argc, char *argv[])
{
const char *path;
if (argc == 2) path = argv[1];
else if (argc == 1) path = "log";
else {
std::cerr << "Usage: " << argv[0] << " [ log-file ]\n";
return 1;
}
std::ifstream logfile(path);
std::string line;
next_line: while (std::getline(logfile, line))
std::cout << argv[0] << ": extracted [" << line << "]\n";
if (logfile.eof()) {
sleep(3);
logfile.clear();
goto next_line;
}
else {
std::cerr << argv[0] << ": " << path << ": " << std::strerror(errno) << '\n';
return 1;
}
return 0;
}
It's not as interesting as watching it live, but the output is
./extract: extracted [message 1]
./extract: extracted [message 2]
./extract: extracted [message 3]
./extract: extracted [message 4]
./extract: extracted [message 5]
./extract: extracted [message 6]
./extract: extracted [message 7]
./extract: extracted [message 8]
./extract: extracted [message 9]
./extract: extracted [message 10]
^C
I left the interrupt in the output to emphasize that this is an infinite loop.
Use Perl as a glue language to make extract
get lines from the log by way of tail
:
#! /usr/bin/perl
use warnings;
use strict;
die "Usage: $0 [ log-file ]\n" if @ARGV > 1;
my $path = @ARGV ? shift : "log";
open my $fh, "-|", "tail", "-c", "+1", "-f", $path
or die "$0: could not start tail: $!";
while (<$fh>) {
chomp;
print "$0: extracted [$_]\n";
}
Finally, if you insist on doing the heavy lifting yourself, there's a related Perl FAQ:
How do I do a tail -f in perl?
First try
seek(GWFILE, 0, 1);
The statement seek(GWFILE, 0, 1)
doesn't change the current position, but it does clear the end-of-file condition on the handle, so that the next <GWFILE>
makes Perl try again to read something.
If that doesn't work (it relies on features of your stdio implementation), then you need something more like this:
for (;;) {
for ($curpos = tell(GWFILE); <GWFILE>; $curpos = tell(GWFILE)) {
# search for some stuff and put it into files
}
# sleep for a while
seek(GWFILE, $curpos, 0); # seek to where we had been
}
If this still doesn't work, look into the clearerr
method from IO::Handle
, which resets the error and end-of-file states on the handle.
There's also a File::Tail
module from CPAN.