jaeger-client 0.8.0 → 0.9.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/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
|