こんにちは
今朝herokuからwebinarの案内が来ていました。日本時間だと午前2時からのWebinarなんで多分スルーなんですが(^^;;;、アジェンダの中にたまたま目にとまった1行がありました。
•Using heroku-pg-extras to gain visibility into database performance
「heroku-pg-extras」って何じゃい?と思って検索したところ予想通りGitHubでソースが見つかりました。(^^v
https://github.com/heroku/heroku-pg-extras
ふむふむ。postgresqlの統計情報ビューからSELECTした結果をコマンド一発で表示するプラグインなのね。
ここで実行されているSQLがどういう時に有用なのかはよくわかりませんが。。。(^^;
ソースの方も見ましたが中身は単純にSQLを発行しているだけなんで、自分用にカスタマイズするのも簡単そうです。
□□□□
だいたい内容はわかったので、興味を失いかけたところでふと気がつきました。
あれ?これちょっとカスタマイズすれば。。。
heroku myapp:user_count heroku myapp:sales
みたいな感じで個別案件で欲しい情報がコマンド一発でとれるプラグインが作れるんじゃね?
改めてソースを眺めてみたところ多分簡単にできるんじゃないかと思ったので、ちょっと試してみました。
★gitリポジトリをコピる
herokuコマンドのプラグイン拡張は直接gitから必要なモジュール一式を引っこ抜くという大胆な構成をしています。つまり、pluginを作成するにはgitリポジトリが必要です。
通常ならGitHubを使えば良いんですが、今回は個別案件専用のプラグインなのでBacklogのgitを使いました。
git clone git@github.com:heroku/heroku-pg-extras.git git remote rm origin git remote add origin xxx@xxx.git.backlog.jp:/xxx-project/myapp-sqlplugin.git git push origin master heroku plugins:install xxx@xxx.git.backlog.jp:/xxx-project/myapp-sqlplugin.git heroku pg:cache_hit
pluginのインストールがGitHub以外からでも行えるかどうかイマイチ確信がなかったんですが、特に問題ないようです。
ちなみにプラグイン名はGitのリポジトリ名(上の例の場合は「myapp-sqlplugin」)になるようです。
★案件用にカスタマイズする
とりあえずpg-extrasを別の名前でプラグインとしてインストールすることに成功したのでここから案件用にカスタマイズしていきます。
pg-extrasは「heroku pg」にコマンドを追加するという形で実装されているんですが、個別案件用の名前として「pg」はふさわしくないのでまずはコマンド名を変更してみます。
class Heroku::Command::Pg < Heroku::Command::Base ↓ class Heroku::Command::Myapp < Heroku::Command::Pg
クラス名がコマンド名だろうというのは単なる勘です。消去法でここしかそれらしいところが無いので多分そうだろうという。。。(^^;;;
最初は継承元のクラスをBaseのままにして試しましたが、それだと動きませんでした。まぁpostgresqlを使うためのするためのprivateメソッドが何かあるんでしょう。継承元をPgに変更したところ見事「heroku myapp:cache_hit」というコマンドで動作するようになりました。(^^v
★pluginsディレクトリで直接修正してみる
ところで先の修正は最初にcloneしたgitリポジトリで行っていました。これはherokuコマンドの参照するプラグイン本体ではないので修正内容をプラグインに反映させるためには以下のコマンドを叩く必要があります。
git add . git commit -m "Modify class name" git push origin master heroku pugins:update myapp-sqlplugin
一度修正内容をgitにpushして「heroku plugins」コマンドでそれを取り直す必要があるわけです。まぁめんどくさいです。
トライ&エラーで修正している時にはこんな手順踏んでられないので、Herokuのプラグインディレクトリで直接修正することにしました。
Windowsの場合はHerokuプラグインは
<ユーザーホーム>/.heroku/plugins
にあります。「heroku plugins:update」コマンドは要するにここで「git pull」を実行しているだけなので、ここを修正のワークにしても特に問題ないはずです。
これでソースを修正したらすぐに動作確認ができるようになりました。(^^v
★案件用のコマンドを追加してみる
ソース眺めると一目瞭然でコマンド追加方法は見当がつくんですが、例えばユーザー数をカウントするコマンドの追加は以下のようになります。
def user sql = %q( SELECT count(*) AS user_count FROM user_table ) puts exec_sql(sql) end
要するにpublicメソッドがそのままコマンドになって、putsで結果を出力しているだけなんですね。
コマンド追加で修正するのはほとんどSQLだけなので、僕のようにRubyにあんまり詳しくなくても特につまることなく修正、動作確認までできました。(^^v
元々あるcache_hitなどのコマンドは使わないのであれば削除してしまってOKです。
★オプション引数を追加してみる
例えば売上取得のSELECT文なんかでは年、月をパラメータで指定したいわけですよ。
ここまですこぶる快調に実装できてきたので、あとはパラメータを使用するサンプルだけ書いて、残りは案件担当者に自分で必要なSQLを追加してもらえば良いかと思っていたんですが、最後の最後ではめられました。(--
というか、やり方が分かった時には「こんなんアリかよ。。。」とかなりの衝撃を受けたんですが、これがRuby界隈ではわりと普通のことなのかそれともHerokuの独自仕様なのかを是非とも知りたいです。
□□□□
以下、その内容です。ソース見てると引数は「option[:xxxx]」または「shift_argument」で取得するらしいということはすぐにわかりました。
前者はオプション引数「--xxxx」で指定した内容に相当し、後者はオプションなしの引数に相当します。(「shift_」の名前が示すように実行するとポインタがずれるので2回目の実行では2つ目の引数が取れ最後はnilになります。)
今回の場合はオプションで年、月を指定したかったのでとりあえずこんなコードを書いてみました。
def test month = options[:month] puts month end
引数「month」を出力しているだけ。
これで「heroku myapp:test --month 7」と叩いた時に「7」が出力されるかなぁと期待したんですが。。。
残念ながら何も出力されません。どうやらどこかで有効なオプションを登録する必要があるようです。
まぁlogsコマンドの「--tail」みたいに引数を取らないオプションもあるわけだし、それは予想の範疇です。
。。。が!
どこのソースを見てもGREPかけてもどうにもそれらしいところが見つかりません。
また、調べているうちにさらなる疑問もわいてきました。
例えば「--tail」はエイリアスとして「-t」としてもOKですが、この情報もどこにも書かれていない気がするんですよね。。。
確かに各種コマンドのコメントには引数として何が使えるかということが全部書かれて入るんですが。。。
。。。コメント。。。
コメントはコメントですよ。。。
しかし他にそれらしいところが無い。。。
# -m, --month MONTH # month
def test
month = options[:month]
puts month
end
heroku myapp:test --month 7
りたーん
7
マジでかーーーー!!!
heroku myapp:test -m 7
りたーん
7
本気かーーーー!!!!
気付くか!?こんなもーーーん!!!(--
□□□□
。。。Rubyな人達はこれ見当つくもんなんでしょうか。。。(--
それともDSLとかそっち系の文化???
いずれにしても結構な衝撃でした。コメントはコメントではないかもしれない。ということをこれからは頭に入れておくべき???(いや、ないだろ。。。(--)
さらにざっと調べたところ「heroku help」コマンドが出力しているヘルプがメソッドのコメントをそのまま出力しているだけということがわかりました。多分その辺りのコードでオプション引数を解析して登録しているんでしょうね。
これで引数つきのSQL実行コマンドもめでたく作成できたわけですが、そこはもはやどうでもいい気がするので割愛します。
今回SELECTしか試してませんが多分INSERTやUPDATEも問題ないでしょう。
ちなみにこれに関するドキュメント(というかプラグイン開発全般)はDevCenterのどこにもない気がします。