summaryrefslogtreecommitdiff
path: root/lib/gitlab/instrumentation/redis.rb
blob: cc99e828251c92144311a8dc4a9223746d1b707a (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
# frozen_string_literal: true

require 'redis'

module Gitlab
  module Instrumentation
    module RedisInterceptor
      def call(*args, &block)
        start = Time.now
        super(*args, &block)
      ensure
        duration = (Time.now - start)

        if ::RequestStore.active?
          ::Gitlab::Instrumentation::Redis.increment_request_count
          ::Gitlab::Instrumentation::Redis.add_duration(duration)
          ::Gitlab::Instrumentation::Redis.add_call_details(duration, args)
        end
      end
    end

    class Redis
      REDIS_REQUEST_COUNT = :redis_request_count
      REDIS_CALL_DURATION = :redis_call_duration
      REDIS_CALL_DETAILS = :redis_call_details

      def self.get_request_count
        ::RequestStore[REDIS_REQUEST_COUNT] || 0
      end

      def self.increment_request_count
        ::RequestStore[REDIS_REQUEST_COUNT] ||= 0
        ::RequestStore[REDIS_REQUEST_COUNT] += 1
      end

      def self.detail_store
        ::RequestStore[REDIS_CALL_DETAILS] ||= []
      end

      def self.query_time
        query_time = ::RequestStore[REDIS_CALL_DURATION] || 0
        query_time.round(::Gitlab::InstrumentationHelper::DURATION_PRECISION)
      end

      def self.add_duration(duration)
        total_time = query_time + duration
        ::RequestStore[REDIS_CALL_DURATION] = total_time
      end

      def self.add_call_details(duration, args)
        return unless Gitlab::PerformanceBar.enabled_for_request?
        # redis-rb passes an array (e.g. [:get, key])
        return unless args.length == 1

        detail_store << {
          cmd: args.first,
          duration: duration,
          backtrace: ::Gitlab::BacktraceCleaner.clean_backtrace(caller)
        }
      end
    end
  end
end

class ::Redis::Client
  prepend ::Gitlab::Instrumentation::RedisInterceptor
end