Monit で各デーモンプロセスの死活監視、ポートの疎通監視をしています。問題は Monit が疎通監視のために接続する度に、ログが出力されることです。もちろん無害ですし、決して無意味ではありませんが、ログを読む時はとにかく邪魔です。

sshd は /var/log/secure にこんなのが出力されます。

Jun  9 08:01:33 seinolab sshd[4178]: Connection closed by 127.0.0.1 port 39828 [preauth]
Jun  9 08:03:33 seinolab sshd[4288]: Connection closed by 127.0.0.1 port 39852 [preauth]
Jun  9 08:05:33 seinolab sshd[4402]: Connection closed by 127.0.0.1 port 39876 [preauth]

postfix は /var/log/maillog にこんなのが出力されます。

Jun  9 10:57:10 seinolab postfix/smtpd[14285]: connect from localhost[127.0.0.1]
Jun  9 10:57:10 seinolab postfix/smtpd[14285]: disconnect from localhost[127.0.0.1]

rsyslog のフィルタリング機能

rsyslog には property-based filters(公式/英語) という機能があり、簡単な設定でログをフィルタリングすることができます。プロパティとはログを構成する各要素(タイムスタンプ、タグ、メッセージ本体など)のことです。これらに特定の文字列が含まれている/含まれていない時に、何かを行う、という機能です。指定可能なプロパティ一覧はここ(公式/英語)にあります。

上記の sshd のログをフィルタリングするには /etc/rsyslog.conf の #### RULES #### の下に、こんな感じで設定を追加します。

#### RULES ####
:msg, contains, "Connection closed by 127.0.0.1 port" stop

対象プロパティは msg(メッセージ本体)で、"" で囲まれた文字列を含む(contains)場合にログの出力を停止(stop)します。もうちょっと真面目に書くなら regex とすれば "" の中に正規表現が書けますが、まあそこまではしなくていいでしょう。

設定ファイルのチェックをします。

$ sudo /sbin/rsyslogd -N 2
rsyslogd: version 8.24.0-57.el7_9, config validation run (level 2), master config /etc/rsyslog.conf
rsyslogd: End of config validation run. Bye.
$ 

rsyslogd を再起動します。

$ sudo systemctl restart rsyslog
$ 

最後にログを表示させて、所望の結果が得られているかチェックします。

複数の条件を指定したい

ここまでの情報は、ネットを探すとたくさん出てきます。私が記事を書いた理由はここからです。

メッセージ本体だけでフィルタリングするのはいかにも乱暴です。sshd 以外がこのログを吐いたら、それは残しておいてほしいです。せっかくログに付いているタグもチェックできるのですから、

  • タグが sshd かつ、
  • メッセージ本体が Connection closed by 127.0.0.1 port を含むとき

という具合に条件を 2つ書けないと、property-based filters って使い物にならないぞ? と思ってやってみると…。

#### RULES ####
:programname, isequal, "sshd"
:msg, contains, "Connection closed by 127.0.0.1 port" stop

はい、できました。プロパティ programname はプログラム名(そのまんまですが、後述する落とし穴あり)、isequal は完全一致です。条件は 1行に一つしか書けないので、(2行で)2つ書けば OK です。

落とし穴回避

sshd はこれでいいのですが、postfix のログには postfix/smtpd って出てます。これが programname なの? と言うと、ちょっと違います。rsyslogd の programname の検出はちょっとアバウトなところがあるので(公式に検出ルールが書かれています)、思ったものと違ったという事態を回避するために、代わりにプロパティ syslogtag を使った方がいいです。なぜなら、syslogtag は、目に見える情報と完全に一致するからです。

プロパティ syslogtag には、私たちがイメージするタグとは少し違うのですが、postfix/smtpd[14285] のような感じでプロセス ID 込みの文字列です。これを使ったフィルタリングルールはこう書けます。

#### RULES ####
:syslogtag, contains, "sshd["
:msg, contains, "Connection closed by 127.0.0.1 port" stop

:syslogtag, contains, "postfix/smtpd["
:msg, contains, "connect from localhost[127.0.0.1]" stop

:syslogtag, contains, "postfix/smtpd["
:msg, contains, "disconnect from localhost[127.0.0.1]" stop

これできっちり、ログ出力元と、メッセージ本体の 2つの条件でフィルタリングルールを書くことができました。

おわりに

rsyslog は他にも色々な機能があります。property-based filters 以外にも、expression-based filters ではスクリプト言語で複雑なフィルタリングルールを書くこともできます。ここで取り上げた内容も、expression-based filters でできますが、やりたいことがシンプルに書けることは重要なので、あえて property-based filters でやってみました。