Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-04 15:08:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-04 15:08:21 +0300
commit63546c0b11e768f1a82dee9507f27bd31a9fc460 (patch)
tree7284dadf385aa01a69c319dfb3566873e434df18 /lib/gitlab/instrumentation
parentb3ce1ce45218454cc3f8b719d7748f8a467f36a3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/gitlab/instrumentation')
-rw-r--r--lib/gitlab/instrumentation/redis.rb92
-rw-r--r--lib/gitlab/instrumentation/redis_base.rb101
-rw-r--r--lib/gitlab/instrumentation/redis_interceptor.rb (renamed from lib/gitlab/instrumentation/redis_driver.rb)50
3 files changed, 155 insertions, 88 deletions
diff --git a/lib/gitlab/instrumentation/redis.rb b/lib/gitlab/instrumentation/redis.rb
index 19d4d9d0f11..b3831c9b50a 100644
--- a/lib/gitlab/instrumentation/redis.rb
+++ b/lib/gitlab/instrumentation/redis.rb
@@ -1,90 +1,30 @@
# 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
-
+ # Aggregates Redis measurements from different request storage sources.
class Redis
- REDIS_REQUEST_COUNT = :redis_request_count
- REDIS_CALL_DURATION = :redis_call_duration
- REDIS_CALL_DETAILS = :redis_call_details
- REDIS_READ_BYTES = :redis_read_bytes
- REDIS_WRITE_BYTES = :redis_write_bytes
+ ActionCable = Class.new(RedisBase)
+ Cache = Class.new(RedisBase)
+ Queues = Class.new(RedisBase)
+ SharedState = Class.new(RedisBase)
+
+ STORAGES = [ActionCable, Cache, Queues, SharedState].freeze
# Milliseconds represented in seconds (from 1 to 500 milliseconds).
QUERY_TIME_BUCKETS = [0.001, 0.0025, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5].freeze
- 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.increment_read_bytes(num_bytes)
- ::RequestStore[REDIS_READ_BYTES] ||= 0
- ::RequestStore[REDIS_READ_BYTES] += num_bytes
- end
-
- def self.increment_write_bytes(num_bytes)
- ::RequestStore[REDIS_WRITE_BYTES] ||= 0
- ::RequestStore[REDIS_WRITE_BYTES] += num_bytes
- end
-
- def self.read_bytes
- ::RequestStore[REDIS_READ_BYTES] || 0
- end
-
- def self.write_bytes
- ::RequestStore[REDIS_WRITE_BYTES] || 0
- 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)
- ::RequestStore[REDIS_CALL_DURATION] ||= 0
- ::RequestStore[REDIS_CALL_DURATION] += duration
- 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
+ class << self
+ def detail_store
+ STORAGES.flat_map(&:detail_store)
+ end
- detail_store << {
- cmd: args.first,
- duration: duration,
- backtrace: ::Gitlab::BacktraceCleaner.clean_backtrace(caller)
- }
+ %i[get_request_count query_time read_bytes write_bytes].each do |method|
+ define_method method do
+ STORAGES.sum(&method) # rubocop:disable CodeReuse/ActiveRecord
+ end
+ end
end
end
end
end
-
-class ::Redis::Client
- prepend ::Gitlab::Instrumentation::RedisInterceptor
-end
diff --git a/lib/gitlab/instrumentation/redis_base.rb b/lib/gitlab/instrumentation/redis_base.rb
new file mode 100644
index 00000000000..a8fb8f5076b
--- /dev/null
+++ b/lib/gitlab/instrumentation/redis_base.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+require 'redis'
+
+module Gitlab
+ module Instrumentation
+ class RedisBase
+ class << self
+ include ::Gitlab::Utils::StrongMemoize
+
+ # TODO: To be used by https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/395
+ # as a 'label' alias.
+ def storage_key
+ self.name.underscore
+ end
+
+ def add_duration(duration)
+ ::RequestStore[call_duration_key] ||= 0
+ ::RequestStore[call_duration_key] += duration
+ end
+
+ def 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
+
+ # TODO: Add information about current Redis client
+ # being instrumented.
+ # https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/316.
+ detail_store << {
+ cmd: args.first,
+ duration: duration,
+ backtrace: ::Gitlab::BacktraceCleaner.clean_backtrace(caller)
+ }
+ end
+
+ def increment_request_count
+ ::RequestStore[request_count_key] ||= 0
+ ::RequestStore[request_count_key] += 1
+ end
+
+ def increment_read_bytes(num_bytes)
+ ::RequestStore[read_bytes_key] ||= 0
+ ::RequestStore[read_bytes_key] += num_bytes
+ end
+
+ def increment_write_bytes(num_bytes)
+ ::RequestStore[write_bytes_key] ||= 0
+ ::RequestStore[write_bytes_key] += num_bytes
+ end
+
+ def get_request_count
+ ::RequestStore[request_count_key] || 0
+ end
+
+ def read_bytes
+ ::RequestStore[read_bytes_key] || 0
+ end
+
+ def write_bytes
+ ::RequestStore[write_bytes_key] || 0
+ end
+
+ def detail_store
+ ::RequestStore[call_details_key] ||= []
+ end
+
+ def query_time
+ query_time = ::RequestStore[call_duration_key] || 0
+ query_time.round(::Gitlab::InstrumentationHelper::DURATION_PRECISION)
+ end
+
+ private
+
+ def request_count_key
+ strong_memoize(:request_count_key) { build_key(:redis_request_count) }
+ end
+
+ def read_bytes_key
+ strong_memoize(:read_bytes_key) { build_key(:redis_read_bytes) }
+ end
+
+ def write_bytes_key
+ strong_memoize(:write_bytes_key) { build_key(:redis_write_bytes) }
+ end
+
+ def call_duration_key
+ strong_memoize(:call_duration_key) { build_key(:redis_call_duration) }
+ end
+
+ def call_details_key
+ strong_memoize(:call_details_key) { build_key(:redis_call_details) }
+ end
+
+ def build_key(namespace)
+ "#{storage_key}_#{namespace}"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/instrumentation/redis_driver.rb b/lib/gitlab/instrumentation/redis_interceptor.rb
index 2d0bce07be5..a485fcaaea1 100644
--- a/lib/gitlab/instrumentation/redis_driver.rb
+++ b/lib/gitlab/instrumentation/redis_interceptor.rb
@@ -4,7 +4,20 @@ require 'redis'
module Gitlab
module Instrumentation
- class RedisDriver < ::Redis::Connection::Ruby
+ module RedisInterceptor
+ def call(*args, &block)
+ start = Time.now
+ super(*args, &block)
+ ensure
+ duration = (Time.now - start)
+
+ if ::RequestStore.active?
+ instrumentation_class.increment_request_count
+ instrumentation_class.add_duration(duration)
+ instrumentation_class.add_call_details(duration, args)
+ end
+ end
+
def write(command)
measure_write_size(command) if ::RequestStore.active?
super
@@ -35,27 +48,40 @@ module Gitlab
end
end
- ::Gitlab::Instrumentation::Redis.increment_write_bytes(size)
+ instrumentation_class.increment_write_bytes(size)
end
def measure_read_size(result)
- # The superclass can return one of four types of results from read:
+ # The Connection::Ruby#read class can return one of four types of results from read:
# https://github.com/redis/redis-rb/blob/f597f21a6b954b685cf939febbc638f6c803e3a7/lib/redis/connection/ruby.rb#L406
#
# 1. Error (exception, will not reach this line)
# 2. Status (string)
# 3. Integer (will be converted to string by to_s.bytesize and thrown away)
# 4. "Binary" string (i.e. may contain zero byte)
- # 5. Array of binary string (recurses back into read)
-
- # Avoid double-counting array responses: the array elements themselves
- # are retrieved with 'read'.
- unless result.is_a? Array
- # This count is an approximation that omits the Redis protocol overhead
- # of type prefixes, length prefixes and line endings.
- ::Gitlab::Instrumentation::Redis.increment_read_bytes(result.to_s.bytesize)
- end
+ # 5. Array of binary string
+
+ size = if result.is_a? Array
+ # This count is an approximation that omits the Redis protocol overhead
+ # of type prefixes, length prefixes and line endings.
+ result.inject(0) { |sum, y| sum + y.to_s.bytesize }
+ else
+ result.to_s.bytesize
+ end
+
+ instrumentation_class.increment_read_bytes(size)
+ end
+
+ # That's required so it knows which GitLab Redis instance
+ # it's interacting with in order to categorize accordingly.
+ #
+ def instrumentation_class
+ @options[:instrumentation_class] # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
end
end
+
+class ::Redis::Client
+ prepend ::Gitlab::Instrumentation::RedisInterceptor
+end