Un nouveau monde parfumé

香り立つ備忘録

特定のログが流れてきたときにコマンドを実行するやつをシェルスクリプトで書く

ログファイルの中身を追跡して、特定の文字列が流れてきたことを検知してコマンドを実行したい、ということがあり、

tail -n0 -f $1 | while read line
do
    if [[ $line =~ 正規表現 ]]
    then
        echo '(∪^ω^)わんわんお!'
        # do something else
    fi
done

こんな感じの watchdog じみたものを書いた。

しかし、ログファイルはローテートされるものである。しかも、監視対象のシステムは一定のタイミングで別名のファイルを新たに作成しそちらに書き込み始めるという挙動を行っていた(すなわち、tail --follow=nametail --follow=descriptor による追跡は行えない)。

というわけで上記処理をシェル関数に切り出し、別の while : ループからバックグラウンドタスクとして & つけて実行、一定期間 sleep したのちそのタスクを kill して新しいファイル名を与えて実行しなおす、という感じにしたのだが、何がいけないのかプロセスを殺しきれず2重に処理を実行してしまうことがあった。親プロセスから逃れて PID1 に匿われる様子はさながら逃げ出した犬である。

結果的に上記 tail ループを watchdog-worker.sh として切り出し、dumb-init 経由で起動する形にすることで問題を解決した。

# watchdog-master.sh
SCRIPTDIR=$(cd $(dirname $0); pwd)

get_latest_logfile() {
}

while :
do
    file=$(get_latest_logfile)
    dumb-init $SCRIPTDIR/watchdog-worker.sh $file &
    pid=$!
    # 5分でリロード
    sleep 360
    kill $pid 
done

watchdog-worker.sh 側の while ループをコマンド実行後に break するようにすれば若干クールダウンタイムっぽいものを設けることもできた。今のところはそれでどうにかなっている。