Thomas ryolas Thomas ryolas - 1 year ago 102
Perl Question

How to handle updates from an continuous process pipe in Perl

I am trying to follow log files in Perl on Fedora but unfortunately, Fedora uses

to read binary log files that I cannot parse directly. This, according to my understanding, means I can only read Fedora's log files by calling

I tried using
to do this, but the problem is that
waits until
journalctl --follow
is done writing output (which will be never since
is like
tail -F
) and then allows me to print everything out which is not what I want. I would like to be able to set a callback function to be called each time a new line is printed to the process pipe so that I can parse/handle each new log event.

use IO::Pipe;

my $p = IO::Pipe->new();
$p->reader("journalctl --follow"); #Waits for process to exit

while (<$p>) {

Answer Source

I assume that journalctl is working like tail -f. If this is correct, a simple open should do the job:

use Fcntl; # Import SEEK_CUR

my $pid = open my $fh, '|-', 'journalctl --follow'
    or die "Error $! starting journalctl";
while (kill 0, $pid) {
    while (<$fh>) {
        print $_; # Print log line
    sleep 1; # Wait some time for new lines to appear
    seek($fh,0,SEEK_CUR); # Reset EOF

open opens a filehandle for reading the output of the called command:

seek is used to reset the EOF marker: Without reset, all subsequent <$fh> calls will just return EOF even if the called script issued additional output in the meantime.

kill 0,$pid will be true as long as the child process started by open is alive.

You may replace sleep 1 by usleep from Time::HiRes or select undef,undef,undef,$fractional_seconds; to wait less than a second depending on the frequency of incoming lines.

AnyEvent should also be able to do the job via it's AnyEvent::Handle.