jaeger-client 0.10.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +33 -0
- data/.rubocop.yml +12 -1
- data/.rubocop_todo.yml +13 -0
- data/README.md +55 -3
- data/crossdock/Dockerfile +3 -1
- data/crossdock/Gemfile +1 -1
- data/crossdock/Gemfile.lock +15 -13
- data/crossdock/jaeger-docker-compose.yml +19 -14
- data/crossdock/server +6 -4
- data/jaeger-client.gemspec +10 -5
- data/lib/jaeger/client/version.rb +1 -1
- data/lib/jaeger/client.rb +14 -7
- data/lib/jaeger/encoders/thrift_encoder.rb +113 -32
- data/lib/jaeger/extractors.rb +71 -7
- data/lib/jaeger/http_sender.rb +3 -3
- data/lib/jaeger/injectors.rb +19 -5
- data/lib/jaeger/recurring_executor.rb +35 -0
- data/lib/jaeger/samplers/const.rb +1 -1
- data/lib/jaeger/samplers/guaranteed_throughput_probabilistic.rb +13 -6
- data/lib/jaeger/samplers/per_operation.rb +44 -14
- data/lib/jaeger/samplers/probabilistic.rb +15 -1
- data/lib/jaeger/samplers/rate_limiting.rb +24 -6
- data/lib/jaeger/samplers/remote_controlled/instructions_fetcher.rb +34 -0
- data/lib/jaeger/samplers/remote_controlled.rb +119 -0
- data/lib/jaeger/samplers.rb +1 -0
- data/lib/jaeger/scope.rb +3 -2
- data/lib/jaeger/scope_manager.rb +1 -0
- data/lib/jaeger/span.rb +3 -4
- data/lib/jaeger/span_context.rb +3 -3
- data/lib/jaeger/thrift_tag_builder.rb +42 -0
- data/lib/jaeger/trace_id.rb +10 -1
- data/lib/jaeger/tracer.rb +29 -10
- data/lib/jaeger/udp_sender/transport.rb +4 -3
- data/lib/jaeger/udp_sender.rb +9 -7
- metadata +55 -20
- data/.travis.yml +0 -14
- data/lib/jaeger/span/thrift_tag_builder.rb +0 -43
data/lib/jaeger/extractors.rb
CHANGED
@@ -6,10 +6,12 @@ module Jaeger
|
|
6
6
|
def self.parse(trace)
|
7
7
|
return nil if !trace || trace == ''
|
8
8
|
|
9
|
-
trace_arguments = trace.split(':')
|
9
|
+
trace_arguments = trace.split(':')
|
10
10
|
return nil if trace_arguments.size != 4
|
11
11
|
|
12
|
-
trace_id
|
12
|
+
trace_id = TraceId.base16_hex_id_to_uint128(trace_arguments[0])
|
13
|
+
span_id, parent_id, flags = trace_arguments[1..3].map(&TraceId.method(:base16_hex_id_to_uint64))
|
14
|
+
|
13
15
|
return nil if trace_id.zero? || span_id.zero?
|
14
16
|
|
15
17
|
SpanContext.new(
|
@@ -63,13 +65,47 @@ module Jaeger
|
|
63
65
|
end
|
64
66
|
|
65
67
|
class B3RackCodec
|
68
|
+
class Keys
|
69
|
+
TRACE_ID = 'HTTP_X_B3_TRACEID'
|
70
|
+
SPAN_ID = 'HTTP_X_B3_SPANID'
|
71
|
+
PARENT_SPAN_ID = 'HTTP_X_B3_PARENTSPANID'
|
72
|
+
FLAGS = 'HTTP_X_B3_FLAGS'
|
73
|
+
SAMPLED = 'HTTP_X_B3_SAMPLED'
|
74
|
+
end.freeze
|
75
|
+
|
76
|
+
def self.extract(carrier)
|
77
|
+
B3CodecCommon.extract(carrier, Keys)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class B3TextMapCodec
|
82
|
+
class Keys
|
83
|
+
TRACE_ID = 'x-b3-traceid'
|
84
|
+
SPAN_ID = 'x-b3-spanid'
|
85
|
+
PARENT_SPAN_ID = 'x-b3-parentspanid'
|
86
|
+
FLAGS = 'x-b3-flags'
|
87
|
+
SAMPLED = 'x-b3-sampled'
|
88
|
+
end.freeze
|
89
|
+
|
66
90
|
def self.extract(carrier)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
91
|
+
B3CodecCommon.extract(carrier, Keys)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class B3CodecCommon
|
96
|
+
def self.extract(carrier, keys)
|
97
|
+
return nil if carrier[keys::TRACE_ID].nil? || carrier[keys::SPAN_ID].nil?
|
98
|
+
|
99
|
+
trace_id = if carrier[keys::TRACE_ID].length <= 16
|
100
|
+
TraceId.base16_hex_id_to_uint64(carrier[keys::TRACE_ID])
|
101
|
+
else
|
102
|
+
TraceId.base16_hex_id_to_uint128(carrier[keys::TRACE_ID])
|
103
|
+
end
|
104
|
+
|
105
|
+
span_id = TraceId.base16_hex_id_to_uint64(carrier[keys::SPAN_ID])
|
106
|
+
parent_id = TraceId.base16_hex_id_to_uint64(carrier[keys::PARENT_SPAN_ID])
|
107
|
+
flags = parse_flags(carrier[keys::FLAGS], carrier[keys::SAMPLED])
|
71
108
|
|
72
|
-
return nil if span_id.nil? || trace_id.nil?
|
73
109
|
return nil if span_id.zero? || trace_id.zero?
|
74
110
|
|
75
111
|
SpanContext.new(
|
@@ -91,6 +127,34 @@ module Jaeger
|
|
91
127
|
private_class_method :parse_flags
|
92
128
|
end
|
93
129
|
|
130
|
+
class TraceContextRackCodec
|
131
|
+
# Internal regex used to identify the TraceContext version
|
132
|
+
VERSION_PATTERN = /^([0-9a-fA-F]{2})-(.+)$/.freeze
|
133
|
+
|
134
|
+
# Internal regex used to parse fields in version 0
|
135
|
+
HEADER_V0_PATTERN = /^([0-9a-fA-F]{32})-([0-9a-fA-F]{16})(-([0-9a-fA-F]{2}))?$/.freeze
|
136
|
+
|
137
|
+
def self.extract(carrier)
|
138
|
+
header_value = carrier['HTTP_TRACEPARENT']
|
139
|
+
|
140
|
+
version_match = VERSION_PATTERN.match(header_value)
|
141
|
+
return nil unless version_match
|
142
|
+
|
143
|
+
# We currently only support version 0
|
144
|
+
return nil if version_match[1].to_i(16) != 0
|
145
|
+
|
146
|
+
match = HEADER_V0_PATTERN.match(version_match[2])
|
147
|
+
return nil unless match
|
148
|
+
|
149
|
+
trace_id = TraceId.base16_hex_id_to_uint128(match[1])
|
150
|
+
span_id = TraceId.base16_hex_id_to_uint64(match[2])
|
151
|
+
flags = TraceId.base16_hex_id_to_uint64(match[4])
|
152
|
+
return nil if trace_id.zero? || span_id.zero?
|
153
|
+
|
154
|
+
SpanContext.new(trace_id: trace_id, span_id: span_id, flags: flags)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
94
158
|
DEFAULT_EXTRACTORS = {
|
95
159
|
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
96
160
|
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
data/lib/jaeger/http_sender.rb
CHANGED
@@ -4,7 +4,7 @@ require 'logger'
|
|
4
4
|
|
5
5
|
module Jaeger
|
6
6
|
class HttpSender
|
7
|
-
def initialize(url:, headers: {},
|
7
|
+
def initialize(url:, encoder:, headers: {}, logger: Logger.new($stdout))
|
8
8
|
@encoder = encoder
|
9
9
|
@logger = logger
|
10
10
|
|
@@ -21,8 +21,8 @@ module Jaeger
|
|
21
21
|
batch = @encoder.encode(spans)
|
22
22
|
@transport.write(@serializer.serialize(batch))
|
23
23
|
@transport.flush
|
24
|
-
rescue StandardError =>
|
25
|
-
@logger.error("Failure while sending a batch of spans: #{
|
24
|
+
rescue StandardError => e
|
25
|
+
@logger.error("Failure while sending a batch of spans: #{e}")
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/jaeger/injectors.rb
CHANGED
@@ -51,18 +51,32 @@ module Jaeger
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
class TraceContextRackCodec
|
55
|
+
def self.inject(span_context, carrier)
|
56
|
+
flags = span_context.sampled? || span_context.debug? ? 1 : 0
|
57
|
+
|
58
|
+
carrier['traceparent'] = format(
|
59
|
+
'%<version>s-%<trace_id>s-%<span_id>s-%<flags>s',
|
60
|
+
version: '00',
|
61
|
+
trace_id: span_context.trace_id.to_s(16).rjust(32, '0'),
|
62
|
+
span_id: span_context.span_id.to_s(16).rjust(16, '0'),
|
63
|
+
flags: flags.to_s(16).rjust(2, '0')
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
54
68
|
DEFAULT_INJECTORS = {
|
55
69
|
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
56
70
|
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
57
71
|
OpenTracing::FORMAT_RACK => JaegerRackCodec
|
58
72
|
}.freeze
|
59
73
|
|
60
|
-
def self.prepare(
|
61
|
-
DEFAULT_INJECTORS.reduce(
|
62
|
-
|
63
|
-
|
74
|
+
def self.prepare(injectors)
|
75
|
+
DEFAULT_INJECTORS.reduce(injectors) do |acc, (format, default)|
|
76
|
+
provided_injectors = Array(injectors[format])
|
77
|
+
provided_injectors += [default] if provided_injectors.empty?
|
64
78
|
|
65
|
-
acc.merge(format =>
|
79
|
+
acc.merge(format => provided_injectors)
|
66
80
|
end
|
67
81
|
end
|
68
82
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
# Executes a given block periodically. The block will be executed only once
|
5
|
+
# when interval is set to 0.
|
6
|
+
class RecurringExecutor
|
7
|
+
def initialize(interval:)
|
8
|
+
@interval = interval
|
9
|
+
end
|
10
|
+
|
11
|
+
def start(&block)
|
12
|
+
raise 'Already running' if @thread
|
13
|
+
|
14
|
+
@thread = Thread.new do
|
15
|
+
if @interval <= 0
|
16
|
+
yield
|
17
|
+
else
|
18
|
+
loop do
|
19
|
+
yield
|
20
|
+
sleep @interval
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def running?
|
27
|
+
@thread&.alive?
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop
|
31
|
+
@thread.kill
|
32
|
+
@thread = nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -12,27 +12,34 @@ module Jaeger
|
|
12
12
|
# emitted, ie. if is_sampled() for both samplers return true, the tags
|
13
13
|
# for Probabilistic sampler will be used.
|
14
14
|
class GuaranteedThroughputProbabilistic
|
15
|
-
attr_reader :tags
|
15
|
+
attr_reader :tags, :probabilistic_sampler, :lower_bound_sampler
|
16
16
|
|
17
17
|
def initialize(lower_bound:, rate:, lower_bound_sampler: nil)
|
18
18
|
@probabilistic_sampler = Probabilistic.new(rate: rate)
|
19
19
|
@lower_bound_sampler = lower_bound_sampler || RateLimiting.new(max_traces_per_second: lower_bound)
|
20
20
|
@lower_bound_tags = {
|
21
21
|
'sampler.type' => 'lowerbound',
|
22
|
-
'sampler.param' =>
|
22
|
+
'sampler.param' => rate
|
23
23
|
}
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
26
|
+
def update(lower_bound:, rate:)
|
27
|
+
is_updated = @probabilistic_sampler.update(rate: rate)
|
28
|
+
is_updated = @lower_bound_sampler.update(max_traces_per_second: lower_bound) || is_updated
|
29
|
+
@lower_bound_tags['sampler.param'] = rate
|
30
|
+
is_updated
|
31
|
+
end
|
32
|
+
|
33
|
+
def sample(...)
|
34
|
+
is_sampled, probabilistic_tags = @probabilistic_sampler.sample(...)
|
28
35
|
if is_sampled
|
29
36
|
# We still call lower_bound_sampler to update the rate limiter budget
|
30
|
-
@lower_bound_sampler.sample
|
37
|
+
@lower_bound_sampler.sample(...)
|
31
38
|
|
32
39
|
return [is_sampled, probabilistic_tags]
|
33
40
|
end
|
34
41
|
|
35
|
-
is_sampled, _tags = @lower_bound_sampler.sample
|
42
|
+
is_sampled, _tags = @lower_bound_sampler.sample(...)
|
36
43
|
[is_sampled, @lower_bound_tags]
|
37
44
|
end
|
38
45
|
end
|
@@ -10,37 +10,67 @@ module Jaeger
|
|
10
10
|
DEFAULT_SAMPLING_PROBABILITY = 0.001
|
11
11
|
DEFAULT_LOWER_BOUND = 1.0 / (10.0 * 60.0) # sample once every 10 minutes'
|
12
12
|
|
13
|
+
attr_reader :default_sampling_probability, :lower_bound, :samplers
|
14
|
+
|
13
15
|
def initialize(strategies:, max_operations:)
|
14
16
|
@max_operations = max_operations
|
17
|
+
@samplers = {}
|
18
|
+
update(strategies: strategies)
|
19
|
+
end
|
20
|
+
|
21
|
+
def update(strategies:)
|
22
|
+
is_updated = false
|
23
|
+
|
15
24
|
@default_sampling_probability =
|
16
25
|
strategies[:default_sampling_probability] || DEFAULT_SAMPLING_PROBABILITY
|
17
|
-
@lower_bound =
|
26
|
+
@lower_bound =
|
27
|
+
strategies[:default_lower_bound_traces_per_second] || DEFAULT_LOWER_BOUND
|
18
28
|
|
19
|
-
@default_sampler
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
sampler = GuaranteedThroughputProbabilistic.new(
|
24
|
-
lower_bound: @lower_bound,
|
25
|
-
rate: rate
|
26
|
-
)
|
27
|
-
acc.merge(operation => sampler)
|
29
|
+
if @default_sampler
|
30
|
+
is_updated = @default_sampler.update(rate: @default_sampling_probability)
|
31
|
+
else
|
32
|
+
@default_sampler = Probabilistic.new(rate: @default_sampling_probability)
|
28
33
|
end
|
34
|
+
|
35
|
+
update_operation_strategies(strategies) || is_updated
|
29
36
|
end
|
30
37
|
|
31
|
-
def sample
|
38
|
+
def sample(opts)
|
32
39
|
operation_name = opts.fetch(:operation_name)
|
33
40
|
sampler = @samplers[operation_name]
|
34
|
-
return sampler.sample
|
41
|
+
return sampler.sample(opts) if sampler
|
35
42
|
|
36
|
-
return @default_sampler.sample
|
43
|
+
return @default_sampler.sample(opts) if @samplers.length >= @max_operations
|
37
44
|
|
38
45
|
sampler = GuaranteedThroughputProbabilistic.new(
|
39
46
|
lower_bound: @lower_bound,
|
40
47
|
rate: @default_sampling_probability
|
41
48
|
)
|
42
49
|
@samplers[operation_name] = sampler
|
43
|
-
sampler.sample
|
50
|
+
sampler.sample(opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def update_operation_strategies(strategies)
|
56
|
+
is_updated = false
|
57
|
+
|
58
|
+
(strategies[:per_operation_strategies] || []).each do |strategy|
|
59
|
+
operation = strategy.fetch(:operation)
|
60
|
+
rate = strategy.fetch(:probabilistic_sampling).fetch(:sampling_rate)
|
61
|
+
|
62
|
+
if (sampler = @samplers[operation])
|
63
|
+
is_updated = sampler.update(lower_bound: @lower_bound, rate: rate) || is_updated
|
64
|
+
else
|
65
|
+
@samplers[operation] = GuaranteedThroughputProbabilistic.new(
|
66
|
+
lower_bound: @lower_bound,
|
67
|
+
rate: rate
|
68
|
+
)
|
69
|
+
is_updated = true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
is_updated
|
44
74
|
end
|
45
75
|
end
|
46
76
|
end
|
@@ -6,19 +6,33 @@ module Jaeger
|
|
6
6
|
#
|
7
7
|
# Sample a portion of traces using trace_id as the random decision
|
8
8
|
class Probabilistic
|
9
|
+
attr_reader :rate
|
10
|
+
|
9
11
|
def initialize(rate: 0.001)
|
12
|
+
update(rate: rate)
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(rate:)
|
10
16
|
if rate < 0.0 || rate > 1.0
|
11
17
|
raise "Sampling rate must be between 0.0 and 1.0, got #{rate.inspect}"
|
12
18
|
end
|
13
19
|
|
20
|
+
new_boundary = TraceId::TRACE_ID_UPPER_BOUND * rate
|
21
|
+
return false if @boundary == new_boundary
|
22
|
+
|
23
|
+
@rate = rate
|
14
24
|
@boundary = TraceId::TRACE_ID_UPPER_BOUND * rate
|
15
25
|
@tags = {
|
16
26
|
'sampler.type' => 'probabilistic',
|
17
27
|
'sampler.param' => rate
|
18
28
|
}
|
29
|
+
|
30
|
+
true
|
19
31
|
end
|
20
32
|
|
21
|
-
def sample
|
33
|
+
def sample(opts)
|
34
|
+
trace_id = opts.fetch(:trace_id)
|
35
|
+
|
22
36
|
[@boundary >= trace_id, @tags]
|
23
37
|
end
|
24
38
|
end
|
@@ -8,24 +8,42 @@ module Jaeger
|
|
8
8
|
# well, but if requests are bursty, especially sub-second, then a number
|
9
9
|
# of sequential requests can be sampled each second.
|
10
10
|
class RateLimiting
|
11
|
-
attr_reader :tags
|
11
|
+
attr_reader :tags, :max_traces_per_second
|
12
12
|
|
13
13
|
def initialize(max_traces_per_second: 10)
|
14
|
+
update(max_traces_per_second: max_traces_per_second)
|
15
|
+
end
|
16
|
+
|
17
|
+
def update(max_traces_per_second:)
|
14
18
|
if max_traces_per_second < 0.0
|
15
19
|
raise "max_traces_per_second must not be negative, got #{max_traces_per_second}"
|
16
20
|
end
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
max_balance: [max_traces_per_second, 1.0].max
|
21
|
-
)
|
22
|
+
return false if max_traces_per_second == @max_traces_per_second
|
23
|
+
|
22
24
|
@tags = {
|
23
25
|
'sampler.type' => 'ratelimiting',
|
24
26
|
'sampler.param' => max_traces_per_second
|
25
27
|
}
|
28
|
+
@max_traces_per_second = max_traces_per_second
|
29
|
+
max_balance = [max_traces_per_second, 1.0].max
|
30
|
+
|
31
|
+
if @rate_limiter
|
32
|
+
@rate_limiter.update(
|
33
|
+
credits_per_second: max_traces_per_second,
|
34
|
+
max_balance: max_balance
|
35
|
+
)
|
36
|
+
else
|
37
|
+
@rate_limiter = RateLimiter.new(
|
38
|
+
credits_per_second: max_traces_per_second,
|
39
|
+
max_balance: [max_traces_per_second, 1.0].max
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
true
|
26
44
|
end
|
27
45
|
|
28
|
-
def sample
|
46
|
+
def sample(*)
|
29
47
|
[@rate_limiter.check_credit(1.0), @tags]
|
30
48
|
end
|
31
49
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Samplers
|
5
|
+
class RemoteControlled
|
6
|
+
class InstructionsFetcher
|
7
|
+
FetchFailed = Class.new(StandardError)
|
8
|
+
|
9
|
+
def initialize(host:, port:, service_name:)
|
10
|
+
@host = host
|
11
|
+
@port = port
|
12
|
+
@service_name = service_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch
|
16
|
+
http = Net::HTTP.new(@host, @port)
|
17
|
+
path = "/sampling?service=#{CGI.escape(@service_name)}"
|
18
|
+
response =
|
19
|
+
begin
|
20
|
+
http.request(Net::HTTP::Get.new(path))
|
21
|
+
rescue StandardError => e
|
22
|
+
raise FetchFailed, e.inspect
|
23
|
+
end
|
24
|
+
|
25
|
+
unless response.is_a?(Net::HTTPSuccess)
|
26
|
+
raise FetchFailed, "Unsuccessful response (code=#{response.code})"
|
27
|
+
end
|
28
|
+
|
29
|
+
JSON.parse(response.body)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'remote_controlled/instructions_fetcher'
|
4
|
+
|
5
|
+
module Jaeger
|
6
|
+
module Samplers
|
7
|
+
class RemoteControlled
|
8
|
+
DEFAULT_REFRESH_INTERVAL = 60
|
9
|
+
DEFAULT_SAMPLING_HOST = 'localhost'
|
10
|
+
DEFAULT_SAMPLING_PORT = 5778
|
11
|
+
|
12
|
+
attr_reader :sampler
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@sampler = opts.fetch(:sampler, Probabilistic.new)
|
16
|
+
@logger = opts.fetch(:logger, Logger.new($stdout))
|
17
|
+
|
18
|
+
@poll_executor = opts[:poll_executor] || begin
|
19
|
+
refresh_interval = opts.fetch(:refresh_interval, DEFAULT_REFRESH_INTERVAL)
|
20
|
+
RecurringExecutor.new(interval: refresh_interval)
|
21
|
+
end
|
22
|
+
|
23
|
+
@instructions_fetcher = opts[:instructions_fetcher] || begin
|
24
|
+
service_name = opts.fetch(:service_name)
|
25
|
+
host = opts.fetch(:host, DEFAULT_SAMPLING_HOST)
|
26
|
+
port = opts.fetch(:port, DEFAULT_SAMPLING_PORT)
|
27
|
+
InstructionsFetcher.new(host: host, port: port, service_name: service_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def sample(*args)
|
32
|
+
@poll_executor.start(&method(:poll)) unless @poll_executor.running?
|
33
|
+
|
34
|
+
@sampler.sample(*args)
|
35
|
+
end
|
36
|
+
|
37
|
+
def poll
|
38
|
+
@logger.debug 'Fetching sampling strategy'
|
39
|
+
|
40
|
+
instructions = @instructions_fetcher.fetch
|
41
|
+
handle_instructions(instructions)
|
42
|
+
rescue InstructionsFetcher::FetchFailed => e
|
43
|
+
@logger.warn "Fetching sampling strategy failed: #{e.message}"
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def handle_instructions(instructions)
|
49
|
+
if instructions['operationSampling']
|
50
|
+
update_per_operation_sampler(instructions['operationSampling'])
|
51
|
+
else
|
52
|
+
update_rate_limiting_or_probabilistic_sampler(instructions['strategyType'], instructions)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_per_operation_sampler(instructions)
|
57
|
+
strategies = normalize(instructions)
|
58
|
+
|
59
|
+
if @sampler.is_a?(PerOperation)
|
60
|
+
@sampler.update(strategies: strategies)
|
61
|
+
else
|
62
|
+
@sampler = PerOperation.new(strategies: strategies, max_operations: 2000)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def normalize(instructions)
|
67
|
+
{
|
68
|
+
default_sampling_probability: instructions['defaultSamplingProbability'],
|
69
|
+
default_lower_bound_traces_per_second: instructions['defaultLowerBoundTracesPerSecond'],
|
70
|
+
per_operation_strategies: instructions['perOperationStrategies'].map do |strategy|
|
71
|
+
{
|
72
|
+
operation: strategy['operation'],
|
73
|
+
probabilistic_sampling: {
|
74
|
+
sampling_rate: strategy['probabilisticSampling']['samplingRate']
|
75
|
+
}
|
76
|
+
}
|
77
|
+
end
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def update_rate_limiting_or_probabilistic_sampler(strategy, instructions)
|
82
|
+
case strategy
|
83
|
+
when 'PROBABILISTIC'
|
84
|
+
update_probabilistic_strategy(instructions['probabilisticSampling'])
|
85
|
+
when 'RATE_LIMITING'
|
86
|
+
update_rate_limiting_strategy(instructions['rateLimitingSampling'])
|
87
|
+
else
|
88
|
+
@logger.warn "Unknown sampling strategy #{strategy}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def update_probabilistic_strategy(instructions)
|
93
|
+
rate = instructions['samplingRate']
|
94
|
+
return unless rate
|
95
|
+
|
96
|
+
if @sampler.is_a?(Probabilistic)
|
97
|
+
@sampler.update(rate: rate)
|
98
|
+
@logger.info "Updated Probabilistic sampler (rate=#{rate})"
|
99
|
+
else
|
100
|
+
@sampler = Probabilistic.new(rate: rate)
|
101
|
+
@logger.info "Updated sampler to Probabilistic (rate=#{rate})"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def update_rate_limiting_strategy(instructions)
|
106
|
+
max_traces_per_second = instructions['maxTracesPerSecond']
|
107
|
+
return unless max_traces_per_second
|
108
|
+
|
109
|
+
if @sampler.is_a?(RateLimiting)
|
110
|
+
@sampler.update(max_traces_per_second: max_traces_per_second)
|
111
|
+
@logger.info "Updated Ratelimiting sampler (max_traces_per_second=#{max_traces_per_second})"
|
112
|
+
else
|
113
|
+
@sampler = RateLimiting.new(max_traces_per_second: max_traces_per_second)
|
114
|
+
@logger.info "Updated sampler to Ratelimiting (max_traces_per_second=#{max_traces_per_second})"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/jaeger/samplers.rb
CHANGED
data/lib/jaeger/scope.rb
CHANGED
@@ -23,6 +23,7 @@ module Jaeger
|
|
23
23
|
# updating the ScopeManager#active in the process.
|
24
24
|
def close
|
25
25
|
raise "Tried to close already closed span: #{inspect}" if @closed
|
26
|
+
|
26
27
|
@closed = true
|
27
28
|
|
28
29
|
@span.finish if @finish_on_close
|
@@ -30,8 +31,8 @@ module Jaeger
|
|
30
31
|
|
31
32
|
if removed_scope != self # rubocop:disable Style/GuardClause
|
32
33
|
raise 'Removed non-active scope, ' \
|
33
|
-
|
34
|
-
|
34
|
+
"removed: #{removed_scope.inspect}, "\
|
35
|
+
"expected: #{inspect}"
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
data/lib/jaeger/scope_manager.rb
CHANGED
data/lib/jaeger/span.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'span/thrift_tag_builder'
|
4
3
|
require_relative 'span/thrift_log_builder'
|
5
4
|
|
6
5
|
module Jaeger
|
@@ -35,7 +34,7 @@ module Jaeger
|
|
35
34
|
# a String, Numeric, or Boolean it will be encoded with to_s
|
36
35
|
def set_tag(key, value)
|
37
36
|
if key == 'sampling.priority'
|
38
|
-
if value.to_i
|
37
|
+
if value.to_i.positive?
|
39
38
|
return self if @context.debug?
|
40
39
|
|
41
40
|
@context.flags = @context.flags | SpanContext::Flags::SAMPLED | SpanContext::Flags::DEBUG
|
@@ -72,9 +71,9 @@ module Jaeger
|
|
72
71
|
# Add a log entry to this span
|
73
72
|
#
|
74
73
|
# @deprecated Use {#log_kv} instead.
|
75
|
-
def log(
|
74
|
+
def log(...)
|
76
75
|
warn 'Span#log is deprecated. Please use Span#log_kv instead.'
|
77
|
-
log_kv(
|
76
|
+
log_kv(...)
|
78
77
|
end
|
79
78
|
|
80
79
|
# Add a log entry to this span
|
data/lib/jaeger/span_context.rb
CHANGED
@@ -19,10 +19,10 @@ module Jaeger
|
|
19
19
|
)
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
attr_accessor :flags
|
23
|
+
attr_reader :span_id, :parent_id, :trace_id, :baggage
|
24
24
|
|
25
|
-
def initialize(span_id:, parent_id: 0,
|
25
|
+
def initialize(span_id:, trace_id:, flags:, parent_id: 0, baggage: {})
|
26
26
|
@span_id = span_id
|
27
27
|
@parent_id = parent_id
|
28
28
|
@trace_id = trace_id
|