使用Perl如何读取文件并解析日志以查找错误日志并输出到log.txt文件

时间:2015-05-04 18:01:48

标签: regex perl

我正在尝试使用Perl创建一个程序,该程序将读取长度超过40,000行的文件的数据并解析每条消息以从中提取错误消息。

我使用的数据样本如下所示:

--------All Messages---------
SUCCESS: data transferred successfully .
SUCCESS: data transferred successfully .
SUCCESS: data transferred successfully .
ERROR: there was an error transferring data .
SUCCESS: data transferred successfully .
SUCCESS: data transferred successfully .
SUCCESS: data transferred successfully .
ERROR: there was an error transferring the data and the error message spans
more than 1 line of code and may also contain newline characters as well .
SUCCESS: data transferred successfully .
SUCCESS: data transferred successfully .
SUCCESS: data transferred successfully .
---------END REPOSITORY---------

日志中的每条消息都有以下共同点:

1)它以SUCCESS或ERROR开头,具体取决于结果

2)所有消息都将以<whitespace><period><newline>

结束

以下是我编写的代码但由于某种原因我似乎无法调试它。非常感谢任何帮助。

open(FH,$filetoparse);
{
# following line is supposed to change the delimiter for the file
    $/ = " .";
# the follow statement will create an error log of all error messages in log and save it
# to a file named errorlog.txt
    while(<FH>)
    {
        push (@msgarray, $_);
    }
if ($outputtype == 1)
{
    $outputfile="errorlog.txt";
    open(OUTPUT,">>$outputfile");
    $errorcount=0;
    $errortarget="ERROR";
    print OUTPUT "-----------Error Log-----------\n";

    for ($i=0;$i<@msgarray;$i++)
    {
    if ($msgarray[$i] =~ /^$errortarget/)
    {

        print OUTPUT "$msgarray[$i]\n";
#       print OUTPUT "next code is: \n";
        $errorcount++;

    }
    print OUTPUT "\nError Count : $errorcount\n";

    close (OUTPUT);
    }
}

3 个答案:

答案 0 :(得分:3)

将换行符添加到分隔符。变化:

$/ = " .";

为:

$/ = " .\n";

如果您想删除分隔符,可以chomp

while(<FH>)
{
    chomp;
    push (@msgarray, $_);
}

答案 1 :(得分:2)

设置$/ = " ."的问题在于,您读取的行将以该结束点结束,后面的行将以其后面的换行符开头。这意味着除了第一行之外,你的所有行都不会以"ERROR"开头 - 它们将以"\nERROR"开头,因此您的测试将始终失败

您希望了解代码中存在的其他一些问题。

  • 必须始终 use strictuse warnings,并使用my声明所有变量尽可能接近其第一个使用点< / p>

  • 您应始终使用具有open三参数形式的词汇文件句柄。您还需要检查每个open的状态,并将$!放在die字符串中,以便您知道 失败的原因。所以

    open(FH,$filetoparse);
    

    变为

    open my $in_fh, '<', $filetoparse or die qq{Unable to open "$filetoparse" for input: $!};
    
  • 最好逐行处理文本文件,除非您有充分的理由将它们全部读入内存 - 例如,如果您需要对数据进行多次传递,或者您需要随机访问对内容而不是线性处理它们。

    值得注意的是,而不是写

    while ( <$in_fh> ) {
        push @msgarray, $_;
    }
    

    你可以说

    @msgarray = <$in_fh>;
    

    具有完全相同的结果

  • 通常更好地迭代数组的内容而不是其索引。而不是

    for ( my $i = 0; $i < @msgarray; ++$i ) {
        # Do stuff with $msgarray[$i];
    }
    
    你可以写

    for my $message ( @msgarray ) {
        # Do stuff with $message;
    }
    

这是重写代码,用于演示这些要点

open my $in_fh, '<', $filetoparse
        or die qq{Unable to open "$filetoparse" for input: $!};

{
    if ( $outputtype == 1 ) {

        my $outputfile  = 'errorlog.txt';
        my $errorcount  = 0;
        my $errortarget = 'ERROR';

        open my $out_fh, '>>', $outputfile
                or die qq{Unable to open "$outputfile" for output: $!};

        print $out_fh "-----------Error Log-----------\n";

        while ( <$in_fh> ) {
          next unless /^\Q$errortarget/;

          s/\s*\.\s*\z//;       # Remove trailing detail
          print $out_fh "$_\n";
          ++$errorcount;
        }

        print $out_fh "\nError Count : $errorcount\n";

        close ($out_fh) or die $!;
    }
}

答案 2 :(得分:0)

文件句柄OUTPUTfor循环中关闭,您在关闭后每次迭代都会访问该循环。将它移到循环外面并尝试

相关问题