From 4f6716ab8126d94bdd87032b4bec8a650a7a8f4c Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 8 Aug 2017 10:15:41 +0200 Subject: RFC: Instrumentable module using Prometheus Using histograms, we can expose method timings. This is now done with Influx, but we're moving away from this. This commit itself is more of a PoC, and a request for comments rather than a finished work. [ci skip] --- lib/gitlab/instrumentable.rb | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 lib/gitlab/instrumentable.rb diff --git a/lib/gitlab/instrumentable.rb b/lib/gitlab/instrumentable.rb new file mode 100644 index 00000000000..1d7e7b0f2df --- /dev/null +++ b/lib/gitlab/instrumentable.rb @@ -0,0 +1,58 @@ +# Used to instrument methods in the GitLab codebase +# +# Creates a lightweight wrapper around the method pointed at by DSL method call +# Under the hood this creates a Prometheus histogram, with at most 12 buckets to +# keep that instance alife. Labels are not supported yet, as the number of labels +# per histogram should remain limited, ideally to about 10. Also I didn't want +# an extra DSL method like grape as that gets messy real quick. +# +# Usage: +# class SomeClass +# include Gitlab::Instrumentable +# +# instrument_method :some_method +# +# # with custom buckets, max 12 +# instrument_method :other_method, 20..30 +# instrument_method :other_method, [1,3,5,8,12,30,60,120] +# end +require 'active_support/concern' + +module Gitlab + module Instrumentable + extend ActiveSupport::Concern + + class_methods do + def instrument_method(method, buckets = nil) + @buckets = buckets&.to_a || ::Prometheus::Client::Histogram::DEFAULT_BUCKETS + raise 'Too many buckets, limit to 12' if @buckets.size > 12 && !Rails.env.production? + + mod = Module.new do + define_method(method) do |*args| + return super(*args) if Rails.env.test? + + start_time = Time.now.to_f + res = super(*args) + record_timing_since(start_time, __method__) + + res + end + + private + + def record_timing_since(time, method) + class_name = self.class.name + @histogram ||= Gitlab::Metrics.histogram( + "#{class_name.underscore}_duration_seconds", + "Execution time for #{class_name}##{method}", + {}, @buckets) + + @histogram.observe({}, Time.now.to_f - time) + end + end + + self.prepend(mod) + end + end + end +end -- cgit v1.2.1