2016-03-23 50 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