Logwatch で独自の通知を追加するメモ

Logwatch とは

  • Logwatch
  • 日次でシステム内のさまざまなログから見つかった問題を通知する
    • /etc/cron.daily/0logwatch で実行される
  • デフォだと root へのメールで通知される
  • デフォでいろいろなログの通知が組み込まれている
    • ls /usr/share/logwatch/scripts/services/

独自の通知の追加

例えば oreore というサービスのログを追加することにします。

ログファイルの設定

oreore のログファイルに関する設定を追加します。

/etc/logwatch/conf/logfiles/oreore.conf

LogFile = oreore.log
LogFile = oreore.log-*[0-9]
Archive = oreore.log-*.gz

LogFile にはログファイル名を glob 形式で指定します。パスは /var/log/ からの相対です。このディレクトリ以外のログを指定したい場合は絶対パスで指定します。

Archive には gzip でアーカイブされたログファイルを指定します。ただ、この設定は普段は使われません(logwatch の実行時のオプションでアーカイブされたログも走査するかのオプションがあるけどデフォで指定されていない)。

また、通常はこの設定ファイルでログファイルを日付でフィルタするための設定を記述します。例えば syslog 形式のログであれば次のように記述すれば日付でフィルタされます。

*ApplyStdDate

この記述によって /usr/share/logwatch/scripts/shared/applystddate にログファイルがパイプされるようになります。

他にも /usr/share/logwatch/scripts/shared/ ディレクトリにあるスクリプトを指定することができます。ログファイルに独自の処理を行いたい場合は下記のディレクトリにスクリプトを配置します。

  • /etc/logwatch/scripts/logfiles/oreore/

このディレクトリに配置したスクリプトは oreore のログの走査時に自動的に適用されます。

例えば次のような内容で作成します。

/etc/logwatch/scripts/logfiles/oreore/applydate

use Logwatch ':dates';

my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0;

my $SearchDate = TimeFilter('\[%Y-%m-%dT%H:%M:%S\]');

if ( $Debug > 5 ) {
    print STDERR "DEBUG: Inside oreore..\n";
    print STDERR "DEBUG: Looking For: (" . $SearchDate . ")\n";
}

while (defined($ThisLine = <STDIN>)) {
    if ($ThisLine =~ s/^$SearchDate\s+//o) {
        print $ThisLine;
    }
}

既存のスクリプトからほとんどコピペです。Logwatch モジュールの TimeFilter を使えば日時でフィルタするための正規表現を簡単に作ることができます。例えば↑の例だと $SearchDate\[2016-04-14T..:..:..\] のようになります。

この例では perl でスクリプトを作成していますが、シェバングを書けばそのインタプリタで実行されるので、好きな言語で作成することができます。

サービスの設定

oreore のサービスに関する設定を追加します。

/etc/logwatch/conf/services/oreore.conf

Title = "oreore report"
LogFile = oreore

Title は通知のレポートで使われるサービスの名称です。

LogFile には↑で設定したログファイルの設定名を指定します。この例ではログファイルとサービスで同じ oreore という設定名ですが、例えばこのサービスが /var/log/messages にログを出すようになっているのなら LogFile = messages と指定したりすることもあります。

また、ログファイルの設定と同じように、フィルタを下記のように記述することができます。

*Remove = "^(DEBUG|INFO):"

指定できるものはログファイルの設定と同じです(/usr/share/logwatch/scripts/shared/ のスクリプト)。

最後に、レポートを出力するためのスクリプトを /etc/logwatch/scripts/services/oreore に作成します。ログファイルの設定やサービスの設定によってフィルタされたログが標準入力から入ってくるので、それっぽい出力にしてやれば OK です。

例えば、単にそのまま流すだけですが、次のような内容です。

/etc/logwatch/scripts/services/oreore

while (defined($ThisLine = <STDIN>)) {
    print $ThisLine;
}

もちろん perl 以外でも作成できるので、そのまま流すだけなら下記で十分です。

#!/bin/bash
cat

環境変数

ログファイルやサービスの設定ファイルで次のように変数を記述すると、

$oreore_value = 123

スクリプトで環境変数として取り出せます。

my $oreore_value = $ENV{'oreore_value'} || 0;

変数名に大文字を用いてもすべて小文字に置換されます。

ログファイルの設定ファイルで記述した変数は、ログファイルとサービスの両方のスクリプトで有効になります。ただ、見た感じ既存のログファイルの設定ファイルで変数が記述されているものはありませんでした。

サービスの設定ファイルで記述した変数は、サービスのスクリプトのみで有効になります。

動作確認

次のように環境変数を設定しつつログファイルからスクリプトをパイプしていくと最終的な出力が得られます。

export LANG=C PERL5LIB=/usr/share/logwatch/lib/ LOGWATCH_DEBUG=9 LOGWATCH_DATE_RANGE=today
sudo cat /var/log/oreore.log |
  perl /etc/logwatch/scripts/logfiles/oreore/applydate |
  perl /usr/share/logwatch/scripts/shared/remove "^(DEBUG|INFO):" |
  perl /etc/logwatch/scripts/services/oreore

切り貼りすれば途中までの結果を出力したりもできるのでデバッグが捗ります。

最終的な動作確認には 次のように logwatch を実行します(CentOS 7)。

sudo logwatch --service oreore --output stdout --range today

CentOS 6 だと --output オプションが無くて、代わりに --print を使います。

sudo logwatch --service oreore --print--range today

フィルタ

ログファイルやサービスの設定で指定可能なフィルタ(/usr/share/logwatch/scripts/shared/ のスクリプト)には以下のようなものがあります。

  • applybinddate
  • applyeurodate
  • applyhttpdate
  • applystddate
  • applytaidate
  • applyusdate
  • applyvsftpddate
    • 日付でフィルタ(ログファイルの形式により様々)
  • eventlogonlyservice
  • eventlogremoveservice
    • 謎・・MSWinEventLog とかいう記述が見えるけど
  • expandrepeats
    • last message repeated 10 times のように省略されたログを展開
  • hosthash
    • 謎・・syslog 形式のログからホスト名の一覧を出力するっぽいけど
  • hostlist
    • 謎・・syslog 形式のログからホスト名の一覧をテンポラリに書き出すっぽいけど
  • multiservice
    • syslog 形式のログで特定のサービスの以外の行を除去
    • *RemoveService = ntpd,ntpdate のように引数をカンマ区切りで指定する
  • onlycontains
    • 指定されたパターンにマッチする行のみを抽出
    • *OnlyContains = ^(ERROR|WARN): のように正規表現で指定する
  • onlyhost
    • syslog 形式のログで特定のホストの行のみを抽出
    • ホスト名は logwatch.confHostLimit または引数で指定する
    • logwatch.conf で指定するときはカンマ区切りまたは正規表現で指定する
      • カンマの有無で意味が変わる
    • 引数で指定するときは正規表現で指定する
  • onlyservice
    • syslog 形式のログで特定のサービスの行のみを抽出
    • *OnlyService = (spamd|sendmail) のように引数を正規表現で指定する
  • remove
    • 指定されたパターンにマッチする行を除去する
    • *remove = ^(DEBUG|INFO): のように正規表現で指定する
  • removeheaders
    • syslog 形式のログのメッセージ以外の部分を削除
    • Apr 13 23:20:01 localhost systemd: hogehoge -> hogehoge
  • removeservice
    • syslog 形式のログで特定のサービスの行を除去
    • *RemoveService = anacron,cron のように引数をカンマ区切りで指定する

詳しいことは less /usr/share/doc/logwatch-*/HOWTO-Customize-LogWatch で。

参考

全部自分の記事だけど・・