summaryrefslogtreecommitdiff
path: root/lib/gitlab/metrics/concern.rb
blob: ccc55cf5b762dbcba711a1b9c2a7b87c0a7bf6f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
module Gitlab
  module Metrics
    module Concern
      extend ActiveSupport::Concern
      class_methods do
        private

        def metrics_provider(type, name, docstring, options = {})
          @@_metrics_provider_mutex ||= Mutex.new

          if instance_methods(false).include?(name)
            raise ArgumentError, "metrics class method #{name} already exists"
          end
          options[:base_labels] ||= {}

          args = [name.inspect, %{"#{docstring}"}, options[:base_labels].inspect]

          case type
            when :gauge
              options[:multiprocess_mode] ||= :all
              args << options[:multiprocess_mode].inspect
            when :histogram
              options[:buckets] ||= ::Prometheus::Client::Histogram::DEFAULT_BUCKETS
              args << options[:buckets].inspect
          end

          metric_fetching_code = %{Gitlab::Metrics::Prometheus.#{type}(#{args.join(', ')})}

          # optionally wrap in feature
          metric_fetching_code = if options[:with_feature].is_a?(Symbol)
                                   <<-FETCH.strip_heredoc
                                  if Feature.get(#{options[:with_feature].inspect}).enabled? 
                                    #{metric_fetching_code}
                                  else
                                    Gitlab::Metrics::NullMetric.new
                                  end
                                   FETCH
                                 end

          method_code, line = <<-METRIC, __LINE__ + 1
            def #{name}
              @@_metric_provider_cached_#{name} if @@_metric_provider_cached_#{name}

              @@_metrics_provider_mutex.synchronize do
                @_metric_provider_cached_#{name} ||= #{metric_fetching_code}
              end
            end
          METRIC

          class_eval(method_code, __FILE__, line)
          module_eval(method_code, __FILE__, line)
        end

        # Declare a Counter
        # @param [Symbol] name
        # @param [String] docstring
        # @param [Hash] opts
        def counter(name, docstring, opts = {})
          metrics_provider(:counter, name, docstring, options)
        end

        # Declare a Gauge
        # @param [Symbol] name
        # @param [String] docstring
        # @param [Hash] opts
        def gauge(name, docstring, opts = {})
          metrics_provider(:counter, name, docstring, opts)
        end

        # Declare a Histograam
        # @param [Symbol] name
        # @param [String] docstring
        # @param [Hash] opts
        def histogram(name, docstring, opts = {})
          metrics_provider(:histogram, name, docstring, opts)
        end

        def summary(*args)
          raise NotImplementedError, "summary metrics are not currently supported"
        end
      end
    end
  end
end