summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZ.J. van de Weg <git@zjvandeweg.nl>2017-08-08 10:15:41 +0200
committerZ.J. van de Weg <git@zjvandeweg.nl>2017-08-08 10:18:35 +0200
commit4f6716ab8126d94bdd87032b4bec8a650a7a8f4c (patch)
tree9f710fdbb9fd37e2f6e1d182ffa677d631a41e4c
parentb0464fa4e19e187adc46ec054ccd68832faec08c (diff)
downloadgitlab-ce-zj-instrumentable.tar.gz
RFC: Instrumentable module using Prometheuszj-instrumentable
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]
-rw-r--r--lib/gitlab/instrumentable.rb58
1 files changed, 58 insertions, 0 deletions
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