デーモンプロセスをゆるふわ監視するときに便利な$0

たとえばデーモンがあったとします。こんな感じで。

$ ruby -rwebrick -e 'include WEBrick; Daemon.start;\
HTTPServer.new(:Port => 3000).tap{|s|\
  s.mount "/", HTTPServlet::ProcHandler.new(Proc.new{|req,res|\
    res.body = "hi"});\
  trap(:TERM){s.shutdown}\
}.start'

これで3000番でHTTPサーバが起動しました。ちょっとリクエストしてみましょう。

$ curl 'http://127.0.0.1:3000/'
hi

期待通り動きましたね。ではちょっとこのデーモンが今どんな状態なのかを監視できるようにしましょう… ってなると多分、ログをどっかにとかになりますが、もっと簡単になんとなく知る方法として$0が使えます。

ruby$0はご存知の通り現在実行しているrubyスクリプトの名前とかが入ってるんですが、これ書き換えができるんです。で、書き換えるとps(1)の値が変わ(ることがあ)ります。

先のコードをちょっと書き換えて、何回リクエストが来たか数えておきます。 そしてそれを$0に入れてみます。 あ、今度のを実行するまえに前のプロセスをkillしといて下さいね。

$ ruby -rwebrick -e 'include WEBrick; Daemon.start; $count = 0;\
HTTPServer.new(:Port => 3000).tap{|s|\
  s.mount "/", HTTPServlet::ProcHandler.new(Proc.new{|req,res|\
    $count += 1; $0 = "mydaemon: count=#{$count}"; res.body = "hi"});\
  trap(:TERM){s.shutdown}\
}.start'

新しいデーモンが起動しました。ちょっとps(1)してみます。

$ ps x|grep '[r]uby'
16046 ?        S      0:00 ruby -rwebrick -e...

あー、居ましたね。こいつです。このPID覚えておきます。で、一回リクエストします。

$ curl 'http://127.0.0.1:3000/'
hi

期待通りの結果ですね。ではps(1)はどうでしょうか。

ps x|grep '[r]uby'

ぶへ、なんも出ない。となるわけですが、これはさっき$0を書き換えたからps(1)で表示される名前が変わってるんです。こうします。

$ ps x|grep 16046
16046 ?        S      0:00 mydaemon: count=1

いたー! しかも処理したリクエスト数が見える! と、このようにps(1)でこのデーモンがどれだけリクエストを処理したかが見えますね。適当に何度か呼んでみましょう。

while true; do curl 'http://127.0.0.1:3000/'; done

それでこっそり裏でtop -cp 16046とかしてみます。おおーじわじわ増える…!

PID   ... VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
16046 ... 14556 4652 1388 S    0  0.6   0:03.42 mydaemon: count=1025

ま、こんな感じで$0を使うとゆるふわにデーモンの状態を眺められますよ、という話でした。


うまく行かない場合は環境がダメなんだと思います。実は$0ps(1)の結果を書き換えるのは環境依存なので必ずしもどんな環境でも使えるわけではありません。上記例はLinuxで実行してます。

あともうひとつ、rubyを起動する際に、この例ではワンライナー的に-eでスクリプトを渡していますが、これは実はミソで$0で書き換えられる範囲は最初にプロセスを作ったときの名前の長さまでという制約があったりします。なので場合によっては十分な長さのダミーな引数を付けたりして呼び出すと大丈夫だったりします。