web-dev-qa-db-ja.com

新しいログエントリのみに作用するスクリプトの記述方法

これは簡単なことだと思いますが、理解するのに苦労しています。

Apacheログファイルの1つを監視し、特定のアクションを実行するスクリプトを記述しようとしています。しかし、どうすればログファイルを監視できますか?

ログに新しい行が書き込まれるたびに、そのエントリをチェックして、探しているものと一致するかどうかを確認し、一致する場合はxが発生するようにします。これを手動で行うときは、catまたはtail -fを使用しました。スクリプトをcron経由で30秒ごとに実行し、ログ全体(または最後の5行)を調べて、スクリプトが最後に実行されてから新しい行がどれであるかを把握したくないので、いくつかのことを行います。

ログの単一の新しいエントリのみを確認する方法はありますか?

7
karmet

Cronを介してスクリプトを実行しますが、logtailまたは logtail2 を使用してファイルを読み取ると、毎分ファイル全体が読み取られなくなります。 Logtailは最後に読み取った場所を追跡し、次にそれを使用したときにその時点にジャンプします。

Cronの呼び出しの間に最大59秒待機するのではなく、新しいログ行をすぐに処理したい場合は、tail -fまたは同等のものを使用する必要があります。

ジャンヌとハレドの答えはどちらもこの問題をうまく解決するためのものです。

5
Ladadadada

tailgrepnamed pipesなどの既存のLinuxツールを利用できます。まず、以下を使用して名前付きパイプ(fifo)を作成します。

$ mkfifo /tmp/myfifo

次に、このfifoファイルから読み取る単純なスクリプトを作成します。以下に簡単な例を示します。

#!/bin/bash
pipe=/tmp/myfifo

while true
do
    if read line <$pipe; then
        if [[ "$line" == 'quit' ]]; then
            break
        fi
        echo $line
    fi
done
echo "Reader exiting"

このスクリプトは、名前付きパイプから読み取り、 "quit"ワードを取得するまでその行をstdoutに出力します。これはカスタマイズ可能な例にすぎません。

3番目に、tailを使用して、Apacheログファイルに追加された新しい行を読み取り、出力を名前付きパイプにリダイレクトします。

$ tail -n0 -F /var/log/Apache2/access.log | grep some_text > /tmp/myfifo

-Fオプションは、ファイルを名前で追跡することを意味し、logrotateの影響を受けないようにする必要があります。したがって、常に同じファイル名に従います。 -n0は、古い行を取得しないことを意味します。 grepは、関連する行のみを送信するのに役立ちます。

このソリューションを使用すると、cronジョブは必要ありません。上記のスクリプトとtailコマンドを実行するだけです。

6
Khaled

あなたが持っている場合 syslog-ng(おそらくrsyslogdも同様に機能します)syslog-daemonとして使用できます。

Apacheログファイルを監視するように設定するか、CustomLogディレクティブとloggerを使用してログをsyslogファシリティに送信するようにApacheを設定します。

Syslog-daemonはパターンマッチングを使用し、一致が見つかった場合は$ fooを実行します。たとえば、syslog-ngでは、ログファイルフックを設定し、次のようにフィルタリングできます。

source Apache_log { file("/var/log/Apache2/access.log"); };
filter Apache_match { match("GET /evilscript.php"); };

そして、syslog-ngは外部スクリプトを呼び出します

destination Apache_logmatch_script { program("/usr/local/bin/apachematch.pl"); };

最後に、これらすべてをまとめます。

log { source(Apache_log); filter(Apache_match); destination Apache_logmatch_script); };

この手法を使用する場合、syslog-ngは新しいものが現れるのを待ってスクリプトのバックグラウンドを生成します。このため、STDINからの入力を待機するようにスクリプトを変更する必要があります。これは短いPerlの例です:

#!/usr/bin/Perl -w

$|=1;
while (<>) {
     printf "Stuff happened, I got this entry: %s!\n", $_;
}

あなたがこのテクニックを試してみたいと思うまで、私は返信を深く掘り下げません。

3

あなたが読んだ最後の行の記録を保持することができます。新しい実行ごとに、最後の+1行からファイルの終わりまで読み取り、レコードを更新します。

ただし、ログファイルはローテーションされる可能性があることに注意してください。したがって、たとえばiノード番号の記録を保持する必要があります。

fail2ban 希望どおりの方法でログファイル監視を実装します。多分それを見てください?いくつかのアイデアを借りるか、実際に使用することができます。

1
Jonathan

Diffを使用できます。ログファイルを一時ファイルにコピーします。

ライブログファイルと一時ファイルの差分を取ります。

結果の差分でパターンマッチングを実行します。

Nagios check_logプラグインからのアイデア。詳細は http://www.kilala.nl/Sysadmin/index.php?id=715 を参照してください。

0
dmourati

Fail2banがニーズに合わない場合は、Markus J. Ranumによって記述された flog.c を変更してみてください。

"この小さなユーティリティは、" tail -f "と同等ですが、実行中にログローターがファイルをユーザーの下から移動した場合に、ファイルの変更を処理するのに十分スマートです。また、" tail -f "このプログラムは、ユーザーがログアウトしたときに終了するほどスマートであり(!)、ログをptyに永久に送り出すことはありません。エレガンスやパフォーマンスは向上しません。"

新しい行が目的のパターンと一致するかどうかを確認するように変更して、それに応じて動作させることができます。

0
adamo

pythonソリューションが必要な場合は、Pygtailを確認してください: https://github.com/bgreenlee/pygtail

logchecklogtail2ツールに基づいています

0
s g
#!/bin/bash

while read line;
do
      echo $line > /tmp/output.log
      mail -s 'Event Msg.' '[email protected]' < /tmp/output.log
done < <(tail -n0 -F /var/adm/messages)
0
ramon