1

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....

次の3つの要件を満たす例外と対応する日付をログファイルで見つける必要があります。

  1. 例外は、この静的テキストの前にある最初のものでなければなりません。

    TechnicalDifficultiesException:handleThrowableによって配信されたTDページ

  2. 例外は、「BaseServlet。*Site-102」を持つ2つの行の間に直接存在する必要があります

  3. 例外は、上記の条件を満たすログファイルの最新(最後)である必要があります。ログは定期的にロールオーバーされるため、Logの最後である必要があります。または、Log.001の最後に存在しない場合、またはLog.002の最後に存在しない場合などです。

このプログラムは多くの潜在的なサーバーの1つにSSHで接続する必要があるため、ログのあるマシンではなく、node.jsプログラムのロジックのみを維持する必要がある方がよいでしょう。したがって、perl / sed / awk / grep/etcのワンライナーが最も理想的です。

4

1 に答える 1

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)'

I don't understand how it could only return the first match; this code should process the whole file. If you could provide a more complete testcase, I could verify that this code works as required.

于 2013-02-04T22:59:50.523 に答える