【问题标题】:Perl scripting for syslog系统日志的 Perl 脚本
【发布时间】:2016-03-23 10:11:03
【问题描述】:

我希望我的 Perl 脚本有一种更有效的方式来解析系统日志。

我的脚本每小时运行一次,以输出一些统计数据。我注意到随着时间的推移,完成几乎需要 5-10 分钟(系统日志每天存档),因为系统日志文件大小为几 GB,脚本执行简单:

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

问题在于,最初几小时的日志是日志中的第一行。随着时间的推移,系统日志中日志条目的“当前时间”现在从第 600000 行到第 700000 行。所以每小时它变得越来越慢。

一种复杂的方法是根据时间对文件运行 grep 并将结果存储在 tmp 文件中,然后让我的 perl 脚本处理 tmp 文件,然后删除 tmp 文件,重复。

是否有更程序化的方式来确保我不会每次都重读数千行?

SK

【问题讨论】:

  • 打开文件所需的时间与文件大小无关。 5 或 10 分钟的搜索时间即使是几 GB 也是很长的。你能发布实际的搜索代码吗?
  • 我在while (<LOG>) { $count++; print line $count\n" 之后添加了一个打印,它以每秒 5000 行的速度递增。但是,到了第 7 个小时,我当前一小时的日志价值在 60​​0000-70000 行。代码很长,而且在一个不在这个网络上的盒子上很难移植,因此是小的 sn-p。基本上,我不想每隔一小时重新阅读第 1-600000 行,因为我正在检查日志以获取当前小时的日志价值。希望这是有道理的。
  • 实际搜索就在上面的打印之后,上面写着if ($_ =~ /^$time_search_str/ ) {...do some stuff
  • 您可以将实际代码添加到帖子中吗?很难在 cmets 中对问题进行补充。编辑帖子更容易阅读,更有可能被其他人看到。您可能必须删除业务逻辑,但基本的“读取文件并查找正确的时间戳”应该是可发布的。
  • 抱歉 Schwern,请阅读以上内容,它位于非互联网连接的盒子上,并且不容易输入。我仍在学习如何以更易读的方式发帖,抱歉。

标签: perl


【解决方案1】:

你有很多可能的解决方案。


首先是实施每小时而不是每天的日志轮换。然后你的程序只需要读取每小时的日志文件。如果您的日志每天达到千兆字节范围,这可能是一个好主意。


如果无法做到这一点,则可能需要做一些工作来提高搜索代码的性能。第一步是运行像Devel::NYTProf 这样的代码分析器来找出你的程序在哪里花费时间。


您可以使用binary search 代替线性搜索。假设您的日志文件条目是这样的:

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

seek 到文件的中间点,读取部分行,将其丢弃,然后读取下一个完整行。检查它的时间戳。如果它太新,seek 向后一半剩余空间,如果它太旧,seek 向前一半剩余空间。重复直到找到小时的开始。

对于十亿条记录,这大约需要 log2(230) 或 30 个步骤。


另一种选择是向后读取文件。从最后开始(最新的日志条目)并返回直到您到达小时的开始。 File::ReadBackwards 可以相当有效地做到这一点。


您可以更改您的日志统计程序,将其结果写入数据库,包括它写入的最后一条记录在日志文件中的位置。然后下一次运行它seeks 到那个位置,验证它是正确的,然后从那里向前读取。


最后,考虑使用数据库。您可以将 syslogd 记录到数据库本身,这避免了每个程序都必须记录到数据库的开销。例如,rsyslogsyslog-ng 可以做到这一点。

【讨论】:

  • 所有很棒的建议 Schwern。我绝对无法控制日志轮换,但我也想到了这一点。至于分析,这是一个有趣的工具,我通过 $count 打印输出确定了原因。他们打印了几分钟,直到最后我点击了我的搜索字符串并且我的代码开始处理。
    我喜欢二分查找法,让我想起了半步法。我假设seek 是一个 PERL 函数?
    我确实考虑过向后读取文件,但不确定它如何存储在变量中。换句话说,我是否必须对其进行反向处理。
  • 数据库是我正在推动的东西,特别是因为他们需要历史统计数据,但是,我专注于修复似乎永远需要的处理的第一步,因此发布。
  • seek() 是一个 Perl 函数,它在大多数编程语言中都很常见,它可以像在编辑器中一样在文件中移动光标。至于数据库,不需要等人安装数据库服务器,使用SQLite即可。
  • 脚本还可以简单地记住最后处理的行号,然后在下次运行时开始处理该行之后的文件。
  • @dgw 不是行号,因为它必须读取整个文件才能返回该行号(至少它不必解析每一行)。而是记住该行末尾的字节位置。然后它可以在下次直接seek。这是答案中倒数第二个建议。
猜你喜欢
  • 2016-02-11
  • 1970-01-01
  • 2021-02-14
  • 2017-03-15
  • 2013-06-12
  • 2014-04-30
  • 2013-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多