2016-03-23 47 views
0

我想要一個更有效的方式讓我的Perl腳本通過系統日誌解析。系統日誌的Perl腳本

我的腳本每小時運行一個cron以輸出一些統計信息。我注意到它需要近5-10分鐘即可完成隨着時間的進展(系統日誌每天存檔),因爲日誌文件是幾個GB的大小和腳本只是簡單:

open LOG, $logfile or die "fatal error. Could not open $logfile" 

的問題是,最初的價值第一小時的日誌是日誌中的第一行。隨着時間的推移,系統日誌中的日誌條目的「當前小時」現在來自於,比如行600000到700000.因此,每個小時它變得越來越慢。

一個複雜的方法是根據時間對文件進行grep運行並將結果存儲在tmp文件中,然後讓我的perl腳本處理tmp文件,然後刪除tmp文件並重復。

是否有更多的編程方式來確保我不會每次重讀數千行代碼?

SK

+1

打開文件所花的時間與它的大小無關。 5或10分鐘是很長時間搜索甚至幾千兆字節。你能發佈實際的搜索代碼嗎? – Schwern

+0

我在'while(){$ count ++;打印行$ count \ n「'並以每秒5000行的速度遞增,但在第7個小時內,我當前小時的日誌值爲600000-70000行。代碼非常長,並且不在框中在這個網絡上這麼難以移植,因此這是一小段代碼,基本上,我不想每小時重讀一行1-600000行,我正在檢查當前日誌的日誌值,希望這是有道理的。 – scryptKiddy

+0

實際的搜索是正確的,在上面的打印後面說'如果($ _ =〜/^$ time_search_str /){...做一些事情' – scryptKiddy

回答

7

您有一堆可能的解決方案。


首先是實現小時而不是每天的日誌輪換。然後你的程序只需要讀取每小時的日誌文件。一般來說,如果您的日誌每天進入千兆字節範圍,這可能是一個好主意。


如果這是不可能的,可能有工作可以改善搜索代碼的性能。第一步是運行代碼分析器,如Devel::NYTProf,以確定程序在哪裏花費時間。


而不是做一個線性搜索,你可以做一個binary search。假設你的日誌文件條目是這樣的:

Mar 22 01:22:34 blah blah blah 
Mar 22 01:22:35 blah blah blah 

seek到文件的中間點,讀取部分行,把它扔出去,並讀取下一個全系列。檢查它的時間戳。如果它太新,seek倒退剩餘空間的一半,如果它太舊,seek轉發剩餘空間的一半。重複,直到找到小時的開始。

對於十億條記錄,這需要約log (2 )或30步。


另一種選擇是向後讀取文件。從最後開始(最新的日誌條目)開始工作,直到您點擊小時開始。 File::ReadBackwards可以相當有效地做到這一點。


您可以更改您的日誌統計程序,將其結果寫入數據庫,包括它寫入的最後一條記錄的日誌文件中的位置。然後下一次它將seek s運行到該位置,驗證它是否正確,然後從那裏讀取。


最後,可以考慮使用一個數據庫。您可以將syslogd日誌記錄到數據庫本身,這樣可以避免每個程序都需要登錄到數據庫的開銷。例如,rsyslogsyslog-ng可以做到這一點。

+0

所有偉大的建議Schwern。我完全無法控制日誌輪換,但我也這麼想。就分析而言,這是一個有趣的工具,我通過$ count打印輸出確定了原因。他們打印了幾分鐘,直到最後我打開搜索字符串,我的代碼開始處理。
我喜歡二分查找方法,讓我想起了半步法。我假設'seek'是一個PERL函數?
我的確在考慮向後讀取文件,但不確定它將如何存儲在變量中。換句話說,我必須對其進行反向處理。 – scryptKiddy

+0

數據庫是我推動的東西,尤其是因爲他們渴望歷史統計數據,但是,我關注的第一步是修復似乎永遠需要處理的第一步,因此是後期。 – scryptKiddy

+3

['seek()'](http://perldoc.perl.org/functions/seek.html)是一個Perl函數,它對於大多數編程語言都很常見,並且它會像您在編輯。至於數據庫,你不需要等待某人安裝數據庫服務器,你可以使用[SQLite](https://en.wikipedia.org/wiki/SQLite)。 – Schwern