Vitals
Vitals is your one stop shop for metrics in Ruby and Ruby Web and API frameworks. It currently support Rails, Rack (Sinatra and any Rack-supported frameworks), and Grape.
Installation
Add this line to your application's Gemfile:
gem 'vitals'
And then execute:
$ bundle
Or install it yourself as:
$ gem install vitals
Usage
Rails or Grape
Make an initializers/vitals.rb
initializer, and configure Vitals as you'd like:
require 'vitals'
Vitals.configure! do |c|
c.facility = 'my_service'
c.reporter = Vitals::Reporters::StatsdReporter.new(host: 'statsd-host', port: 8125)
end
#
# Rails
#
require 'vitals/integrations/notifications/action_controller'
Vitals::Integrations::Notifications::ActionController.subscribe!
# if you also want ActiveJob metrics
require 'vitals/integrations/notifications/action_job'
Vitals::Integrations::Notifications::ActiveJob.subscribe!
#
# Grape
#
require 'vitals/integrations/notifications/grape'
Vitals::Integrations::Notifications::Grape.subscribe!
You can shortcircuit the notifications configuration by using subscribe!
right after configuring:
require 'vitals'
Vitals.configure! do |c|
c.facility = 'my_service'
c.reporter = Vitals::Reporters::StatsdReporter.new(host: 'statsd-host', port: 8125)
end
# Subscribe to Rails' controllers, background jobs, and grape's API controllers
Vitals.subscribe!(:action_controller, :active_job, :grape)
Rack
You can use the Requests
middleware for pure Rack apps or Sinatra, Rails, and Grape instead of, or
in addition to, using the notification based instrumentation. Here is a sample Sinatra app:
require 'vitals'
require 'vitals/integrations/rack/requests'
class SinatraTestAPI < Sinatra::Base
use Vitals::Integrations::Rack::Requests
get '/foo/bar/baz' do
sleep 0.1
"hello get"
end
post '/foo/bar/:name' do
sleep 0.1
"hello post"
end
end
Ruby
You can emit metrics from anywhere:
Vitals.inc('my_metric')
Vitals.count('my_metric', 17)
Vitals.gauge('my_metric', 42)
Vitals.timing('my_metric', 500) # milliseconds
Vitals.time('my_metric'){
# so something slow
}
# Use a dot to logically separate segments
Vitals.timing('category.my_metric', 500) # milliseconds
Configuration Options
The Vitals API is extensible. It should resemble the standard Logger
look and feel,
and it revolves around 3 concepts:
-
Reporter
- the thing that takes your metrics and flushes them to a metrics agent. UseStatsdReporter
in production andConsoleReporter
in development.ConsoleReporter
will spit out metrics tostdout
as they come. You can also wire them both withMultiReporter
. Check the specs for how to do that. -
Format
- takes the contextual information (host, service, environment) and your metric, and formats them in an order that makes sense for working with Graphite. You have theProductionFormat
,HostLastFormat
andNoHostFormat
. -
Integrations
- integrations hook things that we're able to instrument with Vitals. Check integrations for more.
Here's what's available to you at configuration time:
Vitals.configure! do |c|
# Set your service name (default: 'default')
c.facility = 'my_service'
# Set environment (default: taken from RACK_ENV)
# c.environment = 'env'
# Set a host (default: taken from hostname)
# c.host = 'foohost'
# Use a specific reporter (default: InmemReporter)
# c.reporter = Vitals::Reporters::ConsoleReporter.new
# Use a different format perhaps? (default: ProductionFormat)
# c.format = Vitals::Formats::HostLastFormat
# Use a different metric path separator, control how hierarcies are generated (default: '.')
# c.path_sep = '__'
end
Metric Hierarchies
If you leave the default metric path separator, it will be a dot. This means Graphite will parse this and generate a branch in the tree when ever it sees a new segment, so:
requests.api.status.registration.get.200.host-123
Will be created from a GET /api/status/registration
On the other hand, if you choose a non-dot separator, like underscore, then:
requests.api_status_registration.get.200.host-123
Will be generated from a GET /api/status/registration
.
You can pick either of those and the trade-offs are:
-
Nested hierarchy (using a dot): fine-grained control over grouping your metrics efficiently. If you want to pick and choose a metric, and be able to group based on topics efficiently. You cannot group cross-segments of a path in graphite.
-
Flat hierarchy (using anything other than a dot, like an underscore): grouping over segments can be glob-like, so quick wins like "graph all errors" can be had like this:
api.*.500.*
. However, every time you want to group metrics, you will need to find the appropriate glob pattern, which will taxi Graphite for a huge amounts of metrics.
The default separator is a dot, which makes everything hierarchical.
Development
Tests and benchmarks should be run with at least Ruby 2.1 (because of memory profiling API)
$ bundle install && rake spec && rake bench
You can use the following to test various web frameworks using their own integration testing stacks:
$ rake multiverse
Contributing
Fork, implement, add tests, pull request, get my everlasting thanks and a respectable place here :).
Copyright
Copyright (c) 2011-2016 Dotan Nahum @jondot. See LICENSE for further details.