#378 FnordMetric
FnordMetricを使うと、Railsアプリケーションで、ユーザの活動などのイベントをリアルタイムにトラックしたりグラフ化することが可能になります。インタフェースがすっきりとしていて、作成されたグラフを簡単にブラウズできます。今回のエピソードでは、その設定方法とRailsアプリケーションに統合する方法の基本を紹介します。
FnordMetricを使う
FnordMetricはイベントの保存にRedisを利用するので、まずそれをインストールします。OS Xを利用しているのであれば、Homebrewを使うのが一番簡単でしょう。
$ brew install redis
インストールが完了したら、以下のコマンドで起動します。
$ redis-server /usr/local/etc/redis.conf
Redisが起動したので、FnordMetricの設定をREADMEについているサンプルを使って行ないます。この記事の執筆時点では、このページのsimple exampleには何らか問題があるようなので、full exampleの方を使います。新規にfnordmetric.rb
というファイルを作成し、そこにこのサンプルのコードをペーストします。長すぎるのでここに表示はしませんが、Githubのここで確認できます。これを実行する前に、FnordMetric gemをインストールする必要があります。インストールが終わったらサンプルを実行してみます。
$ gem install fnordmetric $ ruby fnordmetric.rb >> Thin web server (v1.3.1 codename Triple Espresso) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:4242, CTRL+C to stop [12-09-26 17:54:46] listening on http://0.0.0.0:4242 [12-09-26 17:54:46] listening on tcp://0.0.0.0:2323 [12-09-26 17:54:46] worker started
このスクリプトが実行されると、いくつかのポートが待機状態になります。Webアプリケーションが4242番ポートで待機し、新規のイベントを2323番ポートにpostすることができます。localhost:4242
にアクセスすると、各種のイベントについてのグラフが表示されているWeb画面が表示されます。これらのグラフ用のデータはスクリプトによって生成され、グラフはリアルタイムで更新されます。左側のパネルのリンクをクリックすると他のグラフが表示されますが、その例を後で紹介します。
このスクリプトのコードを見てみると、画面に表示されるgaugeを定義するために準備されたDSLがあります。イベントを生成するにはeventを呼び出してブロックを渡します。するとFnordMetricがこのイベントに対して待機状態になり、ブロックのコードで定義されたグラフを更新します。
event :search do observe :popular_keywords, data[:keyword] endTowards the bottom of this script we can see how the events are populated. fnordmetric.rb def start_example_data_generator api = FnordMetric::API.new Thread.new do loop do api.event(:_type => :signup, :referrer => (rand(3) == 1 ? :twitter : :facebook)) api.event(:_type => :search, :keyword => (%w(Donau Dampf Schiff Fahrts Kaptitaens Muetzen Staender).shuffle[0..2] * "")) api.event(:_type => :user_demography, :age => rand(15..85), :gender => (rand(2)==1 ? :female : :male) ) sleep (rand(10)/10.to_f) end end end
ここではFnordMetric::API
クラスの新規インスタンスを生成し、event
を呼び出してイベントを起動します。これに対して、イベントに関して定義した属性の一つである_type
と、その他の必要な属性を渡します。このコードはこれらのイベントをループしながらランダムな間隔で呼び出します。
RailsアプリケーションにFnordMetricを追加する
FnordMetricの基本機能が理解できたところで、次に商品リストを扱う簡単なRailsアプリケーションに統合する方法を見ていきます。
各商品のページが閲覧された回数をトラックしようと思います。ページが閲覧されたらイベントをFnordMetricに送信し、この情報を各種のグラフに表示できるようにします。そのためにはまずgemfileにfnordmetric
gemを追加して、bundle
コマンドを実行してインストールを行ないます。
gem 'fnordmetric'
次にFnordMetricを設定するための初期化ファイルを新規に作成します。FnordMetric::API
の新規インスタンスを作成して定数に割り当て、Railsアプリケーション内のどこからでもアクセスできるようにします。
FNORD_METRIC = FnordMetric::API.new
これがRedisデータベースに対して新規の接続を開き、直接イベントを挿入します。これは、2323番ポートからイベントを追加するよりも効率的です。次にProductsController
のshow
アクション(個別の商品の情報を表示するページ)の中でイベントを起動します。
def show @product = Product.find(params[:id]) FNORD_METRIC.event(@product.attributes.merge(_type: :view_product)) end
イベントを起動するためにFNORD_METRIC.event
を呼び出して必要なパラメータ(今回の場合は商品の属性)を渡します。イベントに名前をつけるために_type
属性も同時に渡すことに留意してください。商品ページにアクセスするたびにRedisにイベントが追加されます。次にFnordアプリケーションを設定してこのイベントを待機するようにし、gaugeを調整する必要があります。これを行なうRubyスクリプトを作成してアプリケーションのルートディレクトリに置きます。
require "fnordmetric" FnordMetric.namespace :store do toplist_gauge :popular_products, title: "Popular Products" event :view_product do observe :popular_products, data[:name] end end FnordMetric::Web.new(port: 4242) FnordMetric::Worker.new FnordMetric.run
ここでfnordmetric
をrequireしてstore
という名前空間を定義し、そこでgaugeを定義することができます。そしてWeb
とWorker
を起動します。イベントを直接Redisに追加するのでacceptorは起動しない点に注意してください。使用できるgaugeのタイプがいくつかあり、ここではtoplist_gauge
を使用して人気商品を表示します。それでは、view_product
イベントを待機する新規のイベントリスナーを作成します。これは、先ほど設定したpopular_products
のgaugeを監視します。このリスナーに対して商品名を、コントローラで渡した商品の属性を含むdata
ハッシュの形式で渡します。
ruby fnordmetric_app.rb
を実行してFnordMetricアプリケーションを起動して、ブラウザでgaugeを見てみます。まだイベントが発生していないのでページには何も表示されていません。ブラウザで適当な商品ページにアクセスして左側のパネルの“Popular Products”をクリックすると、今までに閲覧した商品が表示されます。
これらのイベントを手動で起動させるのは面倒なので、これを行なうRakeタスクを設定して実際のユーザの動きをシミュレートします。その前にFnordMetricイベントトリガーをコントローラからProduct
モデルに移動させます。これによってコントローラが多少整理され、Rakeタスクからイベントを起動できるようになります。モデル内にtrigger_view_event
という新規のメソッドを作成して、コントローラから呼び出します。
def show @product = Product.find(params[:id]) @product.trigger_view_event end
次にモデル内に次のメソッドを新規に作成します。
def trigger_view_event FNORD_METRIC.event(attributes.merge(_type: :view_product)) end
これでRakeタスクを作成することができます。
namespace :fnordmetric do desc "Populate FnordMetric with events to simulate user activity" task :populate => :environment do products = Product.all loop do products.sample.trigger_view_event sleep(rand) end end end
これはシンプルなRakeタスクで、Railsの環境をロードして商品に対して、0〜1秒間隔でランダムにスリープしながら連続してビューイベントを起動します。ここで作成したRakeタスクを起動するとバックグラウンドで実行されます。
$ rake fnordmetric:populate
gaugeをリロードすると、より多くの追加されたイベントが表示され、商品の人気の上り下がりを見ることができます。
次に別のgaugeを追加して、どの価格帯が最も人気があるかを表示します。そのためには、distribution_gauge
を追加して、それにtitle
と価格帯の配列を渡します。このgaugeも監視する必要があります。
require "fnordmetric" FnordMetric.namespace :store do hide_active_users toplist_gauge :popular_products, title: "Popular Products" distribution_gauge :popular_prices, title: "Popular Prices", value_ranges: [0..5, 5..10, 10..20, 20..50, 50..10000] event :view_product do observe :popular_products, data[:name] observe :popular_prices, data[:price] end end FnordMetric::Web.new(port: 4242) FnordMetric::Worker.new FnordMetric.run
このファイルに、hide_active_users
の呼び出しも追加しました。これによって、不要になった左パネルのActive Usersのメニューオプションを外します。このスクリプトの変更を反映するため一度終了して再起動します。すると“Popular Prices”のグラフが表示され、クリックするとページの訪問数に基づいてもっとも人気の商品が表示されます。
最後にリストに1秒間の閲覧数を表示するgaugeを追加します。
FnordMetric.namespace :store do hide_active_users toplist_gauge :popular_products, title: "Popular Products" distribution_gauge :popular_prices, title: "Popular Prices", value_ranges: [0..5, 5..10, 10..20, 20..50, 50..10000] gauge :product_views_per_second, tick: 1.second widget "Product Views", title: "Views per Second", type: :timeline, width: 100, gauges: :product_views_per_second, include_current: true, autoupdate: 1 event :view_product do observe :popular_products, data[:name] observe :popular_prices, data[:price] incr :product_views_per_second end end
これは、1秒ごとに更新される汎用的なgaugeを生成します。このようなgaugeを作成した場合は、通常は同時にwidget
を追加して表示方法を定義します。view_product
イベントを受け取るごとにこのgaugeを更新したいので、incr
を使ってgaugeの数値を記録します。スクリプトを終了して再起動すると、商品が閲覧されるごとに自動的に更新されるproduct views widgetが表示されます。
FnordMetricの紹介は以上です。今はまだドキュメントが整備されていない状況ですが、Railsアプリケーションでイベントをトラックしたい場合には導入を検討する価値があるでしょう。