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
|
# frozen_string_literal: true
require 'opentracing'
module Gitlab
module Tracing
module Redis
include Common
MAX_SENT_REDIS_COMMAND_LENGTH = 240
def self.instrument_client
::Redis::Client.class_exec do
prepend RedisTracingInstrumented
end
end
private
module RedisTracingInstrumented
include Common
def call(*args, &block)
# For Redis calls, certain systems (Sidekiq in particular) will poll Redis
# periodically, outside of a trace scope. In this event, don't trace the
# call
scope = OpenTracing.scope_manager.active
return super(*args, &block) unless scope
start_active_span(operation_name: "redis.call",
tags: {
:component => 'redis',
:'span.kind' => 'client',
:'db.host' => self.host,
:'db.port' => self.port,
:'redis.db' => self.db,
:'redis.command' => quantize_redis_arguments(*args),
:'redis.args.count' => args.length
}) do |span|
super(*args, &block)
end
end
# Turns an array of redis arguments into a trace-worthy string
def quantize_redis_arguments(args)
args.inject("") do |memo, arg|
str = ""
begin
str = arg.to_s.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
rescue
# Don't stumble on encoding errors while generating tracing
str = "?"
end
str = str.slice(0, 19) + "…" if str.length > 20
memo = memo == "" ? str : memo + " " + str
if memo.length > MAX_SENT_REDIS_COMMAND_LENGTH
memo = memo.slice(0, MAX_SENT_REDIS_COMMAND_LENGTH - 1) + "…"
# No need to iterate over the rest of the arguments
break memo
end
memo
end
end
end
end
end
end
|