2016-04-30 3 views
4

Я пытаюсь следить за файлами журнала в Perl на Fedora, но, к сожалению, Fedora использует journalctl для чтения двоичных файлов журнала, которые я не могу разобрать напрямую. Это, по моему мнению, означает, что я могу только читать файлы журнала Fedora, вызывая journalctl.Как обрабатывать обновления из непрерывного процесса в Perl

Я попытался с помощью IO::Pipe, чтобы сделать это, но проблема в том, что $p->reader(..) ждет, пока journalctl --follow делается записи выходных данных (который не будет никогда так --follow, как tail -F), а затем позволяет мне печатать все из которых не то, что я хочу , Я хотел бы иметь возможность установить функцию обратного вызова, которая будет вызываться каждый раз, когда новая строка будет напечатана в канале процесса, чтобы я мог анализировать/обрабатывать каждое новое событие журнала.

use IO::Pipe; 

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

while (<$p>) { 
    print; 
} 
+2

Вашего код работает отлично, когда я использую .e.g. 'tail -f messages' вместо' journalctl' (которого у меня нет). Вы пытались 'journalctl --follow --no-pager'? –

+0

«-no-pager» - это красная селедка, так как любая разумная программа Unix будет вызывать только пейджер, когда его 'stdout' является' tty'. Я пробовал вашу программу на моем телефоне Jolla (у которого есть 'journalctl'), и он работает так, как ожидалось. Все, что не так, не в вашем коде! –

+0

@HansLub Это работает отлично, спасибо. –

ответ

3

Я предполагаю, что 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> просто вернут EOF, даже если вызываемый скрипт выпустил дополнительный вывод за это время.

kill 0,$pid будет правдой до тех пор, пока дочерний процесс начинается с open.

Вы можете заменить sleep 1 на usleep из Time::HiRes или select undef,undef,undef,$fractional_seconds; ждать меньше, чем второй в зависимости от частоты входящих линий.

AnyEvent также должен быть в состоянии выполнить работу через AnyEvent::Handle.

Update:

Добавление use POSIX ":sys_wait_h"; в начале и waitpid $pid, WNOHANG) к внешней петле будет также обнаружить (и пожнешь) зомби journalctl процесс:

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

Демон может также хотите, чтобы проверить, $pid все еще является дочерним элементом текущего процесса ($$), и если он все еще является исходным процессом journalctl.

+0

Почему это поддерживается? Я едва знаю perl, но это выглядит очень неправильно для меня. По крайней мере perl, как указано в fedora (5.22.1-351.fc23.x86_64) не будет звать зомби и сигнализировать зомби с 0 работает просто отлично, так что это бесконечный цикл. Если бы собирали зомби, это противоречило бы чему-то, возможно, повторно использующему pid. Возможно, обработка данных perl нечетна, но 1. SEEK_CUR не должен работать 2. не должно быть никаких данных и нет возможности новых данных после завершения цикла чтения. Если другой конец все еще открыт, procss будет блокироваться в ядре. Так что «спать 1» бесполезно. –

+0

Пожалуйста, RTFM для команд, все они связаны с ответом. Конечно, 'kill 0' не является отказоустойчивым, но достаточным для большинства случаев. Как указано в руководстве, Perl '<$fh>' читает до EOF и после этого возвращает undef/empty list. «Поиск SEEK_CUR» сбрасывает маркер EOF. Этот процесс перейдет на 100% CPU (EOF -> seek -> EOF -> seek), если новые данные не появятся. Это один из способов решения вопроса, но Perl TIMTOWTDY: использование AnyEvent или 'select' было бы более профессиональным, но также более сложным. – Sebastian

+0

Но если зомби не получают (и в моем случае это не так), цикл бесконечен. У вас есть версия, которая пожинает сама по себе? Учитывая ваше изменение добавления waitpid, я дополнительно смущен вашим ответом. Для чтения так называемый EOF обнаруживается, когда syscall возвращается 0. Это не произойдет, даже если труба пуста, если кто-то открывает другой конец. Может быть, у perl есть ошибка, связанная с этим (не так ли?), И ложно устанавливает EOF на его ручках, но я не вижу никаких доказательств этого иска. tl; dr внешний, а цикл выглядит ненужным и неправильным. можете ли вы показать случай, когда это необходимо? –

0

У меня нет доступа к journalctl, но если вы будете избегать IO::Pipe и открыть трубопроводный выход непосредственно, то данные не будут буферным

use strict; 
use warnings 'all'; 

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

print while <$follow_fh>;