jaeger-client 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +76 -7
- data/jaeger-client.gemspec +2 -1
- data/lib/jaeger/client.rb +11 -4
- data/lib/jaeger/client/extractors.rb +1 -1
- data/lib/jaeger/client/injectors.rb +1 -1
- data/lib/jaeger/client/rate_limiter.rb +63 -0
- data/lib/jaeger/client/reporters.rb +7 -0
- data/lib/jaeger/client/reporters/composite_reporter.rb +19 -0
- data/lib/jaeger/client/{async_reporter/buffer.rb → reporters/in_memory_reporter.rb} +13 -10
- data/lib/jaeger/client/reporters/logging_reporter.rb +24 -0
- data/lib/jaeger/client/reporters/null_reporter.rb +13 -0
- data/lib/jaeger/client/reporters/remote_reporter.rb +44 -0
- data/lib/jaeger/client/reporters/remote_reporter/buffer.rb +31 -0
- data/lib/jaeger/client/samplers.rb +3 -0
- data/lib/jaeger/client/samplers/const.rb +5 -8
- data/lib/jaeger/client/samplers/guaranteed_throughput_probabilistic.rb +42 -0
- data/lib/jaeger/client/samplers/per_operation.rb +49 -0
- data/lib/jaeger/client/samplers/probabilistic.rb +7 -9
- data/lib/jaeger/client/samplers/rate_limiting.rb +35 -0
- data/lib/jaeger/client/span_context.rb +0 -7
- data/lib/jaeger/client/tracer.rb +16 -8
- data/lib/jaeger/client/version.rb +1 -1
- metadata +28 -5
- data/lib/jaeger/client/async_reporter.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9af8a3a945af29ffe9f0045a2eff121fa519c689d04a680a41c7346a198cbf6
|
4
|
+
data.tar.gz: aad37d03df89f03707f91d3fd2f58b0af5b84122736b24f35edff791bb5f0b7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 975e4605ee85e4e1b34b763233c16fe6ec3ec0ad88a01f8d1239b523e97bc8fde5844a2ca0d152c71a3b7f601be6237fd70303f31229cb995d896958180aaef7
|
7
|
+
data.tar.gz: 490214bc62f0a922e869b24ccbf5510538fa84365d50aafa1e892fe498aaa79e7bcb7d47da97445db8e07c4ebfb2481ecc6cb6aaeac7f81224e5a1ec90eb4616
|
data/README.md
CHANGED
@@ -28,18 +28,56 @@ OpenTracing.start_active_span('span name') do
|
|
28
28
|
end
|
29
29
|
```
|
30
30
|
|
31
|
-
|
31
|
+
See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more examples.
|
32
|
+
|
33
|
+
### Reporters
|
34
|
+
|
35
|
+
#### RemoteReporter (default)
|
36
|
+
|
37
|
+
RemoteReporter buffers spans in memory and sends them out of process using Sender.
|
38
|
+
|
39
|
+
There are two senders: `UdpSender` (default) and `HttpSender`.
|
40
|
+
|
41
|
+
To use `HttpSender`:
|
42
|
+
|
32
43
|
```ruby
|
33
|
-
|
34
|
-
|
44
|
+
OpenTracing.global_tracer = Jaeger::Client.build(
|
45
|
+
service_name: 'service_name',
|
46
|
+
reporter: Jaeger::Client::Reporter::RemoteReporter.new(
|
47
|
+
sender: Jaeger::Client::HttpSender.new(
|
48
|
+
url: 'http://localhost:14268/api/traces',
|
49
|
+
headers: { 'key' => 'value' }, # headers key is optional
|
50
|
+
encoder: Jaeger::Client::Encoders::ThriftEncoder.new(service_name: 'service_name')
|
51
|
+
),
|
52
|
+
flush_interval: 10
|
53
|
+
)
|
54
|
+
)
|
55
|
+
```
|
56
|
+
|
57
|
+
#### NullReporter
|
35
58
|
|
36
|
-
|
37
|
-
encoder = Jaeger::Client::Encoders::ThriftEncoder.new(service_name: "service_name")
|
38
|
-
sender = Jaeger::Client::HttpSender.new(url: "http://localhost:14268/api/traces", headers: headers, encoder: encoder)
|
59
|
+
NullReporter ignores all spans.
|
39
60
|
|
40
|
-
|
61
|
+
```ruby
|
62
|
+
OpenTracing.global_tracer = Jaeger::Client.build(
|
63
|
+
service_name: 'service_name',
|
64
|
+
reporter: Jaeger::Client::Reporter::NullReporter.new
|
65
|
+
)
|
41
66
|
```
|
42
67
|
|
68
|
+
#### LoggingReporter
|
69
|
+
|
70
|
+
LoggingReporter prints some details about the span using `logger`. This is meant only for debugging. Do not parse and use this information for anything critical. The implemenation can change at any time.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
OpenTracing.global_tracer = Jaeger::Client.build(
|
74
|
+
service_name: 'service_name',
|
75
|
+
reporter: Jaeger::Client::Reporter::LoggingReporter.new
|
76
|
+
)
|
77
|
+
```
|
78
|
+
|
79
|
+
LoggingReporter can also use a custom logger. For this provide logger using `logger` keyword argument.
|
80
|
+
|
43
81
|
See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more examples.
|
44
82
|
|
45
83
|
### Samplers
|
@@ -52,6 +90,37 @@ See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more
|
|
52
90
|
|
53
91
|
`Probabilistic` sampler samples traces with probability equal to `rate` (must be between 0.0 and 1.0). This can be enabled by setting `Jaeger::Client::Samplers::Probabilistic.new(rate: 0.1)`
|
54
92
|
|
93
|
+
#### RateLimiting sampler
|
94
|
+
|
95
|
+
`RateLimiting` sampler samples at most `max_traces_per_second`. The distribution of sampled traces follows burstiness of the service, i.e. a service with uniformly distributed requests will have those requests sampled uniformly as well, but if requests are bursty, especially sub-second, then a number of sequential requests can be sampled each second.
|
96
|
+
|
97
|
+
Set `sampler` to `Jaeger::Client::Samplers::RateLimiting.new(max_traces_per_second: 100)`
|
98
|
+
|
99
|
+
#### GuaranteedThroughputProbabilistic sampler
|
100
|
+
|
101
|
+
`GuaranteedThroughputProbabilistic` is a sampler that guarantees a throughput by using a Probabilistic sampler and RateLimiting sampler The RateLimiting sampler is used to establish a lower_bound so that every operation is sampled at least once in the time interval defined by the lower_bound.
|
102
|
+
|
103
|
+
Set `sampler` to `Jaeger::Client::Samplers::GuaranteedThroughputProbabilistic.new(lower_bound: 10, rate: 0.001)`
|
104
|
+
|
105
|
+
#### PerOperation sampler
|
106
|
+
|
107
|
+
`PerOperation` sampler leverages both Probabilistic sampler and RateLimiting sampler via the GuaranteedThroughputProbabilistic sampler. This sampler keeps track of all operations and delegates calls the the respective GuaranteedThroughputProbabilistic sampler.
|
108
|
+
|
109
|
+
Set `sampler` to
|
110
|
+
```
|
111
|
+
Jaeger::Client::Samplers::PerOperation.new(
|
112
|
+
strategies: {
|
113
|
+
per_operation_strategies: [
|
114
|
+
{ operation: 'GET /articles', probabilistic_sampling: 0.5 },
|
115
|
+
{ operation: 'POST /articles', probabilistic_sampling: 1.0 }
|
116
|
+
],
|
117
|
+
default_sampling_probability: 0.001,
|
118
|
+
default_lower_bound_traces_per_second: 1.0 / (10.0 * 60.0)
|
119
|
+
},
|
120
|
+
max_operations: 1000
|
121
|
+
)
|
122
|
+
```
|
123
|
+
|
55
124
|
### Zipkin HTTP B3 compatible header propagation
|
56
125
|
|
57
126
|
Jaeger Tracer supports Zipkin B3 Propagation HTTP headers, which are used by a lot of Zipkin tracers. This means that you can use Jaeger in conjunction with OpenZipkin tracers.
|
data/jaeger-client.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = 'OpenTracing Tracer implementation for Jaeger in Ruby'
|
13
13
|
spec.description = ''
|
14
|
-
spec.homepage = ''
|
14
|
+
spec.homepage = 'https://github.com/salemove/jaeger-client-ruby'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
26
|
spec.add_development_dependency 'rubocop', '~> 0.54.0'
|
27
27
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.24.0'
|
28
|
+
spec.add_development_dependency 'timecop', '~> 0.9'
|
28
29
|
|
29
30
|
spec.add_dependency 'opentracing', '~> 0.3'
|
30
31
|
spec.add_dependency 'thrift'
|
data/lib/jaeger/client.rb
CHANGED
@@ -14,12 +14,14 @@ require_relative 'client/scope_manager'
|
|
14
14
|
require_relative 'client/carrier'
|
15
15
|
require_relative 'client/trace_id'
|
16
16
|
require_relative 'client/udp_sender'
|
17
|
-
require_relative 'client/
|
17
|
+
require_relative 'client/http_sender'
|
18
|
+
require_relative 'client/reporters'
|
18
19
|
require_relative 'client/version'
|
19
20
|
require_relative 'client/samplers'
|
20
21
|
require_relative 'client/encoders/thrift_encoder'
|
21
22
|
require_relative 'client/injectors'
|
22
23
|
require_relative 'client/extractors'
|
24
|
+
require_relative 'client/rate_limiter'
|
23
25
|
|
24
26
|
module Jaeger
|
25
27
|
module Client
|
@@ -32,15 +34,20 @@ module Jaeger
|
|
32
34
|
sampler: Samplers::Const.new(true),
|
33
35
|
logger: Logger.new(STDOUT),
|
34
36
|
sender: nil,
|
37
|
+
reporter: nil,
|
35
38
|
injectors: {},
|
36
39
|
extractors: {})
|
37
40
|
encoder = Encoders::ThriftEncoder.new(service_name: service_name)
|
38
41
|
|
39
|
-
if sender
|
40
|
-
|
42
|
+
if sender
|
43
|
+
warn '[DEPRECATION] Passing `sender` directly to Jaeger::Client.build is deprecated.' \
|
44
|
+
'Please use `reporter` instead.'
|
41
45
|
end
|
42
46
|
|
43
|
-
reporter
|
47
|
+
reporter ||= Reporters::RemoteReporter.new(
|
48
|
+
sender: sender || UdpSender.new(host: host, port: port, encoder: encoder, logger: logger),
|
49
|
+
flush_interval: flush_interval
|
50
|
+
)
|
44
51
|
|
45
52
|
Tracer.new(
|
46
53
|
reporter: reporter,
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
# RateLimiter is based on leaky bucket algorithm, formulated in terms of a
|
6
|
+
# credits balance that is replenished every time check_credit() method is
|
7
|
+
# called (tick) by the amount proportional to the time elapsed since the
|
8
|
+
# last tick, up to the max_balance. A call to check_credit() takes a cost
|
9
|
+
# of an item we want to pay with the balance. If the balance exceeds the
|
10
|
+
# cost of the item, the item is "purchased" and the balance reduced,
|
11
|
+
# indicated by returned value of true. Otherwise the balance is unchanged
|
12
|
+
# and return false.
|
13
|
+
#
|
14
|
+
# This can be used to limit a rate of messages emitted by a service by
|
15
|
+
# instantiating the Rate Limiter with the max number of messages a service
|
16
|
+
# is allowed to emit per second, and calling check_credit(1.0) for each
|
17
|
+
# message to determine if the message is within the rate limit.
|
18
|
+
#
|
19
|
+
# It can also be used to limit the rate of traffic in bytes, by setting
|
20
|
+
# credits_per_second to desired throughput as bytes/second, and calling
|
21
|
+
# check_credit() with the actual message size.
|
22
|
+
class RateLimiter
|
23
|
+
def initialize(credits_per_second:, max_balance:)
|
24
|
+
@credits_per_second = credits_per_second
|
25
|
+
@max_balance = max_balance
|
26
|
+
@balance = max_balance
|
27
|
+
@last_tick = Time.now
|
28
|
+
end
|
29
|
+
|
30
|
+
def check_credit(item_cost)
|
31
|
+
update_balance
|
32
|
+
|
33
|
+
return false if @balance < item_cost
|
34
|
+
|
35
|
+
@balance -= item_cost
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(credits_per_second:, max_balance:)
|
40
|
+
update_balance
|
41
|
+
|
42
|
+
@credits_per_second = credits_per_second
|
43
|
+
|
44
|
+
# The new balance should be proportional to the old balance
|
45
|
+
@balance = max_balance * @balance / @max_balance
|
46
|
+
@max_balance = max_balance
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def update_balance
|
52
|
+
current_time = Time.now
|
53
|
+
elapsed_time = current_time - @last_tick
|
54
|
+
@last_tick = current_time
|
55
|
+
|
56
|
+
@balance += elapsed_time * @credits_per_second
|
57
|
+
return if @balance <= @max_balance
|
58
|
+
|
59
|
+
@balance = @max_balance
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'reporters/composite_reporter'
|
4
|
+
require_relative 'reporters/in_memory_reporter'
|
5
|
+
require_relative 'reporters/logging_reporter'
|
6
|
+
require_relative 'reporters/null_reporter'
|
7
|
+
require_relative 'reporters/remote_reporter'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Reporters
|
6
|
+
class CompositeReporter
|
7
|
+
def initialize(reporters:)
|
8
|
+
@reporters = reporters
|
9
|
+
end
|
10
|
+
|
11
|
+
def report(span)
|
12
|
+
@reporters.each do |reporter|
|
13
|
+
reporter.report(span)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -2,25 +2,28 @@
|
|
2
2
|
|
3
3
|
module Jaeger
|
4
4
|
module Client
|
5
|
-
|
6
|
-
class
|
5
|
+
module Reporters
|
6
|
+
class InMemoryReporter
|
7
7
|
def initialize
|
8
|
-
@
|
8
|
+
@spans = []
|
9
9
|
@mutex = Mutex.new
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def report(span)
|
13
13
|
@mutex.synchronize do
|
14
|
-
@
|
15
|
-
true
|
14
|
+
@spans << span
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
|
-
def
|
18
|
+
def spans
|
20
19
|
@mutex.synchronize do
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
@spans
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def clear
|
25
|
+
@mutex.synchronize do
|
26
|
+
@spans.clear
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Reporters
|
6
|
+
class LoggingReporter
|
7
|
+
def initialize(logger: Logger.new($stdout))
|
8
|
+
@logger = logger
|
9
|
+
end
|
10
|
+
|
11
|
+
def report(span)
|
12
|
+
span_info = {
|
13
|
+
operation_name: span.operation_name,
|
14
|
+
start_time: span.start_time.iso8601,
|
15
|
+
end_time: span.end_time.iso8601,
|
16
|
+
trace_id: span.context.to_trace_id,
|
17
|
+
span_id: span.context.to_span_id
|
18
|
+
}
|
19
|
+
@logger.info "Span reported: #{span_info}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './remote_reporter/buffer'
|
4
|
+
|
5
|
+
module Jaeger
|
6
|
+
module Client
|
7
|
+
module Reporters
|
8
|
+
class RemoteReporter
|
9
|
+
def initialize(sender:, flush_interval:)
|
10
|
+
@sender = sender
|
11
|
+
@flush_interval = flush_interval
|
12
|
+
@buffer = Buffer.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def flush
|
16
|
+
spans = @buffer.retrieve
|
17
|
+
@sender.send_spans(spans) if spans.any?
|
18
|
+
spans
|
19
|
+
end
|
20
|
+
|
21
|
+
def report(span)
|
22
|
+
return if !span.context.sampled? && !span.context.debug?
|
23
|
+
|
24
|
+
init_reporter_thread
|
25
|
+
@buffer << span
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def init_reporter_thread
|
31
|
+
return if @initializer_pid == Process.pid
|
32
|
+
|
33
|
+
@initializer_pid = Process.pid
|
34
|
+
Thread.new do
|
35
|
+
loop do
|
36
|
+
flush
|
37
|
+
sleep(@flush_interval)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Reporters
|
6
|
+
class RemoteReporter
|
7
|
+
class Buffer
|
8
|
+
def initialize
|
9
|
+
@buffer = []
|
10
|
+
@mutex = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(element)
|
14
|
+
@mutex.synchronize do
|
15
|
+
@buffer << element
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def retrieve
|
21
|
+
@mutex.synchronize do
|
22
|
+
elements = @buffer.dup
|
23
|
+
@buffer.clear
|
24
|
+
elements
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -11,18 +11,15 @@ module Jaeger
|
|
11
11
|
class Const
|
12
12
|
def initialize(decision)
|
13
13
|
@decision = decision
|
14
|
-
@
|
14
|
+
@tags = {
|
15
|
+
'sampler.type' => 'const',
|
16
|
+
'sampler.param' => @decision ? 1 : 0
|
17
|
+
}
|
15
18
|
end
|
16
19
|
|
17
20
|
def sample?(*)
|
18
|
-
@decision
|
21
|
+
[@decision, @tags]
|
19
22
|
end
|
20
|
-
|
21
|
-
def type
|
22
|
-
'const'
|
23
|
-
end
|
24
|
-
|
25
|
-
attr_reader :param
|
26
23
|
end
|
27
24
|
end
|
28
25
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Samplers
|
6
|
+
# A sampler that leverages both Probabilistic sampler and RateLimiting
|
7
|
+
# sampler. The RateLimiting is used as a guaranteed lower bound sampler
|
8
|
+
# such that every operation is sampled at least once in a time interval
|
9
|
+
# defined by the lower_bound. ie a lower_bound of 1.0 / (60 * 10) will
|
10
|
+
# sample an operation at least once every 10 minutes.
|
11
|
+
#
|
12
|
+
# The Probabilistic sampler is given higher priority when tags are
|
13
|
+
# emitted, ie. if is_sampled() for both samplers return true, the tags
|
14
|
+
# for Probabilistic sampler will be used.
|
15
|
+
class GuaranteedThroughputProbabilistic
|
16
|
+
attr_reader :tags
|
17
|
+
|
18
|
+
def initialize(lower_bound:, rate:, lower_bound_sampler: nil)
|
19
|
+
@probabilistic_sampler = Probabilistic.new(rate: rate)
|
20
|
+
@lower_bound_sampler = lower_bound_sampler || RateLimiting.new(max_traces_per_second: lower_bound)
|
21
|
+
@lower_bound_tags = {
|
22
|
+
'sampler.type' => 'lowerbound',
|
23
|
+
'sampler.param' => lower_bound
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def sample?(*args)
|
28
|
+
is_sampled, probabilistic_tags = @probabilistic_sampler.sample?(*args)
|
29
|
+
if is_sampled
|
30
|
+
# We still call lower_bound_sampler to update the rate limiter budget
|
31
|
+
@lower_bound_sampler.sample?(*args)
|
32
|
+
|
33
|
+
return [is_sampled, probabilistic_tags]
|
34
|
+
end
|
35
|
+
|
36
|
+
is_sampled, _tags = @lower_bound_sampler.sample?(*args)
|
37
|
+
[is_sampled, @lower_bound_tags]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Samplers
|
6
|
+
# A sampler that leverages both Probabilistic sampler and RateLimiting
|
7
|
+
# sampler via the GuaranteedThroughputProbabilistic sampler. This sampler
|
8
|
+
# keeps track of all operations and delegates calls the the respective
|
9
|
+
# GuaranteedThroughputProbabilistic sampler.
|
10
|
+
class PerOperation
|
11
|
+
DEFAULT_SAMPLING_PROBABILITY = 0.001
|
12
|
+
DEFAULT_LOWER_BOUND = 1.0 / (10.0 * 60.0) # sample once every 10 minutes'
|
13
|
+
|
14
|
+
def initialize(strategies:, max_operations:)
|
15
|
+
@max_operations = max_operations
|
16
|
+
@default_sampling_probability =
|
17
|
+
strategies[:default_sampling_probability] || DEFAULT_SAMPLING_PROBABILITY
|
18
|
+
@lower_bound = strategies[:default_lower_bound_traces_per_second] || DEFAULT_LOWER_BOUND
|
19
|
+
|
20
|
+
@default_sampler = Probabilistic.new(rate: @default_sampling_probability)
|
21
|
+
@samplers = (strategies[:per_operation_strategies] || []).reduce({}) do |acc, strategy|
|
22
|
+
operation = strategy.fetch(:operation)
|
23
|
+
rate = strategy.fetch(:probabilistic_sampling)
|
24
|
+
sampler = GuaranteedThroughputProbabilistic.new(
|
25
|
+
lower_bound: @lower_bound,
|
26
|
+
rate: rate
|
27
|
+
)
|
28
|
+
acc.merge(operation => sampler)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def sample?(opts)
|
33
|
+
operation_name = opts.fetch(:operation_name)
|
34
|
+
sampler = @samplers[operation_name]
|
35
|
+
return sampler.sample?(opts) if sampler
|
36
|
+
|
37
|
+
return @default_sampler.sample?(opts) if @samplers.length >= @max_operations
|
38
|
+
|
39
|
+
sampler = GuaranteedThroughputProbabilistic.new(
|
40
|
+
lower_bound: @lower_bound,
|
41
|
+
rate: @default_sampling_probability
|
42
|
+
)
|
43
|
+
@samplers[operation_name] = sampler
|
44
|
+
sampler.sample?(opts)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -8,22 +8,20 @@ module Jaeger
|
|
8
8
|
# Sample a portion of traces using trace_id as the random decision
|
9
9
|
class Probabilistic
|
10
10
|
def initialize(rate: 0.001)
|
11
|
-
@param = rate.to_s
|
12
11
|
if rate < 0.0 || rate > 1.0
|
13
12
|
raise "Sampling rate must be between 0.0 and 1.0, got #{rate.inspect}"
|
14
13
|
end
|
15
|
-
@boundary = TraceId::TRACE_ID_UPPER_BOUND * rate
|
16
|
-
end
|
17
14
|
|
18
|
-
|
19
|
-
@
|
15
|
+
@boundary = TraceId::TRACE_ID_UPPER_BOUND * rate
|
16
|
+
@tags = {
|
17
|
+
'sampler.type' => 'probabilistic',
|
18
|
+
'sampler.param' => rate
|
19
|
+
}
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
|
22
|
+
def sample?(trace_id:, **)
|
23
|
+
[@boundary >= trace_id, @tags]
|
24
24
|
end
|
25
|
-
|
26
|
-
attr_reader :param
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Samplers
|
6
|
+
# Samples at most max_traces_per_second. The distribution of sampled
|
7
|
+
# traces follows burstiness of the service, i.e. a service with uniformly
|
8
|
+
# distributed requests will have those requests sampled uniformly as
|
9
|
+
# well, but if requests are bursty, especially sub-second, then a number
|
10
|
+
# of sequential requests can be sampled each second.
|
11
|
+
class RateLimiting
|
12
|
+
attr_reader :tags
|
13
|
+
|
14
|
+
def initialize(max_traces_per_second: 10)
|
15
|
+
if max_traces_per_second < 0.0
|
16
|
+
raise "max_traces_per_second must not be negative, got #{max_traces_per_second}"
|
17
|
+
end
|
18
|
+
|
19
|
+
@rate_limiter = RateLimiter.new(
|
20
|
+
credits_per_second: max_traces_per_second,
|
21
|
+
max_balance: [max_traces_per_second, 1.0].max
|
22
|
+
)
|
23
|
+
@tags = {
|
24
|
+
'sampler.type' => 'ratelimiting',
|
25
|
+
'sampler.param' => max_traces_per_second
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def sample?(*)
|
30
|
+
[@rate_limiter.check_credit(1.0), @tags]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -10,13 +10,6 @@ module Jaeger
|
|
10
10
|
DEBUG = 0x02
|
11
11
|
end
|
12
12
|
|
13
|
-
def self.create_parent_context(sampler = Samplers::Const.new(true))
|
14
|
-
trace_id = TraceId.generate
|
15
|
-
span_id = TraceId.generate
|
16
|
-
flags = sampler.sample?(trace_id) ? Flags::SAMPLED : Flags::NONE
|
17
|
-
new(trace_id: trace_id, span_id: span_id, flags: flags)
|
18
|
-
end
|
19
|
-
|
20
13
|
def self.create_from_parent_context(span_context)
|
21
14
|
new(
|
22
15
|
trace_id: span_context.trace_id,
|
data/lib/jaeger/client/tracer.rb
CHANGED
@@ -50,7 +50,8 @@ module Jaeger
|
|
50
50
|
tags: {},
|
51
51
|
ignore_active_scope: false,
|
52
52
|
**)
|
53
|
-
context = prepare_span_context(
|
53
|
+
context, sampler_tags = prepare_span_context(
|
54
|
+
operation_name: operation_name,
|
54
55
|
child_of: child_of,
|
55
56
|
references: references,
|
56
57
|
ignore_active_scope: ignore_active_scope
|
@@ -61,10 +62,7 @@ module Jaeger
|
|
61
62
|
@reporter,
|
62
63
|
start_time: start_time,
|
63
64
|
references: references,
|
64
|
-
tags: tags.merge(
|
65
|
-
:'sampler.type' => @sampler.type,
|
66
|
-
:'sampler.param' => @sampler.param
|
67
|
-
)
|
65
|
+
tags: tags.merge(sampler_tags)
|
68
66
|
)
|
69
67
|
end
|
70
68
|
|
@@ -150,16 +148,26 @@ module Jaeger
|
|
150
148
|
|
151
149
|
private
|
152
150
|
|
153
|
-
def prepare_span_context(child_of:, references:, ignore_active_scope:)
|
151
|
+
def prepare_span_context(operation_name:, child_of:, references:, ignore_active_scope:)
|
154
152
|
context =
|
155
153
|
context_from_child_of(child_of) ||
|
156
154
|
context_from_references(references) ||
|
157
155
|
context_from_active_scope(ignore_active_scope)
|
158
156
|
|
159
157
|
if context
|
160
|
-
SpanContext.create_from_parent_context(context)
|
158
|
+
[SpanContext.create_from_parent_context(context), {}]
|
161
159
|
else
|
162
|
-
|
160
|
+
trace_id = TraceId.generate
|
161
|
+
is_sampled, tags = @sampler.sample?(
|
162
|
+
trace_id: trace_id,
|
163
|
+
operation_name: operation_name
|
164
|
+
)
|
165
|
+
span_context = SpanContext.new(
|
166
|
+
trace_id: trace_id,
|
167
|
+
span_id: trace_id,
|
168
|
+
flags: is_sampled ? SpanContext::Flags::SAMPLED : SpanContext::Flags::NONE
|
169
|
+
)
|
170
|
+
[span_context, tags]
|
163
171
|
end
|
164
172
|
end
|
165
173
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jaeger-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SaleMove TechMovers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-12-
|
11
|
+
date: 2018-12-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.24.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: timecop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.9'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.9'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: opentracing
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,16 +150,25 @@ files:
|
|
136
150
|
- crossdock/server
|
137
151
|
- jaeger-client.gemspec
|
138
152
|
- lib/jaeger/client.rb
|
139
|
-
- lib/jaeger/client/async_reporter.rb
|
140
|
-
- lib/jaeger/client/async_reporter/buffer.rb
|
141
153
|
- lib/jaeger/client/carrier.rb
|
142
154
|
- lib/jaeger/client/encoders/thrift_encoder.rb
|
143
155
|
- lib/jaeger/client/extractors.rb
|
144
156
|
- lib/jaeger/client/http_sender.rb
|
145
157
|
- lib/jaeger/client/injectors.rb
|
158
|
+
- lib/jaeger/client/rate_limiter.rb
|
159
|
+
- lib/jaeger/client/reporters.rb
|
160
|
+
- lib/jaeger/client/reporters/composite_reporter.rb
|
161
|
+
- lib/jaeger/client/reporters/in_memory_reporter.rb
|
162
|
+
- lib/jaeger/client/reporters/logging_reporter.rb
|
163
|
+
- lib/jaeger/client/reporters/null_reporter.rb
|
164
|
+
- lib/jaeger/client/reporters/remote_reporter.rb
|
165
|
+
- lib/jaeger/client/reporters/remote_reporter/buffer.rb
|
146
166
|
- lib/jaeger/client/samplers.rb
|
147
167
|
- lib/jaeger/client/samplers/const.rb
|
168
|
+
- lib/jaeger/client/samplers/guaranteed_throughput_probabilistic.rb
|
169
|
+
- lib/jaeger/client/samplers/per_operation.rb
|
148
170
|
- lib/jaeger/client/samplers/probabilistic.rb
|
171
|
+
- lib/jaeger/client/samplers/rate_limiting.rb
|
149
172
|
- lib/jaeger/client/scope.rb
|
150
173
|
- lib/jaeger/client/scope_manager.rb
|
151
174
|
- lib/jaeger/client/scope_manager/scope_identifier.rb
|
@@ -176,7 +199,7 @@ files:
|
|
176
199
|
- thrift/gen-rb/jaeger/thrift/zipkin/zipkincore_types.rb
|
177
200
|
- thrift/jaeger.thrift
|
178
201
|
- thrift/zipkincore.thrift
|
179
|
-
homepage:
|
202
|
+
homepage: https://github.com/salemove/jaeger-client-ruby
|
180
203
|
licenses:
|
181
204
|
- MIT
|
182
205
|
metadata: {}
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'thread'
|
4
|
-
|
5
|
-
require_relative './async_reporter/buffer'
|
6
|
-
|
7
|
-
module Jaeger
|
8
|
-
module Client
|
9
|
-
class AsyncReporter
|
10
|
-
def self.create(sender:, flush_interval:)
|
11
|
-
new(sender, flush_interval)
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(sender, flush_interval)
|
15
|
-
@sender = sender
|
16
|
-
@flush_interval = flush_interval
|
17
|
-
@buffer = Buffer.new
|
18
|
-
end
|
19
|
-
|
20
|
-
def flush
|
21
|
-
spans = @buffer.retrieve
|
22
|
-
@sender.send_spans(spans) if spans.any?
|
23
|
-
spans
|
24
|
-
end
|
25
|
-
|
26
|
-
def report(span)
|
27
|
-
return if !span.context.sampled? && !span.context.debug?
|
28
|
-
|
29
|
-
init_reporter_thread
|
30
|
-
@buffer << span
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def init_reporter_thread
|
36
|
-
return if @initializer_pid == Process.pid
|
37
|
-
|
38
|
-
@initializer_pid = Process.pid
|
39
|
-
Thread.new do
|
40
|
-
loop do
|
41
|
-
flush
|
42
|
-
sleep(@flush_interval)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|