Linuxで指定時間内にログに特定の文字列が現れるかどうかをコマンドで監視する(ReadyMediaのDB更新バッチ)2019/06/17LinuxReadyMedia(MiniDLNA)以下の記事にReadyMediaでミュージックストリーミングサーバを構築する手順を書きました。ReadyMediaは、新しい音楽を新規追加してもサムネイルが自動登録されません。追加の都度DBの更新が必要になります。それをバッチ化したのでメモ。ログを監視してシェルスクリプトによる非同期処理の待ち合わせを行っています。minidlnaで再度起動してあげる必要があります。ReadyMediaのDB再作成の終了をどうやって検知するか普通のアプリケーションだと、DBの再作成プロセスはDBの再作成が終わったら勝手に落ちてくれることが多いのかと思いますが、ReadyMediaはそうではありません。ログを監視してDBの再作成が終わった段階でそのプロセスを強制的に殺すようにします。-Rコマンドを打つとこんなログが出ます。/proc/sys/fs/inotify/max_user_watches.12345678以下のような流れになっています。検索終了!というワードが出るので、これを検知したタイミングでプロセスを殺してやればいいですね。作成したDB更新バッチの内容こんなのを作りました。一般ユーザとしてこのシェルスクリプトを起動します。その実行ユーザには下記バッチで実行するコマンドのみパスワードなしでsudoできる権限を/etc/sudoers/にて付与しています。-xeでエラー時にバッチを即終了させるという設定にします。minidlnaでReadyMediaをsytemd経由で起動します。'検索終了!がミソです。ここでステータスコード0以外のコードが返ってくるとこのバッチは即終了しますが、ReadyMediaは幸か不幸か-Rオプションでサーバプロセスとしても稼働しているため、サービス自体は継続可能です(たまたまそうなっただけですが)。grepで指定時間内にログに特定の文字列が現れるかを監視する以下、それぞれのコマンドの意味です。timeoutコマンドタイムリミットを設けてコマンドを実行するコマンドです。何らかの理由でDB更新が完了せず、永遠にログを監視し続けてしまうことを防ぎます。タイムリミット中にコマンドが完了しなかったら、ステータスコード124を返して実行したコマンドのプロセスにSIGTERMを送ります。SIGTERMでプロセスを殺せなかったら、SIGKILLを送ります。ステータスコードは128+9で137になります。タイムリミット中にコマンドが完了した場合、ステータスコードは実行したコマンド自身のステータスコードを継承して返します。-Fコマンドおなじみtailコマンド。-nオプションは、おなじみファイルの末尾何行を表示するかを指定するオプションです。このオプションを0行として、-fもしくは-Fオプションと組み合わせると、そのファイルの監視を開始してから新しい行が末尾に追加されるとそれを表示する、という動作をします。追加されない限りは何も表示されません(0行なので)。-Fオプションは、おなじみファイルを監視し続ける-fオプションとほぼ一緒ですが、ログローテート等なんらかの原因でinodeが変わった際に、それを検知して同名のファイル(新しいinode)を開きなおす、という動作をします。access_log-20190617)を監視し続けます。–line-bufferedコマンドこちらもおなじみgrepコマンド。んですが、私が動作検証したところ、「指定の行数だけマッチした後に、何らかの行が入力されると読み込みを終了する」という動作をしました。パイプだと違う挙動をするよって書いてあるからそれですかね(どう違うのかは書いていない......)。指定の行数にマッチさえしていれば、そのあとに何の行も入力されなくてもステータスコードは0になります。--line-bufferedオプションは、ストリーム全体をバッファするのではなく行単位でバッファをするオプションです。これをつけないとある程度まとまった行数、もしくはファイル全体に対してgrepがかけられるので、検索が遅延したりまったくひっかからなかったりします。パイプで連結したコマンドのステータスコードについて$?だとパイプで連結された一番右側のコマンドのステータスコードしか取れません。パイプ前後のコマンド全てのステータスコードがとりたければ、$PIPESTATUSを使います。これは配列なので、複数パイプを使っている場合は$PIPESTATUS[0]や、$PIPESTATUS[@]という書き方ができます。動作検証の過程で覚えました。今回の例で$PIPESTATUSを見ると面白かったので載せておきます。ちなみに$PIPESTATUSは拡張POSIXであり、bashやzshでしか使えません。grepで1行マッチした後にログファイルに何も書き込まれなかった場合grepは-mオプションで指定の行マッチすればステータスコードは0です。先ほど述べたように、マッチした後に何らかの新しい行が入力されない限り、grepは検索をやめません。そのため、grepコマンドは正常終了、timeoutコマンドはタイムアウトのステータスコード124となります。grepで1行マッチした後にログファイルに新しい行が書き込まれてgrepがその場で終了した場合grepは正常終了しているのでステータスコード0です。timeoutコマンドは128+13で141というステータスコードになっています。シグナル13ってPIPE「読みこまれないパイプへの書き込み」なんですね。grepのプロセスが落ちたところにtailがパイプ経由で書き込もうとしてエラーで死んでる感じです。grepがマッチしなかった場合timeoutコマンドはタイムリミット内に完了しなかったためステータスコード124を、grepコマンドはtimeoutコマンドによりSIGTERMされたため128+15のステータスコードとなっています。ちなみに、このバッチは今Jenkinsに仕込んで動かしています。