librato-rails
will report key statistics for your Rails app to Librato and allow you to easily track your own custom metrics. Metrics are delivered asynchronously behind the scenes so they won't affect performance of your requests.
Rails versions 3.0 or greater are supported on Ruby 1.9.3 and above.
Verified combinations of Ruby/Rails are available in our build matrix.
Note: If you have not yet enabled Rails on the Librato integrations page within your account, do this first. This will automatically set up Rails and Rack Spaces, displaying many useful performance metrics.
Installing librato-rails
and relaunching your application will automatically start the reporting of built-in performance metrics to your Librato account.
Once installed, custom metrics can also be added easily:
# keep counts of key events
Librato.increment 'user.signup'
# easily benchmark sections of code to verify production performance
Librato.timing 'my.complicated.work' do
# do work
end
# track averages across requests
Librato.measure 'user.social_graph.nodes', user.social_graph.size
In your Gemfile
add:
gem 'librato-rails'
Then run bundle install
.
If you don't have a Librato account already, sign up. In order to send measurements to Librato you need to provide your account credentials to librato-rails
. You can provide these one of two ways:
Create a config/librato.yml
like the following:
production:
user: <your-email>
token: <your-api-key>
The librato.yml
file is parsed via ERB in case you need to add some host or environment-specific magic.
Note that using a configuration file allows you to specify different configurations per-environment. Submission will be disabled in any environment without credentials.
Alternately you can provide LIBRATO_USER
and LIBRATO_TOKEN
environment variables. Unlike config file settings, environment variables will be used in all non-test environments (development, production, etc).
Note that if a config file is present, all environment variables will be ignored.
To see all config options or for information on combining config files and environment variables see the full configuration docs.
If you are using the Librato Heroku addon, your user and token environment variables will already be set in your Heroku environment. If you are running without the addon you will need to provide them yourself.
In either case you will need to specify a custom source for your app to track properly. If librato-rails
does not detect an explicit source it will not start. You can set the source in your environment:
heroku config:add LIBRATO_SOURCE=myappname
If you are using a config file, add your source entry to that instead.
Full information on configuration options is available on the configuration wiki page.
If Heroku idles your application, measurements will not be sent until it receives another request and is restarted. If you see intermittent gaps in your measurements during periods of low traffic, this is the most likely cause.
If you are using Librato as a Heroku addon, a paid plan is required for reporting custom metrics with librato-rails. You can view more about available addon levels here.
After installing librato-rails
and restarting your app you will see a number of new metrics appear in your Librato account. These track request performance, sql queries, mail handling, and other key stats.
Built-in performance metrics will start with either rails
or rack
, depending on the level they are being sampled from. For example: rails.request.total
is the total number of requests rails has received each minute.
The metrics automatically recorded by librato-rails
are organized into named metric suites that can be selectively enabled/disabled:
- rails_controller: Metrics which provide a high level overview of request performance including
rails.request.total
,rails.request.time
,rails.request.time.db
,rails.request.time.view
, andrails.request.slow
- rails_method:
rails.request.method.*
metrics (GET, POST, etc) - rails_status:
rails.request.status.*
metrics broken out by individual status codes and class (200, 2xx, etc) - rails_action:
rails.action.*
metrics specific to individual controller actions via the instrument_action helper
- rails_cache:
rails.cache.*
metrics including reads, writes, hits & deletes - rails_job:
rails.job.*
metrics including jobs queued, started & performed (Rails 4.2+) - rails_mail:
rails.mail.*
metrics including mail sent / received - rails_render:
rails.view.*
metrics including time to render individual templates & partials - rails_sql:
rails.sql.*
metrics, including SELECT / INSERT / UPDATE / DELETEs as well as total query operations
Rack measurements are taken from the very beginning of your rack middleware stack. They include all time spent in your ruby process (not just in Rails proper). They will also show requests that are handled entirely in middleware and don't appear in the rails
suites above.
- rack: The
rack.request.total
,rack.request.time
,rack.request.slow
, andrack.request.queue.time
metrics - rack_method:
rack.request.method.*
metrics (GET, POST, etc) - rack_status:
rack.request.status.*
metrics metrics broken out by individual status codes and class (200, 2xx, etc)
The rack.request.queue.time
metric will show you queuing time (the time between your load balancer receiving a request & your application process starting to work on it) if your load balancer sets HTTP_X_REQUEST_START
or HTTP_X_QUEUE_START
.
All of the rails & rack suites listed above are enabled by default.
Suites can be configured via either the LIBRATO_SUITES
environment variable or the suites
setting in a config/librato.yml
configuration file. The syntax is the same regardless of configuration method.
LIBRATO_SUITES="rails_controller,rails_sql" # use ONLY the rails_controller & rails_sql suites
LIBRATO_SUITES="+foo,+bar" # + prefix: default suites plus foo & bar
LIBRATO_SUITES="-rails_render" # - prefix: default suites removing rails_render
LIBRATO_SUITES="+foo,-rack_status" # Default suites except for rack_status, also add foo
LIBRATO_SUITES="all" # Enable all suites
LIBRATO_SUITES="none" # Disable all suites
LIBRATO_SUITES="" # Use only the default suites (same as if env var is absent)
Note that you should specify either an explicit list of suites to enable or add/subtract individual suites from the default list (using the +/- prefixes). If you try to mix these two forms a Librato::Rack::InvalidSuiteConfiguration
error will be raised.
Configuring the metric suites via the config/librato.yml
file would look like this:
production:
user: [email protected]
token: abc123
suites: 'rails_controller,rails_status,rails_sql,rack'
Tracking anything that interests you is easy with Librato. There are four primary helpers available to use anywhere in your application:
Use for tracking a running total of something across requests, examples:
# increment the 'sales_completed' metric by one
Librato.increment 'sales_completed'
# increment by five
Librato.increment 'items_purchased', by: 5
# increment with a custom source
Librato.increment 'user.purchases', source: user.id
Other things you might track this way: user signups, requests of a certain type or to a certain route, total jobs queued or processed, emails sent or received
Note that increment
is primarily used for tracking the rate of occurrence of some event. Given this increment metrics are continuous by default: after being called on a metric once they will report on every interval, reporting zeros for any interval when increment was not called on the metric.
Especially with custom sources you may want the opposite behavior - reporting a measurement only during intervals where increment
was called on the metric:
# report a value for 'user.uploaded_file' only during non-zero intervals
Librato.increment 'user.uploaded_file', source: user.id, sporadic: true
Use when you want to track an average value per-request. Examples:
Librato.measure 'user.social_graph.nodes', 212
# report from a custom source
Librato.measure 'jobs.queued', 3, source: 'worker.12'
Like Librato.measure
this is per-request, but specialized for timing information:
Librato.timing 'twitter.lookup.time', 21.2
# report from a custom source
Librato.measure 'api.response.time', time, source: node_name
The block form auto-submits the time it took for its contents to execute as the measurement value:
Librato.timing 'twitter.lookup.time' do
@twitter = Twitter.lookup(user)
end
By defaults timings will send the average, sum, max and min for every minute. If you want to send percentiles as well you can specify them inline while instrumenting:
# track a single percentile
Librato.timing 'api.request.time', time, percentile: 95
# track multiple percentiles
Librato.timing 'api.request.time', time, percentile: [95, 99]
You can also use percentiles with the block form of timings:
Librato.timing 'my.important.event', percentile: 95 do
# do work
end
There is also a grouping helper, to make managing nested metrics easier. So this:
Librato.measure 'memcached.gets', 20
Librato.measure 'memcached.sets', 2
Librato.measure 'memcached.hits', 18
Can also be written as:
Librato.group 'memcached' do |g|
g.measure 'gets', 20
g.measure 'sets', 2
g.measure 'hits', 18
end
Symbols can be used interchangably with strings for metric names.
librato-rails
also has special helpers which are available inside your controllers:
experimental, this interface may change:
Use when you want to profile execution time or request volume for a specific controller action:
class CommentController < ApplicationController
instrument_action :create # can accept a list
def create
# ...
end
end
Optionally, you can instrument all controller actions:
class ArticlesController < ApplicationController
instrument_action :all
def create
# ...
end
def show
# ...
end
end
Once you instrument an action, librato-rails
will start reporting a set of metrics specific to that action including:
- rails.action.request.total (# of requests)
- rails.action.request.slow (requests >= 200ms to produce)
- rails.action.request.exceptions
- rails.action.request.time (total time spent in action)
- rails.action.request.time.db (db interaction time)
- rails.action.request.time.view (view rendering time)
Each instrumented action will appear as a source for the rails.action.*
metrics, for example mycontroller.action.html
.
IMPORTANT NOTE: Metrics from instrument_action
take into account all time spent in the ActionController stack for that action, including before/after filters and any global processing. They are not equivalent to using a Librato.timing
block inside the method body.
librato-rails
and ActiveSupport::Notifications work great together. In fact, many of the Rails metrics provided are produced by subscribing to the instrumentation events built into Rails.
Assume you have a custom event:
ActiveSupport::Notifications.instrument 'my.event', user: user do
# do work..
end
Writing a subscriber to capture that event and its outcomes is easy:
ActiveSupport::Notifications.subscribe 'my.event' do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
user = event.payload[:user]
# track every time the event happens
Librato.increment 'my.event'
# track how long the event is taking
Librato.timing 'my.event.time', event.duration
# use payload data to do user-specific tracking
Librato.increment 'user.did.event', source: user.id, sporadic: true
# do conditional tracking
if user.feature_on?(:sample_group)
Librato.increment 'user.sample.event'
end
# track slow events
if event.duration >= 50.0
Librato.increment 'my.event.slow'
end
end
These are just a few examples. Combining ActiveSupport::Notifications
instrumentation with Librato can be extremely powerful. As an added benefit, using the instrument/subscribers model allows you to isolate complex instrumentation code from your main application codebase.
You can set an optional prefix to all metrics reported by librato-rails
in your configuration. This can be helpful for isolating test data or forcing different apps to use different metric names.
It can be very useful to track your deploys using annotations so you can use them to monitor the impact of changes to your app. Take a look at the librato-rake-deploytrack gem for an easy install option or this ticket for examples of how you can write your own.
librato-rails
is designed to run within a long-running process and report periodically. Intermittently running rake tasks and most background job tools (delayed job, resque, queue_classic) don't run long enough for this to work.
Never fear, we have some guidelines for how to instrument your workers properly.
librato-rails
submits measurements back to the Librato platform on a per-process basis. By default these measurements are then combined into a single measurement per source (default is your hostname) before persisting the data.
For example if you have 4 hosts with 8 unicorn instances each (i.e. 32 processes total), on the Librato site you'll find 4 data streams (1 per host) instead of 32. Current pricing applies after aggregation, so in this case you will be charged for 4 streams instead of 32.
If you want to report per-process instead, you can set source_pids
to true
in
your config, which will append the process id to the source name used by each thread.
Note that it may take 2-3 minutes for the first results to show up in your Librato account after you have started your servers with librato-rails
enabled and the first request has been received.
If you want to get more information about librato-rails
submissions to the Librato service you can set your log_level
to debug
(see configuration) to get detailed information added to your logs about the settings librato-rails
is seeing at startup and when it is submitting.
Be sure to tail your logs manually (tail -F <logfile>
) as the log output you get when using the rails server
command often skips startup log lines.
If you are having an issue with a specific metric, using a log_level
of trace
will add the exact measurements being sent to your logs along with lots of other information about librato-rails
as it executes. Neither of these modes are recommended long-term in production as they will add quite a bit of volume to your log file and will slow operation somewhat. Note that submission I/O is non-blocking, submission times are total time - your process will continue to handle requests during submissions.
By default the librato-rails
reporter will not start in console mode, even if librato-rails
is configured. If you want to force the reporter to run in console mode, set LIBRATO_AUTORUN
to 1
in your environment:
$ LIBRATO_AUTORUN=1 rails console
If you are debugging setting up librato-rails
locally you can set flush_interval
to something shorter (say 10s) to force submission more frequently. Don't change your flush_interval
in production as it will not result in measurements showing up more quickly, but may affect performance.
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
- Fork the project and submit a pull request from a feature or bugfix branch.
- Please include tests. This is important so we don't break your changes unintentionally in a future version.
- Please don't modify the gemspec, Rakefile, version, or changelog. If you do change these files, please isolate a separate commit so we can cherry-pick around it.
Copyright (c) 2012-2016 Librato Inc. See LICENSE for details.