In this blogpost we'll run you through a quick 'hello world' example instrumenting a Rails application with the Prometheus ruby client.

(The completed sample created in this blogpost can be found here.)

Create a new rails application:

$ rails new prom-example

Add the Prometheus client and rack gems to your Gemfile and install all of the required gems:

...
gem 'prometheus-client'
$ bundle

Next we'll add the two Rack middlewares required by the Prometheus ruby client.
One is used to expose the metrics HTTP endpoint to be scraped by a Prometheus server while the other is used to trace all of the HTTP requests.

Replace your config.ru file with the following:

# config.ru
require_relative 'config/environment'
require 'prometheus/middleware/collector'
require 'prometheus/middleware/exporter'

use Prometheus::Middleware::Collector
use Prometheus::Middleware::Exporter

run Rails.application

Now spin up your rails application and head over to http://localhost:3000/metrics

$ rails s

You should see the following default metrics displayed in your browser window:

Even with the default metrics provided by the client we are able to measure the latency of our application with the follownig PromQL expression:

  rate(http_server_request_duration_seconds_sum{status="200", path="/"}[1m])
/
  rate(http_server_request_duration_seconds_count{status="200", path="/"}[1m])

 

Next we'll define some of our own metrics in our simple rails application to be exported.

To keep things modular, we'll define and keep our Prometheus registry and metrics inside of the /lib directory where extended modules for our application are kept.

Inside of /lib create the following file structure:

/lib
    /prometheus
        controller.rb
prometheus.rb
# /lib/prometheus.rb
module Prometheus; end
# /lib/prometheus/controller.rb

module Prometheus
  module Controller

    # Create a default Prometheus registry for our metrics.
    prometheus = Prometheus::Client.registry

    # Create a simple gauge metric.
    GAUGE_EXAMPLE = Prometheus::Client::Gauge.new(:gauge_example, 'A simple gauge that rands between 1 and 100 inclusively.')

    # Register GAUGE_EXAMPLE with the registry we previously created.
    prometheus.register(GAUGE_EXAMPLE)

  end
end

Then add the following line to your application.rb in order to load the Prometheus module we have just defined:

...
config.autoload_paths << Rails.root.join('lib')
...

Next I've created a controller simply called test_controller.rb that will add some actions to our rails application.

class TestController < ActionController::Base
  include Prometheus::Controller

  # A gauge is a metric that represents a single numerical value that can arbitrarily go up and down.
  def gauge
    GAUGE_EXAMPLE
      .set({route: :gauge}, rand(0..100))
    respond_to do |r|
      r.any do
        render json: {
                 message: "Success",
               }, status: 200
      end
    end
  end

end

Add a route to this action in config/routes.rb

Rails.application.routes.draw do
   get 'test_gauge', to: 'test#gauge'
end

Now issue a request to http://localhost:3000/test_gauge and you should get a success response indicating that new a value has been assigned to our example gauge we just created.

Heading back over to http://localhost:3000/metrics we should now be able to see that our gauge metric has appeared with a random value between 1 and 100:

While this is a simple trivial example of what one might do with Prometheus and Rails it provides a good base line for you to go ahead and create some meaningful metrics and achieve an inside view as to how your RoR application is performing.

 

Need help with Prometheus and its client libraries? Contact us.