2016-04-30 21 views
4

我想在Fedora上關注perl中的日誌文件,但不幸的是,Fedora使用journalctl來讀取我無法直接解析的二進制日誌文件。據我的理解,這意味着我只能通過調用journalctl來閱讀Fedora的日誌文件。如何處理來自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。 '尾巴-f消息'而不是'journalctl'(我沒有)。你有沒有試過'journalctl - followlow - 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開始的子進程處於活動狀態。

根據輸入線路的頻率,您可以用usleep替換sleep 1Time::HiResselect undef,undef,undef,$fractional_seconds;等待不到一秒。

AnyEvent也應該可以通過它的​​來完成這項工作。

更新:

添加use POSIX ":sys_wait_h";在開始和waitpid $pid, WNOHANG)到外環也將檢測(並獲得)殭屍journalctl過程:

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

守護程序也可能要檢查是否$pid仍然是當前進程的子進程($$),如果它仍然是原始journalctl進程。

+0

爲什麼這是upvoted?我幾乎不知道perl,但是這對我來說看起來是非常錯誤的。至少在fedora中提供的perl(5.22.1-351.fc23。x86_64)不會收穫殭屍,並且用0發信號通知殭屍工作得很好,所以這是一個無限循環。如果它正在收穫殭屍,它將與可能重複使用該pid的東西競爭。也許perl的管道處理很奇怪,但是1. SEEK_CUR不應該工作2.一旦完成讀取循環,應該沒有數據留下,也不可能有新數據。如果另一端仍處於打開狀態,則該進程將在內核中阻塞。所以'睡眠1'沒用。 –

+0

請爲這些命令的RTFM,所有這些都從答案鏈接。當然,「殺死0」不是無故障的,但在大多數情況下已經足夠了。正如手冊所述,Perl的'<$fh>'讀取直到EOF並且之後返回undef /空列表。 'seek SEEK_CUR'重置EOF標記。如果沒有新數據到達,進程將進入100%CPU(EOF - > seek - > EOF - > seek)。這是解決問題的一種方式,但Perl是TIMTOWTDY:使用AnyEvent或select可以更專業,但也更復雜。 – Sebastian

+0

但是如果殭屍沒有被收割(在我的情況下它不是),這個循環是無限的。你有一個自己收穫的版本嗎?鑑於你的編輯添加waitpid,我還對你的回覆感到困惑。對於讀取,所謂的EOF通過讀取系統調用返回0來檢測。即使管道是空的,只要有人打開另一端,也不會發生這種情況。也許perl有一個與此相關的錯誤(是否?),並虛假地將EOF設置在其手柄上,但我沒有看到這種說法的證據。 tl; dr外部while循環看起來沒有必要和錯誤。你能否展示一個需要它的案例? –

0

我不得不journalctl用不上,但是如果你避免IO::Pipe並打開管道輸出直接,則數據將不會被緩衝

use strict; 
use warnings 'all'; 

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

print while <$follow_fh>;