jaeger-client 0.10.0 → 1.0.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/.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
|