如何使用Perl修剪日志文件?

时间:2009-02-10 04:13:04

标签: performance perl file-io

我最近提出了这样一种情况:一旦超过一定大小,我需要修剪一些相当大的日志文件。除了每个文件中的最后1000行之外的所有内容都被处理掉,作业每隔半小时由cron运行一次。我的解决方案是简单地浏览文件列表,检查大小并在必要时修剪。

for $file (@fileList) {
  if ( ((-s $file) / (1024 * 1024)) > $CSize) {
      open FH, "$file" or die "Cannot open ${file}: $!\n";
      $lineNo = 0;
      my @tLines;

      while(<FH>) {
        push @tLines, $_;
        shift @tLines if ++$lineNo < CLLimit;
      }
      close FH;

      open FH, ">$file" or die "Cannot write to ${file}: $!\n";
      print FH @tLines;
      close FH;
}

这在当前形式下工作,但是对于大型日志文件(尤其是具有100_000 +行的文件)存在大量开销,因为需要读取每一行并在必要时进行移位。

我是否有办法只阅读文件的一部分,例如在这种情况下,我希望只能访问最后的“CLLimit”行。由于脚本部署在一个看起来更好日子的系统上(想想Celeron 700MHz带有64MB RAM),我正在寻找使用Perl的更快的替代方案。

3 个答案:

答案 0 :(得分:8)

我意识到你想要使用Perl,但如果这是一个UNIX系统,为什么不使用“tail”实用程序进行修剪呢?您可以使用非常简单的脚本在BASH中执行此操作:

if [ `stat -f "%z" "$file"` -gt "$MAX_FILE_SIZE" ]; then
    tail -1000 $file > $file.tmp
    #copy and then rm to avoid inode problems
    cp $file.tmp $file
    rm $file.tmp
fi

话虽如此,如果您为此设置使用Perl,您可能会发现this post非常有帮助。

答案 1 :(得分:4)

估算日志中一条线的平均长度 - 称之为N字节。

从文件末尾向后搜索1000 * 1.10 * N(因子1.10中的误差率为10%)。从那里向前看,只保留最近的1000行。


问的问题是 - 哪个功能或模块?

内置函数seek在我看来就像使用的工具一样?

答案 2 :(得分:4)

考虑简单地使用logrotate实用程序;它包含在大多数现代Linux发行版中。 BSD系统的相关工具称为newsyslog。这些工具的设计或多或少都符合您的预期目的:它以原子方式将日志文件移动到位,创建一个新文件(与以前同名)以保存新的日志条目,指示程序生成消息以使用新文件,然后(可选)压缩旧文件。您可以配置要保留的旋转日志数。这是一个潜在的教程: http://www.debian-administration.org/articles/117

这并不是您想要的界面(保留一定数量的线条),但程序可能比您自己烹饪的更强大;例如,这里的答案不涉及原子地移动文件并通知日志程序使用新文件,因此存在一些日志消息丢失的风险。