特定のログが流れてきたときにコマンドを実行するやつをシェルスクリプトで書く
ログファイルの中身を追跡して、特定の文字列が流れてきたことを検知してコマンドを実行したい、ということがあり、
tail -n0 -f $1 | while read line do if [[ $line =~ 正規表現 ]] then echo '(∪^ω^)わんわんお!' # do something else fi done
こんな感じの watchdog じみたものを書いた。
しかし、ログファイルはローテートされるものである。しかも、監視対象のシステムは一定のタイミングで別名のファイルを新たに作成しそちらに書き込み始めるという挙動を行っていた(すなわち、tail --follow=name
や tail --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
するようにすれば若干クールダウンタイムっぽいものを設けることもできた。今のところはそれでどうにかなっている。