如何在 Perl 中处理来自连续流程管道的更新

How to handle updates from an continuous process pipe in Perl

我试图在 Fedora 上跟踪 Perl 中的日志文件,但不幸的是,Fedora 使用 journalctl 读取我无法直接解析的二进制日志文件。根据我的理解,这意味着我只能通过调用 journalctl.

来读取 Fedora 的日志文件

我尝试使用 IO::Pipe 来做到这一点,但问题是 $p->reader(..) 一直等到 journalctl --follow 完成写入输出(这将永远不会发生,因为 --follow 是像 tail -F) 然后允许我打印出所有不是我想要的东西。我希望能够设置一个回调函数,以便在每次将新行打印到流程管道时调用,这样我就可以 parse/handle 每个新的日志事件。

use IO::Pipe;

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

while (<$p>) {
  print;
}

我认为 journalctl 的工作方式与 tail -f 相同。如果这是正确的,一个简单的 open 应该可以完成工作:

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 打开一个文件句柄以读取被调用命令的输出:http://perldoc.perl.org/functions/open.html

seek 用于重置 EOF 标记:http://perldoc.perl.org/functions/seek.html 如果不重置,所有后续 <$fh> 调用将只是 return EOF 即使被调用的脚本发出额外的输出与此同时。

只要由 open 启动的子进程还活着,

kill 0,$pid 就会为真。

您可以从 Time::HiResselect undef,undef,undef,$fractional_seconds;sleep 1 替换为 usleep 以等待不到一秒钟,具体取决于传入线路的频率。

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

更新:

在开头添加 use POSIX ":sys_wait_h"; 并在外循环中添加 waitpid $pid, WNOHANG) 也会检测(并收获)僵尸 journalctl 进程:

while (kill(0, $pid) and waitpid($pid, WNOHANG) != $pid) {

守护进程可能还想检查 $pid 是否仍然是当前进程 ($$) 的子进程,以及它是否仍然是原始的 journalctl 进程。

我无法访问 journalctl,但是如果您避免 IO::Pipe 并直接打开管道输出,那么数据将不会被缓冲

use strict;
use warnings 'all';

open my $follow_fh, '-|', 'journalctl --follow' or die $!;

print while <$follow_fh>;