パーフェクト Ruby のサンプルコードにバグを見っけた。
パーフェクト Ruby の初版、p.486 にバグを見っけた。
公式の正誤表は見当たらなかったので記事にしておく。
capistrano の capture 関数のサンプルとしてリスト 14.14 にこんな記述がある。
task :log_size_watcher do log_file = "#{deploy_to}/shared/log/development.log" ls_result = capture("ls -l #{log_file}") file_size = ls_result.squeeze.split(/ /)[4].to_i p "file size alert" if file_size > 100 end
リモートホストで ls -l を実行して、ログファイルが 100 バイトより大きくなっていたら
アラートを表示しようとしています。
ですが、このサンプルはうまく動きません。
String#squeeze しちゃダメ
サンプルコードでは ls -l の結果からファイルサイズを抜き出すときに
squeeze して split してファイル列を取り出しています。
String#squeeze はある文字列の中の連続する文字をひとつにまとめます*1。
"yellow moon".squeeze #=> "yelow mon" " now is the".squeeze(" ") #=> " now is the" "putters shoot balls".squeeze("m-z") #=> "puters shot balls"
おそらく split をする前に連続するスペースをまとめるために squeeze を呼んでいるのだと思いますが、
このとき、ファイルサイズに連続した数字が並ぶと桁が変わってしまいます。
例えば、次のようなファイルがあるとどうなるでしょうか。
$ ls -l devel -rw-r--r-- 1 tkomiya tkomiya 1000000 5月 24 20:34 development.log
なんと、ログファイルは 100バイト以上にも関わらずアラートが出力されません。
というわけで、この部分は squeeze を使わずに
file_size = ls_result.split(/ +/)[4].to_i
としてスペース複数文字で split するのがよさそうです。
そもそも。
capture 関数は先頭のサーバしか見に行ってくれないので、
複数のサーバをデプロイ対象にしていても、二番目以降のホストのログファイルチェックはしてくれません。
正しくファイルサイズをチェックするにはどうするといいんですかね。
capistrano を使って実現する場合、僕は parallel を使う方法しか思いつきませんでした。