如何刮取多个日志文件以查找异常

时间:2013-02-04 20:46:57

标签: perl logging sed awk grep

我正在编写一个node.js函数来ssh到远程机器,并尝试从各种不同的日志文件中获取异常日志。日志文件的重要位将如下所示:

.... gunk ....



2013-01-29 04:06:39,133 com.blahblah.BaseServlet processRequest Thread-1629  Site-102 Cons-0 Url-http://theurlthat.com/caused/the/problem App-26 yada yada yada

java.lang.NullPointerException
        at com.blahblah.MyClass.hi(MyClass.java:173)
        at com.blahblah.StandardStackTrace.main(StandardStackTrace.java:125)
        at com.blahblah.SoOnAndSo.forth(SoOnAndSo.java:109)
        at java.lang.Thread.run(Thread.java:595)


2013-01-29 04:06:39,133 com.blahblah.BaseServlet defaultThrowableHandler Thread-1629  Site-102 Cons-0 Url-http://theurlthat.com/caused/the/problem App-26 yad yada yada

TechnicalDifficultiesException: TD page delivered by handleThrowable
http://theurlthat.com/caused/the/problem


....more gunk....

我需要在日志文件中找到满足以下三个要求的异常和相应日期:

  1. 例外必须是此静态文本之前的第一个:

    TechnicalDifficultiesException:由handleThrowable

  2. 提供的TD页面
  3. Exception必须直接在具有“BaseServlet。* Site-102”的两行之间

  4. 例外必须是满足上述条件的日志文件中的最新(最后)。日志定期滚动,因此它需要是Log中的最后一个,或者如果它不存在于Log.001中的最后一个,或者如果不存在,则Log.002中的最后一个等等。

  5. 由于该程序必须ssh到许多潜在服务器中的一个,因此最好只需要维护node.js程序中的逻辑而不是具有日志的计算机上的逻辑。因此,perl / sed / awk / grep / etc中的单行是最理想的。

1 个答案:

答案 0 :(得分:2)

所以,如果我理解正确,你的问题就是这样:

  • 日志文件包含多个以换行符分隔的部分。
  • 每个人都有一行日期等。
  • 我们只对其标题与/BaseServlet.*?Site-102/匹配的部分感兴趣。
  • 如果一个部分的主体与/^TechnicalDifficultiesException: TD page delivered by handleThrowable/匹配,我们想要选择之前匹配的部分的主体,我们应该验证它看起来像一个java异常。
  • 我们处理整个日志文件,并返回以这种方式找到的最后一个异常。

足够公平。

#!/usr/bin/perl
use strict; use warnings;
local $/ = ""; # paragraph mode
my ($prev_sec, $prev_err);
SECTION:
while (my $head = <>) {
  my $body = <>;
  defined $body or die "Can't read from empty filehandle.";
  next SECTION unless $head =~ /BaseServlet.*?Site-102/;
  if ($body =~ /^TechnicalDifficultiesException: TD page delivered by handleThrowable/) {
    $prev_err = $prev_sec;
  }
  $prev_sec = $body;
}
die "No error found" unless defined $prev_err;
print $prev_err;

(没有真正测试那么多,但打印出你的代码片段中的错误)

单行代码有点长。如果需要,您可以随时将源代码传递给perl解释器。

perl -ne'BEGIN{$/=""}END{print$prev_err}$b=<>;defined$b or die"empty FH";/BaseServlet.*?Site-102/ or next;$prev_err=$prev_sec if $b=~/^TechnicalDifficultiesException: TD page delivered by handleThrowable/;$prev_sec=$b'

将日志文件指定为命令行参数,或将文件内容直接传递到该程序中。找到正确的日志文件并不难。在Perl的片段中:

my $log_dir = ...;
my ($log) = sort glob "$log_dir/LOG*";
die "no log in $log_dir" unless defined $log;

更新

如果还应捕获日期,则代码将更改为

#!/usr/bin/perl
use strict; use warnings;
local $/ = ""; # paragraph mode
my (@prev, @prev_err);
SECTION:
while (my $head = <>) {
  my $body = <>;
  defined $body or die "Can't read from empty filehandle.";
  next SECTION unless $head =~ /BaseServlet.*?Site-102/;
  if ($body =~ /^TechnicalDifficultiesException: TD page delivered by handleThrowable/) {
    @prev_err = @prev;
  }
  @prev = ($head, $body);
}
die "No error found" unless @prev_err;
my ($date) = $prev_err[0] =~ /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d),/;
print "$date\n\n$prev_err[1]";

并且作为单行:

perl -ne'BEGIN{$/=""}END{@perr||die"No error found";($date)=$perr[0]=~/^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d),/;print"$date\n\n$perr[1]"}$b=<>;defined$b or die"empty FH";/BaseServlet.*?Site-102/ or next;@perr=@p if $b=~/^TechnicalDifficultiesException: TD page delivered by handleThrowable/;@p=($_,$b)'

我不明白它是如何只返回第一场比赛的;此代码应处理整个文件。如果您可以提供更完整的测试用例,我可以验证此代码是否按要求运行。