Bodhi

A straightforward DSL for generating and reporting on simple metrics in Ruby.

Bodhi helps you generate simple, straightforward reporting metrics for your Rails application. You can generate reports for anything that can be expressed as a value over time with a simple API.

Bodhi works by letting you define what reporting metrics you want to track in a simple initializer file, and by periodically gathering results about those metrics.

Installation

Rails 3

Add the following to your Gemfile, and run bundle install

 gem 'bodhi'

After installing Bodhi, run the following generator and run rake db:migrate. This will create a table where Bodhi can store past metric values.

 rails generate bodhi:install

Finally, you'll need to put a call to the metric generator in something that will be run at a scheduled interval (a cron rake task is perfect for this). Don't worry about how often it runs, Bodhi will be able to take care of what needs to be run when.

 Bodhi::Metric.generate_all

Basic Usage

Definining Metrics

Using Bodhi is as simple as definining what metrics you would like to use in /initializers/bodhi.rb. Bodhi provides several helpers to cover common metrics that you may want to to track.

Counting

Counting metrics count the number of a given model in the database. By default, it counts the total number in the database at the time of execution, but you can limit this to only items created or updated when the metrics were run.

 Metric.count :dogs            # Counts the total number of the 'dogs' model
 Metric.count :dogs, :new      # Counts all new instances of the 'dogs' model
 Metric.count :dogs, :updated  # Counts all updated instances of the 'dogs' model

Aggregating by column

You can also aggregate any numerical column using Bodhi. The following examples aggregate an integer column:

 Metric.average :dogs, :num_puppies  # Calculates the average number of puppies for a given dog
 Metric.sum :dogs, :num_puppies      # Calculates the total number of puppies.
 Metric.minimum :dogs, :num_puppies  # Calculates the minimum puppy count for any dog
 Metric.maximum :dogs, :num_puppies  # Calculates the maximum puppy count for any dog

Custom Metrics

If you need more sophisticated functionality than what the provided helpers define, you can define custom metrics using Metric.define. Just specify a block that returns a float value. A hash will be passed to your block that specifies start and end times of your metric run in a block.

 Metric.define :percentage_with_puppies do |run|
   relevant_dogs = Dog.where("created_at between ? and ?", run[:start], run[:end])

   total_count = relevant_dogs.count
   puppy_count = relevant_dogs.where("num_puppies > 0").count
   total_count == 0 ? 0 : total_count / puppy_count
 end

Using Metrics

Metrics can be accessed by passing the name of the metric to the Metric class, like so:

 m = Metric[:percentage_with_puppies]

At any time, you can get the current value of a metric (from the beginning of the current date to now) by calling current on a metric:

 Metric[:percentage_with_puppies].current

You can access historical values by calling for_period for a given metric:

 m = Metric[:percentage_with_puppies]
 m.for_period 1.month.ago, Time.now

If the second parameter is omitted on for_period, the current date is assumed.

Generating Metrics

You can generate metrics (run metrics up to the current date), by calling generate on a particular Metric, or all metrics with Metric.generate_all

Metric[:percentage_with_puppies].generate
Metric.generate_all

This will store metric values to the database. You'll need to add calls to generate_all to something that runs at a scheduled interval (like a cron rake task), to ensure metrics are generated correctly. Don't worry about the frequency of your runs, Bodhi won't generate duplicate metrics and will backfill any missing metrics.

TODO

  • Support for blocks passed to helper functions
  • Support for parameterized metrics (or metric groups?)
  • Charting and pretty output for metrics.
  • Support for Mongoid or non-ActiveRecord environments

Contributing

Feel free to fork and make any changes necessary. If you'd like to contribute back, I'd appreciate a topic branch and relevant tests.