rsyslogでコマンド実行をしてログに手を加える

アプリケーションで吐いたログ(標準出力)をrsyslogで拾って特定のファイルに出力する
ということをやってたりするんですが
その際にシェルを実行したかったので、そのやり方の記録です。

前提

OS: Ubuntu14.04

rsyslogとは

ログ収集や整形、転送などを行えるサービスで
数多くのLinuxディストリビューションで採用されています。

さくらさんのブログで詳しく解説していらっしゃるのでそちらを参照してください。
http://knowledge.sakura.ad.jp/knowledge/8969/

今回やりたいこと

以下のようなことがrsyslogで実現します。

$ echo -e "foo:bar\thoge:fuga"
foo:bar    hoge:fuga

$ echo -e "foo:bar\thoge:fuga" | logger -t test-app

$ cat /var/log/test-app.log
foo:bar    hoge:piyo

「fuga」文字列を、ログ出力時に「piyo」に変える というものです。

あくまで例なので、内容はしょぼいですが
要は任意の処理をログ出力時に仕込める というものです。

やり方

では実際の手順を記載していきます。

rsyslogの設定

Ubuntuでは標準に設定が入ってるかと思います。
今回の標準出力をログに出力するための設定を行います。

$ vim /etc/rsyslog.d/00-test-app.conf

$template test_logformat, "time:%timegenerated:::date-rfc3339%  %msg:2:$%\n"
module(load="omprog")

if $programname == "test-app" then {
    *.* action(
        type="omprog"
        binary="/tmp/output.sh /tmp/test-app.log"
        template="test_logformat"
    )

    stop
}

rsyslogで外部コマンドを実行する場合、「omprog」モジュールを使用します。
http://www.rsyslog.com/doc/v8-stable/configuration/modules/omprog.html

typeを「omprog」に指定後、binaryに実行スクリプトを指定します。
ここには引数も指定できますが、rsyslogのバージョンが「7.5.1」以上でないと引数が指定できません。
http://www.rsyslog.com/tag/omprog/

ubuntu14.04ではデフォルトバージョンはこれより低いと思うのであげておきましょう。

$ rsyslogd -v
rsyslogd 7.4.4, compiled with:
~

$ sudo add-apt-repository ppa:adiscon/v7-stable

$ sudo apt-get update

$ sudo apt-get install rsyslog

$ rsyslogd -v
rsyslogd 7.6.7, compiled with:
~

シェルの作成

受け取ったログの「fuga」を「piyo」に変換するシェルスクリプトを書きます。
変換だけでなく、ログ出力もしたいのでそういう感じのシェルを書きましょう。

/tmp/output.sh

#!/bin/bash

while read line; do
  echo ${line} | sed -e 's/fuga/piyo/g' >> $1
done

標準入力を待ち受けてますが、rsyslog起動時このシェルスクリプトはrsyslogdの子プロセスとして常時起動します。
なので、都度このシェルスクリプトが実行されるわけではありませんので、標準入力を待ち受けるようにしてあげます。

起動/確認

ここまで出来たらrsyslogを再起動します。

$ sudo /etc/init.d/rsyslog restart

# シェルが起動していることを確認
$ ps auxf | grep syslog
syslog   29443  0.0  0.0 193360  1460 ?        Ssl  09:28   0:00 rsyslogd
syslog   29454  0.0  0.0  17960  1420 ?        S    09:28   0:00  \_ /bin/bash /tmp/output.sh /tmp/test-app.log

では動作を確認してみましょう

$ cat /tmp/test-app.log 
cat: /tmp/test-app.log: No such file or directory

$ echo -e "foo:bar\thoge:fuga" | logger -t test-app

$ cat /tmp/test-app.log
time:2017-09-04T09:41:12.597206+00:00 foo:bar hoge:piyo

はい、というわけで、ログ出力時にシェルスクリプトを実行することが出来ました。

最後に

今回はシェルスクリプトでやりましたが、
PerlやPython、なんでも可能です。

用途としては

  • ログのフィルター
  • 文字列変換
  • 文字列付与
  • etc…

こういうのはfluentdなど使うと思いますが、
その前段階の処理として使用したりできると思います。

では!