如何在 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::HiRes
或 select 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>;
我试图在 Fedora 上跟踪 Perl 中的日志文件,但不幸的是,Fedora 使用 journalctl
读取我无法直接解析的二进制日志文件。根据我的理解,这意味着我只能通过调用 journalctl
.
我尝试使用 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::HiRes
或 select 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>;