From 509082bafb01e39f4dac6f45b4ea98129ed5109c Mon Sep 17 00:00:00 2001
From: Paco Guzman <pacoguzmanp@gmail.com>
Date: Mon, 13 Jun 2016 16:23:17 +0200
Subject: [PATCH] Instrument Grape Endpoint with Metrics::RackMiddleware
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Generating the following tags

Grape#GET /projects/:id/archive

from Grape::Route objects like

{ :path => /:version/projects/:id/archive(.:format)
  :version => “v3”,
  :method => “GET” }

Use an instance variable to cache raw_path transformations.
This variable is only going to growth to the number of
endpoints of the API, not with exact different requests

We can store this cache as an instance variable because
middleware are initialised only once
---
 lib/gitlab/metrics/rack_middleware.rb         | 25 +++++++++++++++-
 .../gitlab/metrics/rack_middleware_spec.rb    | 29 +++++++++++++++++++
 2 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/lib/gitlab/metrics/rack_middleware.rb b/lib/gitlab/metrics/rack_middleware.rb
index 6f179789d3e..3fe27779d03 100644
--- a/lib/gitlab/metrics/rack_middleware.rb
+++ b/lib/gitlab/metrics/rack_middleware.rb
@@ -1,8 +1,9 @@
 module Gitlab
   module Metrics
-    # Rack middleware for tracking Rails requests.
+    # Rack middleware for tracking Rails and Grape requests.
     class RackMiddleware
       CONTROLLER_KEY = 'action_controller.instance'
+      ENDPOINT_KEY   = 'api.endpoint'
 
       def initialize(app)
         @app = app
@@ -21,6 +22,8 @@ module Gitlab
         ensure
           if env[CONTROLLER_KEY]
             tag_controller(trans, env)
+          elsif env[ENDPOINT_KEY]
+            tag_endpoint(trans, env)
           end
 
           trans.finish
@@ -42,6 +45,26 @@ module Gitlab
         controller   = env[CONTROLLER_KEY]
         trans.action = "#{controller.class.name}##{controller.action_name}"
       end
+
+      def tag_endpoint(trans, env)
+        endpoint = env[ENDPOINT_KEY]
+        path = endpoint_paths_cache[endpoint.route.route_method][endpoint.route.route_path]
+        trans.action = "Grape##{endpoint.route.route_method} #{path}"
+      end
+
+      private
+
+      def endpoint_paths_cache
+        @endpoint_paths_cache ||= Hash.new do |hash, http_method|
+          hash[http_method] = Hash.new do |inner_hash, raw_path|
+            inner_hash[raw_path] = endpoint_instrumentable_path(raw_path)
+          end
+        end
+      end
+
+      def endpoint_instrumentable_path(raw_path)
+        raw_path.sub('(.:format)', '').sub('/:version', '')
+      end
     end
   end
 end
diff --git a/spec/lib/gitlab/metrics/rack_middleware_spec.rb b/spec/lib/gitlab/metrics/rack_middleware_spec.rb
index b99be4e1060..40289f8b972 100644
--- a/spec/lib/gitlab/metrics/rack_middleware_spec.rb
+++ b/spec/lib/gitlab/metrics/rack_middleware_spec.rb
@@ -31,6 +31,20 @@ describe Gitlab::Metrics::RackMiddleware do
 
       middleware.call(env)
     end
+
+    it 'tags a transaction with the method andpath of the route in the grape endpoint' do
+      route    = double(:route, route_method: "GET", route_path: "/:version/projects/:id/archive(.:format)")
+      endpoint = double(:endpoint, route: route)
+
+      env['api.endpoint'] = endpoint
+
+      allow(app).to receive(:call).with(env)
+
+      expect(middleware).to receive(:tag_endpoint).
+        with(an_instance_of(Gitlab::Metrics::Transaction), env)
+
+      middleware.call(env)
+    end
   end
 
   describe '#transaction_from_env' do
@@ -60,4 +74,19 @@ describe Gitlab::Metrics::RackMiddleware do
       expect(transaction.action).to eq('TestController#show')
     end
   end
+
+  describe '#tag_endpoint' do
+    let(:transaction) { middleware.transaction_from_env(env) }
+
+    it 'tags a transaction with the method and path of the route in the grape endpount' do
+      route    = double(:route, route_method: "GET", route_path: "/:version/projects/:id/archive(.:format)")
+      endpoint = double(:endpoint, route: route)
+
+      env['api.endpoint'] = endpoint
+
+      middleware.tag_endpoint(transaction, env)
+
+      expect(transaction.action).to eq('Grape#GET /projects/:id/archive')
+    end
+  end
 end
-- 
GitLab