jaeger-client 0.10.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +49 -2
- data/jaeger-client.gemspec +2 -1
- data/lib/jaeger/client.rb +9 -2
- data/lib/jaeger/client/version.rb +1 -1
- data/lib/jaeger/encoders/thrift_encoder.rb +80 -30
- data/lib/jaeger/extractors.rb +64 -6
- data/lib/jaeger/injectors.rb +19 -5
- data/lib/jaeger/recurring_executor.rb +35 -0
- data/lib/jaeger/samplers.rb +1 -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 +46 -14
- data/lib/jaeger/samplers/probabilistic.rb +13 -1
- data/lib/jaeger/samplers/rate_limiting.rb +24 -6
- data/lib/jaeger/samplers/remote_controlled.rb +119 -0
- data/lib/jaeger/samplers/remote_controlled/instructions_fetcher.rb +34 -0
- data/lib/jaeger/span.rb +0 -1
- data/lib/jaeger/thrift_tag_builder.rb +41 -0
- data/lib/jaeger/trace_id.rb +9 -0
- data/lib/jaeger/tracer.rb +26 -8
- data/lib/jaeger/udp_sender.rb +6 -4
- metadata +25 -9
- data/lib/jaeger/span/thrift_tag_builder.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f4b7e773d00ccb0b54390db7b973e674733017ed4c1253bab10931ffdc6358f
|
4
|
+
data.tar.gz: b03393cae166cc9a189f3629cfa2a6eb5eb06fe975e2225aa3c2cc1ffb6ebe36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fa33017d53652e38133d4dab7d134b0d7ff1ee262e07a70b9c9114d80831eaad2f88df16b467ebe7c167c80798e34c39a70b33472d1cf204314d922a43b98d1
|
7
|
+
data.tar.gz: 3a7b325ee92c532bf2b1c50c40fd483cf42458d51e9148f63dc98f0c56513e3d0dc3c2a36ec04f07c8953cff91e162b430d1ebb0d9ccc50f51796db9dea3c62d
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -109,8 +109,8 @@ Set `sampler` to
|
|
109
109
|
Jaeger::Samplers::PerOperation.new(
|
110
110
|
strategies: {
|
111
111
|
per_operation_strategies: [
|
112
|
-
{ operation: 'GET /articles', probabilistic_sampling: 0.5 },
|
113
|
-
{ operation: 'POST /articles', probabilistic_sampling: 1.0 }
|
112
|
+
{ operation: 'GET /articles', probabilistic_sampling: { sampling_rate: 0.5 } },
|
113
|
+
{ operation: 'POST /articles', probabilistic_sampling: { sampling_rate: 1.0 } }
|
114
114
|
],
|
115
115
|
default_sampling_probability: 0.001,
|
116
116
|
default_lower_bound_traces_per_second: 1.0 / (10.0 * 60.0)
|
@@ -119,6 +119,39 @@ Set `sampler` to
|
|
119
119
|
)
|
120
120
|
```
|
121
121
|
|
122
|
+
#### RemoteControlled sampler
|
123
|
+
|
124
|
+
`RemoteControlled` sampler is a sampler that is controller by jaeger agent. It starts out with `Probabilistic` sampler. It polls the jaeger-agent and changes sampling strategy accordingly. Set `sampler` to `Jaeger::Client::Samplers::RemoteControlled.new(service_name: 'service_name')`.
|
125
|
+
|
126
|
+
RemoteControlled sampler options:
|
127
|
+
|
128
|
+
| Param | Required | Description |
|
129
|
+
|-------------------|----------|-------------|
|
130
|
+
| service_name | x | name of the current service / application, same as given to Tracer |
|
131
|
+
| sampler | | initial sampler to use prior to retrieving strategies from Agent |
|
132
|
+
| refresh_interval | | interval in seconds before sampling strategy refreshes (0 to not refresh, defaults to 60) |
|
133
|
+
| host | | host for jaeger-agent (defaults to 'localhost') |
|
134
|
+
| port | | port for jaeger-agent for SamplingManager endpoint (defaults to 5778) |
|
135
|
+
| logger | | logger for communication between jaeger-agent (default to $stdout logger) |
|
136
|
+
|
137
|
+
### TraceContext compatible header propagation
|
138
|
+
|
139
|
+
It is possible to use [W3C Trace Context](https://www.w3.org/TR/trace-context/#overview) headers to propagate the tracing information.
|
140
|
+
|
141
|
+
To set it up you need to change FORMAT_RACK injector and extractor.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
OpenTracing.global_tracer = Jaeger::Client.build(
|
145
|
+
service_name: 'service_name',
|
146
|
+
injectors: {
|
147
|
+
OpenTracing::FORMAT_RACK => [Jaeger::Injectors::TraceContextRackCodec]
|
148
|
+
},
|
149
|
+
extractors: {
|
150
|
+
OpenTracing::FORMAT_RACK => [Jaeger::Extractors::TraceContextRackCodec]
|
151
|
+
}
|
152
|
+
)
|
153
|
+
```
|
154
|
+
|
122
155
|
### Zipkin HTTP B3 compatible header propagation
|
123
156
|
|
124
157
|
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.
|
@@ -141,6 +174,20 @@ It's also possible to set up multiple injectors and extractors. Each injector wi
|
|
141
174
|
|
142
175
|
If multiple extractors is used then the span context from the first match will be returned.
|
143
176
|
|
177
|
+
### Process Tags
|
178
|
+
|
179
|
+
Jaeger Tracer allows you to define process level tags. By default the tracer provides `jaeger.version`, `ip` and `hostname`. You may want to overwrite `ip` or `hostname` if the tracer cannot auto-detect them.
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
OpenTracing.global_tracer = Jaeger::Client.build(
|
183
|
+
service_name: 'service_name',
|
184
|
+
tags: {
|
185
|
+
'hostname' => 'custom-hostname',
|
186
|
+
'custom_tag' => 'custom-tag-value'
|
187
|
+
}
|
188
|
+
)
|
189
|
+
```
|
190
|
+
|
144
191
|
## Development
|
145
192
|
|
146
193
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/jaeger-client.gemspec
CHANGED
@@ -20,12 +20,13 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
|
-
spec.add_development_dependency 'bundler'
|
23
|
+
spec.add_development_dependency 'bundler'
|
24
24
|
spec.add_development_dependency 'rake', '~> 10.0'
|
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
28
|
spec.add_development_dependency 'timecop', '~> 0.9'
|
29
|
+
spec.add_development_dependency 'webmock', '~> 3.4.2'
|
29
30
|
|
30
31
|
spec.add_dependency 'opentracing', '~> 0.3'
|
31
32
|
spec.add_dependency 'thrift'
|
data/lib/jaeger/client.rb
CHANGED
@@ -5,6 +5,10 @@ $LOAD_PATH.push(File.dirname(__FILE__) + '/../../thrift/gen-rb')
|
|
5
5
|
require 'opentracing'
|
6
6
|
require 'jaeger/thrift/agent'
|
7
7
|
require 'logger'
|
8
|
+
require 'time'
|
9
|
+
require 'net/http'
|
10
|
+
require 'cgi'
|
11
|
+
require 'json'
|
8
12
|
|
9
13
|
require_relative 'tracer'
|
10
14
|
require_relative 'span'
|
@@ -21,6 +25,8 @@ require_relative 'encoders/thrift_encoder'
|
|
21
25
|
require_relative 'injectors'
|
22
26
|
require_relative 'extractors'
|
23
27
|
require_relative 'rate_limiter'
|
28
|
+
require_relative 'thrift_tag_builder'
|
29
|
+
require_relative 'recurring_executor'
|
24
30
|
|
25
31
|
module Jaeger
|
26
32
|
module Client
|
@@ -46,8 +52,9 @@ module Jaeger
|
|
46
52
|
sender: nil,
|
47
53
|
reporter: nil,
|
48
54
|
injectors: {},
|
49
|
-
extractors: {}
|
50
|
-
|
55
|
+
extractors: {},
|
56
|
+
tags: {})
|
57
|
+
encoder = Encoders::ThriftEncoder.new(service_name: service_name, tags: tags)
|
51
58
|
|
52
59
|
if sender
|
53
60
|
warn '[DEPRECATION] Passing `sender` directly to Jaeger::Client.build is deprecated.' \
|
@@ -3,49 +3,46 @@
|
|
3
3
|
module Jaeger
|
4
4
|
module Encoders
|
5
5
|
class ThriftEncoder
|
6
|
-
def initialize(service_name:)
|
6
|
+
def initialize(service_name:, tags: {})
|
7
7
|
@service_name = service_name
|
8
|
-
@tags =
|
9
|
-
|
10
|
-
'key' => 'jaeger.version',
|
11
|
-
'vType' => Jaeger::Thrift::TagType::STRING,
|
12
|
-
'vStr' => 'Ruby-' + Jaeger::Client::VERSION
|
13
|
-
),
|
14
|
-
Jaeger::Thrift::Tag.new(
|
15
|
-
'key' => 'hostname',
|
16
|
-
'vType' => Jaeger::Thrift::TagType::STRING,
|
17
|
-
'vStr' => Socket.gethostname
|
18
|
-
)
|
19
|
-
]
|
20
|
-
ipv4 = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }
|
21
|
-
unless ipv4.nil? # rubocop:disable Style/GuardClause
|
22
|
-
@tags << Jaeger::Thrift::Tag.new(
|
23
|
-
'key' => 'ip',
|
24
|
-
'vType' => Jaeger::Thrift::TagType::STRING,
|
25
|
-
'vStr' => ipv4.ip_address
|
26
|
-
)
|
27
|
-
end
|
8
|
+
@tags = prepare_tags(tags)
|
9
|
+
@process = Jaeger::Thrift::Process.new('serviceName' => @service_name, 'tags' => @tags)
|
28
10
|
end
|
29
11
|
|
30
12
|
def encode(spans)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
13
|
+
encode_batch(spans.map(&method(:encode_span)))
|
14
|
+
end
|
15
|
+
|
16
|
+
def encode_limited_size(spans, protocol_class, max_message_length)
|
17
|
+
batches = []
|
18
|
+
current_batch = []
|
19
|
+
transport.flush
|
20
|
+
spans.each do |span|
|
21
|
+
encoded_span = encode_span(span)
|
22
|
+
if aggregated_span_size(encoded_span, protocol_class) > max_message_length && !current_batch.empty?
|
23
|
+
batches << encode_batch(current_batch)
|
24
|
+
current_batch = []
|
25
|
+
transport.flush
|
26
|
+
end
|
27
|
+
current_batch << encoded_span
|
28
|
+
end
|
29
|
+
batches << encode_batch(current_batch) unless current_batch.empty?
|
30
|
+
batches
|
38
31
|
end
|
39
32
|
|
40
33
|
private
|
41
34
|
|
35
|
+
def encode_batch(encoded_spans)
|
36
|
+
Jaeger::Thrift::Batch.new('process' => @process, 'spans' => encoded_spans)
|
37
|
+
end
|
38
|
+
|
42
39
|
def encode_span(span)
|
43
40
|
context = span.context
|
44
41
|
start_ts, duration = build_timestamps(span)
|
45
42
|
|
46
43
|
Jaeger::Thrift::Span.new(
|
47
|
-
'traceIdLow' => TraceId.uint64_id_to_int64(context.trace_id),
|
48
|
-
'traceIdHigh' =>
|
44
|
+
'traceIdLow' => TraceId.uint64_id_to_int64(trace_id_to_low(context.trace_id)),
|
45
|
+
'traceIdHigh' => TraceId.uint64_id_to_int64(trace_id_to_high(context.trace_id)),
|
49
46
|
'spanId' => TraceId.uint64_id_to_int64(context.span_id),
|
50
47
|
'parentSpanId' => TraceId.uint64_id_to_int64(context.parent_id),
|
51
48
|
'operationName' => span.operation_name,
|
@@ -87,6 +84,59 @@ module Jaeger
|
|
87
84
|
nil
|
88
85
|
end
|
89
86
|
end
|
87
|
+
|
88
|
+
def prepare_tags(tags)
|
89
|
+
with_default_tags = tags.dup
|
90
|
+
with_default_tags['jaeger.version'] = 'Ruby-' + Jaeger::Client::VERSION
|
91
|
+
with_default_tags['hostname'] ||= Socket.gethostname
|
92
|
+
|
93
|
+
unless with_default_tags['ip']
|
94
|
+
ipv4 = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }
|
95
|
+
with_default_tags['ip'] = ipv4.ip_address unless ipv4.nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
with_default_tags.map do |key, value|
|
99
|
+
ThriftTagBuilder.build(key, value)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns the right most 64 bits of trace id
|
104
|
+
def trace_id_to_low(trace_id)
|
105
|
+
trace_id & TraceId::MAX_64BIT_UNSIGNED_INT
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns the left most 64 bits of trace id
|
109
|
+
def trace_id_to_high(trace_id)
|
110
|
+
(trace_id >> 64) & TraceId::MAX_64BIT_UNSIGNED_INT
|
111
|
+
end
|
112
|
+
|
113
|
+
class DummyTransport
|
114
|
+
attr_accessor :size
|
115
|
+
|
116
|
+
def initialize
|
117
|
+
@size = 0
|
118
|
+
end
|
119
|
+
|
120
|
+
def write(buf)
|
121
|
+
@size += buf.size
|
122
|
+
end
|
123
|
+
|
124
|
+
def flush
|
125
|
+
@size = 0
|
126
|
+
end
|
127
|
+
|
128
|
+
def close; end
|
129
|
+
end
|
130
|
+
|
131
|
+
def aggregated_span_size(span, protocol_class)
|
132
|
+
@protocol ||= protocol_class.new(transport)
|
133
|
+
span.write(@protocol)
|
134
|
+
transport.size
|
135
|
+
end
|
136
|
+
|
137
|
+
def transport
|
138
|
+
@transport ||= DummyTransport.new
|
139
|
+
end
|
90
140
|
end
|
91
141
|
end
|
92
142
|
end
|
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,11 +65,39 @@ module Jaeger
|
|
63
65
|
end
|
64
66
|
|
65
67
|
class B3RackCodec
|
68
|
+
class Keys
|
69
|
+
TRACE_ID = 'HTTP_X_B3_TRACEID'.freeze
|
70
|
+
SPAN_ID = 'HTTP_X_B3_SPANID'.freeze
|
71
|
+
PARENT_SPAN_ID = 'HTTP_X_B3_PARENTSPANID'.freeze
|
72
|
+
FLAGS = 'HTTP_X_B3_FLAGS'.freeze
|
73
|
+
SAMPLED = 'HTTP_X_B3_SAMPLED'.freeze
|
74
|
+
end.freeze
|
75
|
+
|
66
76
|
def self.extract(carrier)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
77
|
+
B3CodecCommon.extract(carrier, Keys)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class B3TextMapCodec
|
82
|
+
class Keys
|
83
|
+
TRACE_ID = 'x-b3-traceid'.freeze
|
84
|
+
SPAN_ID = 'x-b3-spanid'.freeze
|
85
|
+
PARENT_SPAN_ID = 'x-b3-parentspanid'.freeze
|
86
|
+
FLAGS = 'x-b3-flags'.freeze
|
87
|
+
SAMPLED = 'x-b3-sampled'.freeze
|
88
|
+
end.freeze
|
89
|
+
|
90
|
+
def self.extract(carrier)
|
91
|
+
B3CodecCommon.extract(carrier, Keys)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class B3CodecCommon
|
96
|
+
def self.extract(carrier, keys)
|
97
|
+
trace_id = TraceId.base16_hex_id_to_uint64(carrier[keys::TRACE_ID])
|
98
|
+
span_id = TraceId.base16_hex_id_to_uint64(carrier[keys::SPAN_ID])
|
99
|
+
parent_id = TraceId.base16_hex_id_to_uint64(carrier[keys::PARENT_SPAN_ID])
|
100
|
+
flags = parse_flags(carrier[keys::FLAGS], carrier[keys::SAMPLED])
|
71
101
|
|
72
102
|
return nil if span_id.nil? || trace_id.nil?
|
73
103
|
return nil if span_id.zero? || trace_id.zero?
|
@@ -91,6 +121,34 @@ module Jaeger
|
|
91
121
|
private_class_method :parse_flags
|
92
122
|
end
|
93
123
|
|
124
|
+
class TraceContextRackCodec
|
125
|
+
# Internal regex used to identify the TraceContext version
|
126
|
+
VERSION_PATTERN = /^([0-9a-fA-F]{2})-(.+)$/
|
127
|
+
|
128
|
+
# Internal regex used to parse fields in version 0
|
129
|
+
HEADER_V0_PATTERN = /^([0-9a-fA-F]{32})-([0-9a-fA-F]{16})(-([0-9a-fA-F]{2}))?$/
|
130
|
+
|
131
|
+
def self.extract(carrier)
|
132
|
+
header_value = carrier['HTTP_TRACEPARENT']
|
133
|
+
|
134
|
+
version_match = VERSION_PATTERN.match(header_value)
|
135
|
+
return nil unless version_match
|
136
|
+
|
137
|
+
# We currently only support version 0
|
138
|
+
return nil if version_match[1].to_i(16) != 0
|
139
|
+
|
140
|
+
match = HEADER_V0_PATTERN.match(version_match[2])
|
141
|
+
return nil unless match
|
142
|
+
|
143
|
+
trace_id = TraceId.base16_hex_id_to_uint128(match[1])
|
144
|
+
span_id = TraceId.base16_hex_id_to_uint64(match[2])
|
145
|
+
flags = TraceId.base16_hex_id_to_uint64(match[4])
|
146
|
+
return nil if trace_id.zero? || span_id.zero?
|
147
|
+
|
148
|
+
SpanContext.new(trace_id: trace_id, span_id: span_id, flags: flags)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
94
152
|
DEFAULT_EXTRACTORS = {
|
95
153
|
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
96
154
|
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
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 && @thread.alive?
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop
|
31
|
+
@thread.kill
|
32
|
+
@thread = nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/jaeger/samplers.rb
CHANGED
@@ -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(*args)
|
34
|
+
is_sampled, probabilistic_tags = @probabilistic_sampler.sample(*args)
|
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(*args)
|
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(*args)
|
36
43
|
[is_sampled, @lower_bound_tags]
|
37
44
|
end
|
38
45
|
end
|
@@ -10,37 +10,69 @@ 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
|
+
is_updated = update_operation_strategies(strategies) || is_updated
|
36
|
+
|
37
|
+
is_updated
|
29
38
|
end
|
30
39
|
|
31
|
-
def sample
|
40
|
+
def sample(opts)
|
32
41
|
operation_name = opts.fetch(:operation_name)
|
33
42
|
sampler = @samplers[operation_name]
|
34
|
-
return sampler.sample
|
43
|
+
return sampler.sample(opts) if sampler
|
35
44
|
|
36
|
-
return @default_sampler.sample
|
45
|
+
return @default_sampler.sample(opts) if @samplers.length >= @max_operations
|
37
46
|
|
38
47
|
sampler = GuaranteedThroughputProbabilistic.new(
|
39
48
|
lower_bound: @lower_bound,
|
40
49
|
rate: @default_sampling_probability
|
41
50
|
)
|
42
51
|
@samplers[operation_name] = sampler
|
43
|
-
sampler.sample
|
52
|
+
sampler.sample(opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def update_operation_strategies(strategies)
|
58
|
+
is_updated = false
|
59
|
+
|
60
|
+
(strategies[:per_operation_strategies] || []).each do |strategy|
|
61
|
+
operation = strategy.fetch(:operation)
|
62
|
+
rate = strategy.fetch(:probabilistic_sampling).fetch(:sampling_rate)
|
63
|
+
|
64
|
+
if (sampler = @samplers[operation])
|
65
|
+
is_updated = sampler.update(lower_bound: @lower_bound, rate: rate) || is_updated
|
66
|
+
else
|
67
|
+
@samplers[operation] = GuaranteedThroughputProbabilistic.new(
|
68
|
+
lower_bound: @lower_bound,
|
69
|
+
rate: rate
|
70
|
+
)
|
71
|
+
is_updated = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
is_updated
|
44
76
|
end
|
45
77
|
end
|
46
78
|
end
|
@@ -6,19 +6,31 @@ 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(trace_id:, **)
|
22
34
|
[@boundary >= trace_id, @tags]
|
23
35
|
end
|
24
36
|
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,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'.freeze
|
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
|
@@ -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
|
data/lib/jaeger/span.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
class ThriftTagBuilder
|
5
|
+
FIELDS = Jaeger::Thrift::Tag::FIELDS
|
6
|
+
KEY = FIELDS[Jaeger::Thrift::Tag::KEY].fetch(:name)
|
7
|
+
VTYPE = FIELDS[Jaeger::Thrift::Tag::VTYPE].fetch(:name)
|
8
|
+
VLONG = FIELDS[Jaeger::Thrift::Tag::VLONG].fetch(:name)
|
9
|
+
VDOUBLE = FIELDS[Jaeger::Thrift::Tag::VDOUBLE].fetch(:name)
|
10
|
+
VBOOL = FIELDS[Jaeger::Thrift::Tag::VBOOL].fetch(:name)
|
11
|
+
VSTR = FIELDS[Jaeger::Thrift::Tag::VSTR].fetch(:name)
|
12
|
+
|
13
|
+
def self.build(key, value)
|
14
|
+
if value.is_a?(Integer)
|
15
|
+
Jaeger::Thrift::Tag.new(
|
16
|
+
KEY => key.to_s,
|
17
|
+
VTYPE => Jaeger::Thrift::TagType::LONG,
|
18
|
+
VLONG => value
|
19
|
+
)
|
20
|
+
elsif value.is_a?(Float)
|
21
|
+
Jaeger::Thrift::Tag.new(
|
22
|
+
KEY => key.to_s,
|
23
|
+
VTYPE => Jaeger::Thrift::TagType::DOUBLE,
|
24
|
+
VDOUBLE => value
|
25
|
+
)
|
26
|
+
elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
27
|
+
Jaeger::Thrift::Tag.new(
|
28
|
+
KEY => key.to_s,
|
29
|
+
VTYPE => Jaeger::Thrift::TagType::BOOL,
|
30
|
+
VBOOL => value
|
31
|
+
)
|
32
|
+
else
|
33
|
+
Jaeger::Thrift::Tag.new(
|
34
|
+
KEY => key.to_s,
|
35
|
+
VTYPE => Jaeger::Thrift::TagType::STRING,
|
36
|
+
VSTR => value.to_s
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/jaeger/trace_id.rb
CHANGED
@@ -4,6 +4,7 @@ module Jaeger
|
|
4
4
|
module TraceId
|
5
5
|
MAX_64BIT_SIGNED_INT = (1 << 63) - 1
|
6
6
|
MAX_64BIT_UNSIGNED_INT = (1 << 64) - 1
|
7
|
+
MAX_128BIT_UNSIGNED_INT = (1 << 128) - 1
|
7
8
|
TRACE_ID_UPPER_BOUND = MAX_64BIT_UNSIGNED_INT + 1
|
8
9
|
|
9
10
|
def self.generate
|
@@ -12,10 +13,18 @@ module Jaeger
|
|
12
13
|
|
13
14
|
def self.base16_hex_id_to_uint64(id)
|
14
15
|
return nil unless id
|
16
|
+
|
15
17
|
value = id.to_i(16)
|
16
18
|
value > MAX_64BIT_UNSIGNED_INT || value < 0 ? 0 : value
|
17
19
|
end
|
18
20
|
|
21
|
+
def self.base16_hex_id_to_uint128(id)
|
22
|
+
return nil unless id
|
23
|
+
|
24
|
+
value = id.to_i(16)
|
25
|
+
value > MAX_128BIT_UNSIGNED_INT || value < 0 ? 0 : value
|
26
|
+
end
|
27
|
+
|
19
28
|
# Thrift defines ID fields as i64, which is signed, therefore we convert
|
20
29
|
# large IDs (> 2^63) to negative longs
|
21
30
|
def self.uint64_id_to_int64(id)
|
data/lib/jaeger/tracer.rb
CHANGED
@@ -41,7 +41,13 @@ module Jaeger
|
|
41
41
|
# @param ignore_active_scope [Boolean] whether to create an implicit
|
42
42
|
# References#CHILD_OF reference to the ScopeManager#active.
|
43
43
|
#
|
44
|
-
# @
|
44
|
+
# @yield [Span] If passed an optional block, start_span will yield the
|
45
|
+
# newly-created span to the block. The span will be finished automatically
|
46
|
+
# after the block is executed.
|
47
|
+
# @return [Span, Object] If passed an optional block, start_span will return
|
48
|
+
# the block's return value, otherwise it returns the newly-started Span
|
49
|
+
# instance, which has not been automatically registered via the
|
50
|
+
# ScopeManager
|
45
51
|
def start_span(operation_name,
|
46
52
|
child_of: nil,
|
47
53
|
references: nil,
|
@@ -55,7 +61,7 @@ module Jaeger
|
|
55
61
|
references: references,
|
56
62
|
ignore_active_scope: ignore_active_scope
|
57
63
|
)
|
58
|
-
Span.new(
|
64
|
+
span = Span.new(
|
59
65
|
context,
|
60
66
|
operation_name,
|
61
67
|
@reporter,
|
@@ -63,6 +69,16 @@ module Jaeger
|
|
63
69
|
references: references,
|
64
70
|
tags: tags.merge(sampler_tags)
|
65
71
|
)
|
72
|
+
|
73
|
+
if block_given?
|
74
|
+
begin
|
75
|
+
yield(span)
|
76
|
+
ensure
|
77
|
+
span.finish
|
78
|
+
end
|
79
|
+
else
|
80
|
+
span
|
81
|
+
end
|
66
82
|
end
|
67
83
|
|
68
84
|
# Creates a newly started and activated Scope
|
@@ -87,10 +103,12 @@ module Jaeger
|
|
87
103
|
# References#CHILD_OF reference to the ScopeManager#active.
|
88
104
|
# @param finish_on_close [Boolean] whether span should automatically be
|
89
105
|
# finished when Scope#close is called
|
90
|
-
# @yield [Scope] If an optional block is passed to
|
91
|
-
# yield the newly-started Scope. If `finish_on_close` is true then the
|
106
|
+
# @yield [Scope] If an optional block is passed to start_active_span it
|
107
|
+
# will yield the newly-started Scope. If `finish_on_close` is true then the
|
92
108
|
# Span will be finished automatically after the block is executed.
|
93
|
-
# @return [Scope]
|
109
|
+
# @return [Scope, Object] If passed an optional block, start_active_span
|
110
|
+
# returns the block's return value, otherwise it returns the newly-started
|
111
|
+
# and activated Scope
|
94
112
|
def start_active_span(operation_name,
|
95
113
|
child_of: nil,
|
96
114
|
references: nil,
|
@@ -115,9 +133,9 @@ module Jaeger
|
|
115
133
|
ensure
|
116
134
|
scope.close
|
117
135
|
end
|
136
|
+
else
|
137
|
+
scope
|
118
138
|
end
|
119
|
-
|
120
|
-
scope
|
121
139
|
end
|
122
140
|
|
123
141
|
# Inject a SpanContext into the given carrier
|
@@ -157,7 +175,7 @@ module Jaeger
|
|
157
175
|
[SpanContext.create_from_parent_context(context), {}]
|
158
176
|
else
|
159
177
|
trace_id = TraceId.generate
|
160
|
-
is_sampled, tags = @sampler.sample
|
178
|
+
is_sampled, tags = @sampler.sample(
|
161
179
|
trace_id: trace_id,
|
162
180
|
operation_name: operation_name
|
163
181
|
)
|
data/lib/jaeger/udp_sender.rb
CHANGED
@@ -5,18 +5,20 @@ require 'socket'
|
|
5
5
|
|
6
6
|
module Jaeger
|
7
7
|
class UdpSender
|
8
|
-
def initialize(host:, port:, encoder:, logger:)
|
8
|
+
def initialize(host:, port:, encoder:, logger:, max_packet_size: 65_000)
|
9
9
|
@encoder = encoder
|
10
10
|
@logger = logger
|
11
11
|
|
12
12
|
transport = Transport.new(host, port)
|
13
|
-
|
13
|
+
@protocol_class = ::Thrift::CompactProtocol
|
14
|
+
protocol = @protocol_class.new(transport)
|
14
15
|
@client = Jaeger::Thrift::Agent::Client.new(protocol)
|
16
|
+
@max_packet_size = max_packet_size
|
15
17
|
end
|
16
18
|
|
17
19
|
def send_spans(spans)
|
18
|
-
|
19
|
-
@client.emitBatch(batch)
|
20
|
+
batches = @encoder.encode_limited_size(spans, @protocol_class, @max_packet_size)
|
21
|
+
batches.each { |batch| @client.emitBatch(batch) }
|
20
22
|
rescue StandardError => error
|
21
23
|
@logger.error("Failure while sending a batch of spans: #{error}")
|
22
24
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jaeger-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.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:
|
11
|
+
date: 2019-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0.9'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.4.2
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 3.4.2
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: opentracing
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,6 +170,7 @@ files:
|
|
156
170
|
- lib/jaeger/http_sender.rb
|
157
171
|
- lib/jaeger/injectors.rb
|
158
172
|
- lib/jaeger/rate_limiter.rb
|
173
|
+
- lib/jaeger/recurring_executor.rb
|
159
174
|
- lib/jaeger/reporters.rb
|
160
175
|
- lib/jaeger/reporters/composite_reporter.rb
|
161
176
|
- lib/jaeger/reporters/in_memory_reporter.rb
|
@@ -169,14 +184,16 @@ files:
|
|
169
184
|
- lib/jaeger/samplers/per_operation.rb
|
170
185
|
- lib/jaeger/samplers/probabilistic.rb
|
171
186
|
- lib/jaeger/samplers/rate_limiting.rb
|
187
|
+
- lib/jaeger/samplers/remote_controlled.rb
|
188
|
+
- lib/jaeger/samplers/remote_controlled/instructions_fetcher.rb
|
172
189
|
- lib/jaeger/scope.rb
|
173
190
|
- lib/jaeger/scope_manager.rb
|
174
191
|
- lib/jaeger/scope_manager/scope_identifier.rb
|
175
192
|
- lib/jaeger/scope_manager/scope_stack.rb
|
176
193
|
- lib/jaeger/span.rb
|
177
194
|
- lib/jaeger/span/thrift_log_builder.rb
|
178
|
-
- lib/jaeger/span/thrift_tag_builder.rb
|
179
195
|
- lib/jaeger/span_context.rb
|
196
|
+
- lib/jaeger/thrift_tag_builder.rb
|
180
197
|
- lib/jaeger/trace_id.rb
|
181
198
|
- lib/jaeger/tracer.rb
|
182
199
|
- lib/jaeger/udp_sender.rb
|
@@ -217,8 +234,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
234
|
- !ruby/object:Gem::Version
|
218
235
|
version: '0'
|
219
236
|
requirements: []
|
220
|
-
|
221
|
-
rubygems_version: 2.7.7
|
237
|
+
rubygems_version: 3.0.6
|
222
238
|
signing_key:
|
223
239
|
specification_version: 4
|
224
240
|
summary: OpenTracing Tracer implementation for Jaeger in Ruby
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Jaeger
|
4
|
-
class Span
|
5
|
-
class ThriftTagBuilder
|
6
|
-
FIELDS = Jaeger::Thrift::Tag::FIELDS
|
7
|
-
KEY = FIELDS[Jaeger::Thrift::Tag::KEY].fetch(:name)
|
8
|
-
VTYPE = FIELDS[Jaeger::Thrift::Tag::VTYPE].fetch(:name)
|
9
|
-
VLONG = FIELDS[Jaeger::Thrift::Tag::VLONG].fetch(:name)
|
10
|
-
VDOUBLE = FIELDS[Jaeger::Thrift::Tag::VDOUBLE].fetch(:name)
|
11
|
-
VBOOL = FIELDS[Jaeger::Thrift::Tag::VBOOL].fetch(:name)
|
12
|
-
VSTR = FIELDS[Jaeger::Thrift::Tag::VSTR].fetch(:name)
|
13
|
-
|
14
|
-
def self.build(key, value)
|
15
|
-
if value.is_a?(Integer)
|
16
|
-
Jaeger::Thrift::Tag.new(
|
17
|
-
KEY => key.to_s,
|
18
|
-
VTYPE => Jaeger::Thrift::TagType::LONG,
|
19
|
-
VLONG => value
|
20
|
-
)
|
21
|
-
elsif value.is_a?(Float)
|
22
|
-
Jaeger::Thrift::Tag.new(
|
23
|
-
KEY => key.to_s,
|
24
|
-
VTYPE => Jaeger::Thrift::TagType::DOUBLE,
|
25
|
-
VDOUBLE => value
|
26
|
-
)
|
27
|
-
elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
28
|
-
Jaeger::Thrift::Tag.new(
|
29
|
-
KEY => key.to_s,
|
30
|
-
VTYPE => Jaeger::Thrift::TagType::BOOL,
|
31
|
-
VBOOL => value
|
32
|
-
)
|
33
|
-
else
|
34
|
-
Jaeger::Thrift::Tag.new(
|
35
|
-
KEY => key.to_s,
|
36
|
-
VTYPE => Jaeger::Thrift::TagType::STRING,
|
37
|
-
VSTR => value.to_s
|
38
|
-
)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|