GitHub - afeld/tricle: easy metrics reporting via email

5 min read Original article ↗

Automated metrics reporting via email. It's datastore-agnostic, so you can query SQL, MongoDB, external APIs, etc. to generate the stats you need. Uses sparkle for generating sparklines. Example implementations:

screenshot

Installation

This gem can be used within an existing project (e.g. a Rails app), or standalone.

# Gemfile
gem 'tricle'


# Rakefile
require 'your/tricle/subclasses'
require 'tricle/tasks'


# your/config/file.rb

# unless you already have ActionMailer set up
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.smtp_settings = {
  # ...
}

# Optional: Override the start day of the reports (Rails >= 4.0.3 only)
# http://api.rubyonrails.org/classes/Date.html#method-i-beginning_of_week-3D
Date.beginning_of_week = :monday

See the ActionMailer guide for configuration details. Finally, execute:

Usage

Metrics

For each metric you want to report, create a new subclass of Tricle::Metric that implements #size_for_range and #total:

class MyMetric < Tricle::Metric

  # Retrieve the value of this metric for the provided time period. Generally
  # this will be the count/value added/removed. Not necessary if #items_for_range
  # is defined.
  #
  # @param start_at [Time]
  # @param end_at [Time] non-inclusive
  # @return [Fixnum]
  def size_for_range(start_at, end_at)
    # ...
  end

  # Optional: Retrieve the cumulative value for this metric. If not defined,
  # the total won't be displayed in the mailer.
  #
  # @return [Fixnum] the grand total
  def total
    # ...
  end

  # Optional: Only necessary if using `list` for this Metric within your Mailer.
  #
  # @param start_at [Time]
  # @param end_at [Time] non-inclusive
  # @return [Enumerator]
  def items_for_range(start_at, end_at)
    # ...
  end

end

If you would like finer-grain optimization, the methods included from the Aggregation mixin can be overridden.

ActiveRecord Metrics

You can inherit from Tricle::ActiveRecordMetric for even easier setup. By default, Tricle looks for records with a created_at timestamp between the start_at and end_at times.

# app/metrics/new_users.rb
class NewUsers < Tricle::ActiveRecordMetric

  # Apply any default scopes you need
  def items
    User.where(deleted_at: nil)
  end

end

You can also override the time_column method to split the time intervals based on that value. For example, to see records that have been updated:

# app/metrics/new_users.rb
class NewUsers < Tricle::ActiveRecordMetric

  def items
    User.where(deleted_at: nil)
  end

  def time_column
    'updated_at'
  end

end

"Lower is better" metrics

By default, Tricle highlights numbers that increased in green, and those that decreased in red. If you have a metric where a lower number is considered better, you'll want to override the #better method so Tricle highlights your cells properly:

class LowerIsBetterMetric < Tricle::Metric
  def better
    :lower
  end

  ...
end

You can also return :none, and none of your cells for that metric will be highlighted green or red.

Mailers

Mailers specify how a particular set of Metrics should be sent. You can define one or multiple, to send different metrics to different groups of people.

class MyMailer < Tricle::Mailer

  # accepts the same options as ActionMailer... see "Default Hash" at
  # http://rubydoc.info/gems/actionmailer/ActionMailer/Base
  default(
    # ...
  )

  self.period = :day # options are :day, :week (default), and :month

  metric MyMetric1
  metric MyMetric2
  # ...

  # optional: metrics can be grouped
  group "Group 1 Name" do
    metric MyMetric3
    # ...
  end
  group "Group 2 Name" do
    metric MyMetric4
    # ...
  end

  # optional: list the items for the specified Metric
  list MyMetric2 do |item|
    # return the HTML string for each particular item
  end
  # ...

end

e.g.

# app/mailers/weekly_insights.rb
class WeeklyInsights < Tricle::Mailer

  default(
    to: ['theteam@mycompany.com', 'theboss@mycompany.com'],
    from: 'noreply@mycompany.com'
  )

  metric NewUsers

  list NewUsers do |user|
    <<-MARKUP
      <h3>#{user.name}</h3>
      <div>#{user.location}</div>
      <a href="mailto:#{user.email}>#{user.email}</a>
    MARKUP
  end

end

The subject line will be based on the Mailer class name.

Passing options to a Metric

Sometimes, you'll want to initialize a Metric with specific options. If you pass a hash as a second argument to the mailer's metric method, the Metric will be initialized with an @options instance variable.

class IntelligenceBrief < Tricle::Mailer

  metric NewUsers, matching_email: '@gmail.com'

  # or for a list...
  list NewUsers, matching_email: '@gmail.com' do |item|
    ...
  end

end

Previewing

Since you'd probably like to preview your mailers before sending them, set up the Tricle::MailPreview Rack app (which uses MailView).

Within a Rails app

# config/initializers/tricle.rb
require 'tricle/mail_preview'

# config/routes.rb
if Rails.env.development?
  mount Tricle::MailPreview => 'mail_view'
end

and navigate to localhost:3000/mail_view.

Standalone

bundle exec rake tricle:preview
open http://localhost:8080

Global Configuration

To set global configuration options, in an initializer:

Tricle.configure do |c|
  c.sparklines = false # default: true
end

Deploying

To send all Tricle emails, run

rake tricle:emails:send # sends all emails

or

rake tricle:emails:daily # sends emails with period = :day

To set a speficic time zone, use the TZ environment variable (see the list here).

TZ=UTC rake tricle:emails:send

Heroku

  1. Deploy the application.

    • If this is a standalone app, you won't need a web process.
  2. Enable an add-on for email delivery, and configure ActionMailer to send via that provider.

  3. Enable Heroku Scheduler.

    heroku addons:add scheduler:standard
    heroku addons:open scheduler
  4. Add a "job".

    • For a report sent once per day, use the command from Deploying.
    • For a report sent once per week, use rake tricle:emails:send_after_beginning_of_week daily.
      • Heroku Scheduler only supports a maximum of daily tasks, hence needing to use a special task.

You can trigger the email(s) manually for testing with heroku run rake tricle:emails:send.