FnordMetric allows us to track and chart events, such as user activity, in realtime in a Rails application. It has a clean interface and allows us to easily browse the charts it generates. In this episode we’ll show you the basics of getting it set up and integrated with a Rails app.
Getting Started With FnordMetric
FnordMetric uses Redis to store its events so we’ll first need to install that. If you’re running OS X this is most easily done through Homebrew.
$ brew install redis
Once this has installed we can start it up by running this command:
$ redis-server /usr/local/etc/redis.conf
Now that we have Redis up and running we’ll set up FnordMetric using an example provided in its README. At the time of writing there appear to be some issues with the simple example on this page so we’ll use the full example instead. We’ll create a new Ruby file called
fnordmetric.rb and paste the code from this example into it. This is too long to show here, but can be seen on Github. Before we can run it we’ll need to install the FnordMetric gem. We can then run the example script.
$ 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
When run this script it will start listening on a couple of different ports. Its Web application will start listening on port 4242 while we can post new events to port 2323. If we go to
localhost:4242 we’ll see the Web interface which will show charts for various events. The data for these charts is generated by the script and the charts update in realtime. Clicking the links in the left panel will show other charts and we’ll see examples of these later.
If we look at some of the code in this script we’ll see the DSL that’s provided for defining the gauges that appear in the UI. To create an event we call event and pass it a block. FnordMetric will then listen to this event and update the chart as determined by the code in the block.
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
Here we create a new instance of the
FnordMetric::API class and call
event on it to fire an event. We pass this a
_type, which is one of the types we’ve defined with event, and any other attributes that we want to send. The code here repeatedly lops through these events and calls them at random intervals.
Adding FnordMetric to a Rails Application
Now that we understand the basics of how FnordMetric works we’ll see what’s involved in integrating it into a simple Rails application that handles a list of products.
We want to track how often each product’s page is viewed. When this happens we’ll send an event to FnordMetric so that we can display this information in various charts. To start we’ll need to add the
fnordmetric gem to the gemfile and run
bundle to install it.
Next we’ll create a new initializer file where we can set up FnordMetric. All we need to do is create a new instance of
FnordMetric::API and assign it to a constant so that we can access it anywhere in our Rails application.
FNORD_METRIC = FnordMetric::API.new
This will open a new connection to the Redis database and will insert events into it directly. This is more efficient than adding events through port 2323. Next we’ll trigger an event inside the
show action which is the page that displays information about a single product.
def show @product = Product.find(params[:id]) FNORD_METRIC.event(@product.attributes.merge(_type: :view_product)) end
To trigger the event we call
FNORD_METRIC.event and pass the parameters we want to pass in, in this case the product’s attributes. It’s important that we also pass in a
_type attribute so that we can give the event a name. Whenever we visit a product’s page now it will add an event to Redis. Next we need to set up a Fnord app to listen to this event and adjust any of the gauges and we’ll create a Ruby script at the root of our application to do this.
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
Here we require
fnordmetric and then define a namespace called
store where we can define our gauges. We then start up a
Web and a
Worker. Note that we don’t start an acceptor as we’ll be adding events directly into Redis. There are several types of gauges that can be used and we’ve used a
toplist_gauge where we show the popular products. We then make a new event listener that listens to the
view_product event. This observes the
popular_products gauge that we’ve just set up and which we pass the name of the product through the
data hash which contains the product’s attributes that we passed in in the controller.
We can now start up our FnordMetric app by running
ruby fnordmetric_app.rb and then view our gauge in the browser. When we do this we get a blank page as no events have come in yet. If we visit some of the products’ pages in the browser then click “Popular Products” in the left panel we’ll see the products that we viewed.
Manually triggering these events is a bit of a pain so we’ll set up a Rake task that will do this for us to simulate real-world activity. Before we do this we’ll move the FnordMetric event trigger from the controller into the
Product model. This will clean up the controller a little and allow us to trigger the event from our Rake task. We’ll create a new method called
trigger_view_event in the model and call that from the controller.
def show @product = Product.find(params[:id]) @product.trigger_view_event end
Next we’ll write this new method in the model.
def trigger_view_event FNORD_METRIC.event(attributes.merge(_type: :view_product)) end
Now we can write our Rake task.
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
This is a simple Rake task which loads in the Rails environment then repeatedly triggers the view event for that product, sleeping for a random time between zero and one seconds. We can start our Rake task now and it will run in the background.
$ rake fnordmetric:populate
If we refresh our gauge now we’ll see a lot more events registered and see which products are becoming more or less popular.
Next we’ll add another gauge to see which price ranges are the most popular. This is done by adding a
distribution_gauge which we pass a
title and an array of ranges. We’ll need to observe this gauge, too.
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
We’ve also added a call to
hide_active_users in this file. This will remove the Active Users menu option from the left panel as this isn’t that useful to us. We’ll need to stop and restart this script as we’ve changed it but after we have we’ll see the new “Popular Prices” graph listed and clicking it will show the most popular price ranges based how often each product has been visited.
We’ll add a final gauge to our list showing the number of product views per second.
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
This will create a generic gauge that updates once a second. When we create a gauge like this we usually add a
widget too to define how it’s displayed. We want to update this gauge whenever we receive a
view_product event so we use
incr to increment the gauge when this happens. When we stop and start our script now we’ll see the product views widget which automatically updates every time a product is viewed.
That’s it for our look at FnordMetric. If you want to track events in your Rails applications it’s well worth considering, although it is currently rather lacking in documentation.