2020-06-04 08:08:21 -04:00
# frozen_string_literal: true
require 'redis'
module Gitlab
module Instrumentation
class RedisBase
class << self
include :: Gitlab :: Utils :: StrongMemoize
2020-06-16 08:09:00 -04:00
include :: Gitlab :: Instrumentation :: RedisPayload
2020-06-04 08:08:21 -04:00
# TODO: To be used by https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/395
# as a 'label' alias.
def storage_key
2020-06-16 08:09:00 -04:00
self . name . demodulize . underscore
2020-06-04 08:08:21 -04:00
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
2020-06-24 17:08:46 -04:00
def redis_cluster_validate! ( command )
2020-06-25 08:09:00 -04:00
:: Gitlab :: Instrumentation :: RedisClusterValidator . validate! ( command ) if @redis_cluster_validation
2020-06-24 17:08:46 -04:00
end
def enable_redis_cluster_validation
@redis_cluster_validation = true
self
end
2020-07-07 08:09:16 -04:00
def count_request
2020-07-07 11:08:49 -04:00
@request_counter || = Gitlab :: Metrics . counter ( :gitlab_redis_client_requests_total , 'Client side Redis request count, per Redis server' )
2020-07-07 08:09:16 -04:00
@request_counter . increment ( { storage : storage_key } )
end
def count_exception ( ex )
# This metric is meant to give a client side view of how the Redis
# server is doing. Redis itself does not expose error counts. This
# metric can be used for Redis alerting and service health monitoring.
2020-07-07 11:08:49 -04:00
@exception_counter || = Gitlab :: Metrics . counter ( :gitlab_redis_client_exceptions_total , 'Client side Redis exception count, per Redis server, per exception class' )
2020-07-07 08:09:16 -04:00
@exception_counter . increment ( { storage : storage_key , exception : ex . class . to_s } )
end
2020-06-04 08:08:21 -04:00
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