jaeger-client 0.7.1 → 1.1.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/.gitmodules +3 -0
- data/.rubocop.yml +3 -0
- data/.travis.yml +11 -2
- data/Makefile +1 -0
- data/README.md +127 -13
- data/crossdock/Dockerfile +29 -0
- data/crossdock/Gemfile +6 -0
- data/crossdock/Gemfile.lock +35 -0
- data/crossdock/docker-compose.yml +68 -0
- data/crossdock/jaeger-docker-compose.yml +48 -0
- data/crossdock/rules.mk +35 -0
- data/crossdock/server +173 -0
- data/jaeger-client.gemspec +4 -2
- data/lib/jaeger/client.rb +42 -18
- data/lib/jaeger/client/version.rb +1 -1
- data/lib/jaeger/encoders/thrift_encoder.rb +142 -0
- data/lib/jaeger/extractors.rb +173 -0
- data/lib/jaeger/http_sender.rb +28 -0
- data/lib/jaeger/injectors.rb +83 -0
- data/lib/jaeger/rate_limiter.rb +61 -0
- data/lib/jaeger/recurring_executor.rb +35 -0
- data/lib/jaeger/reporters.rb +7 -0
- data/lib/jaeger/reporters/composite_reporter.rb +17 -0
- data/lib/jaeger/reporters/in_memory_reporter.rb +30 -0
- data/lib/jaeger/reporters/logging_reporter.rb +22 -0
- data/lib/jaeger/reporters/null_reporter.rb +11 -0
- data/lib/jaeger/{client/async_reporter.rb → reporters/remote_reporter.rb} +21 -20
- data/lib/jaeger/{client/async_reporter → reporters/remote_reporter}/buffer.rb +2 -2
- data/lib/jaeger/samplers.rb +8 -0
- data/lib/jaeger/samplers/const.rb +24 -0
- data/lib/jaeger/samplers/guaranteed_throughput_probabilistic.rb +47 -0
- data/lib/jaeger/samplers/per_operation.rb +79 -0
- data/lib/jaeger/samplers/probabilistic.rb +38 -0
- data/lib/jaeger/samplers/rate_limiting.rb +51 -0
- data/lib/jaeger/samplers/remote_controlled.rb +119 -0
- data/lib/jaeger/samplers/remote_controlled/instructions_fetcher.rb +34 -0
- data/lib/jaeger/scope.rb +38 -0
- data/lib/jaeger/scope_manager.rb +47 -0
- data/lib/jaeger/scope_manager/scope_identifier.rb +13 -0
- data/lib/jaeger/scope_manager/scope_stack.rb +33 -0
- data/lib/jaeger/span.rb +97 -0
- data/lib/jaeger/span/thrift_log_builder.rb +18 -0
- data/lib/jaeger/span_context.rb +57 -0
- data/lib/jaeger/thrift_tag_builder.rb +41 -0
- data/lib/jaeger/trace_id.rb +48 -0
- data/lib/jaeger/tracer.rb +213 -0
- data/lib/jaeger/udp_sender.rb +26 -0
- data/lib/jaeger/udp_sender/transport.rb +40 -0
- metadata +78 -31
- data/lib/jaeger/client/carrier.rb +0 -26
- data/lib/jaeger/client/encoders/thrift_encoder.rb +0 -94
- data/lib/jaeger/client/extractors.rb +0 -88
- data/lib/jaeger/client/http_sender.rb +0 -30
- data/lib/jaeger/client/injectors.rb +0 -54
- data/lib/jaeger/client/samplers.rb +0 -4
- data/lib/jaeger/client/samplers/const.rb +0 -29
- data/lib/jaeger/client/samplers/probabilistic.rb +0 -30
- data/lib/jaeger/client/scope.rb +0 -40
- data/lib/jaeger/client/scope_manager.rb +0 -49
- data/lib/jaeger/client/scope_manager/scope_identifier.rb +0 -15
- data/lib/jaeger/client/scope_manager/scope_stack.rb +0 -35
- data/lib/jaeger/client/span.rb +0 -84
- data/lib/jaeger/client/span/thrift_log_builder.rb +0 -20
- data/lib/jaeger/client/span/thrift_tag_builder.rb +0 -45
- data/lib/jaeger/client/span_context.rb +0 -59
- data/lib/jaeger/client/trace_id.rb +0 -41
- data/lib/jaeger/client/tracer.rb +0 -189
- data/lib/jaeger/client/udp_sender.rb +0 -27
- data/lib/jaeger/client/udp_sender/transport.rb +0 -42
data/crossdock/server
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$stdout.sync = true
|
4
|
+
|
5
|
+
require 'sinatra/base'
|
6
|
+
require 'webrick'
|
7
|
+
require 'jaeger/client'
|
8
|
+
require 'net/http'
|
9
|
+
require 'uri'
|
10
|
+
|
11
|
+
class HealthServer < Sinatra::Application
|
12
|
+
get '/' do
|
13
|
+
status 200
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class HttpServer < Sinatra::Application
|
18
|
+
post '/start_trace' do
|
19
|
+
puts "Got request to start trace: #{trace_request}"
|
20
|
+
|
21
|
+
parent_context = tracer.extract(OpenTracing::FORMAT_RACK, request.env)
|
22
|
+
server_span = tracer.start_span('/start_trace', child_of: parent_context)
|
23
|
+
|
24
|
+
server_span.set_baggage_item('crossdock-baggage-key', trace_request['baggage'])
|
25
|
+
if trace_request.key?('sampled')
|
26
|
+
server_span.set_tag('sampling.priority', trace_request['sampled'] ? 1 : 0)
|
27
|
+
end
|
28
|
+
|
29
|
+
response = {
|
30
|
+
span: observe_span(server_span),
|
31
|
+
notImplementedError: ''
|
32
|
+
}
|
33
|
+
|
34
|
+
if trace_request['downstream']
|
35
|
+
downstream = trace_request['downstream']
|
36
|
+
transport = downstream['transport']
|
37
|
+
|
38
|
+
response[:downstream] =
|
39
|
+
if transport == 'HTTP'
|
40
|
+
call_downstream_http(downstream, server_span)
|
41
|
+
elsif transport == 'DUMMY'
|
42
|
+
{ notImplementedError: 'Dummy has not been implemented' }
|
43
|
+
else
|
44
|
+
{ notImplementedError: "Unrecognized transport received: #{transport}" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
puts "Response: #{response}"
|
49
|
+
|
50
|
+
server_span.finish
|
51
|
+
body JSON.dump(response)
|
52
|
+
end
|
53
|
+
|
54
|
+
post '/join_trace' do
|
55
|
+
puts 'Got request to join trace' \
|
56
|
+
"\n Params: #{trace_request}" \
|
57
|
+
"\n Headers: #{request_headers(request)}"
|
58
|
+
|
59
|
+
parent_context = tracer.extract(OpenTracing::FORMAT_RACK, request.env)
|
60
|
+
server_span = tracer.start_span('/join_trace', child_of: parent_context)
|
61
|
+
|
62
|
+
response = {
|
63
|
+
span: observe_span(server_span),
|
64
|
+
notImplementedError: ''
|
65
|
+
}
|
66
|
+
|
67
|
+
if trace_request['downstream']
|
68
|
+
downstream = trace_request['downstream']
|
69
|
+
transport = downstream['transport']
|
70
|
+
|
71
|
+
response[:downstream] =
|
72
|
+
if transport == 'HTTP'
|
73
|
+
call_downstream_http(downstream, server_span)
|
74
|
+
elsif transport == 'DUMMY'
|
75
|
+
{ notImplementedError: 'Dummy has not been implemented' }
|
76
|
+
else
|
77
|
+
{ notImplementedError: "Unrecognized transport received: #{transport}" }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
puts "Response: #{response}"
|
82
|
+
|
83
|
+
server_span.finish
|
84
|
+
body JSON.dump(response)
|
85
|
+
end
|
86
|
+
|
87
|
+
post '/create_traces' do
|
88
|
+
puts "Got request to create traces: #{trace_request}"
|
89
|
+
|
90
|
+
trace_request['count'].times do
|
91
|
+
span = tracer.start_span(trace_request['operation'], tags: trace_request['tags'])
|
92
|
+
span.finish
|
93
|
+
end
|
94
|
+
|
95
|
+
status 200
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def tracer
|
101
|
+
@tracer ||= Jaeger::Client.build(
|
102
|
+
service_name: 'crossdock-ruby',
|
103
|
+
host: 'jaeger-agent',
|
104
|
+
port: 6831,
|
105
|
+
flush_interval: 1,
|
106
|
+
sampler: Jaeger::Samplers::Const.new(true)
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def trace_request
|
111
|
+
@trace_request ||= begin
|
112
|
+
request.body.rewind
|
113
|
+
JSON.parse(request.body.read)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def observe_span(span)
|
118
|
+
if span
|
119
|
+
{
|
120
|
+
traceId: span.context.to_trace_id,
|
121
|
+
sampled: span.context.sampled?,
|
122
|
+
baggage: span.get_baggage_item('crossdock-baggage-key')
|
123
|
+
}
|
124
|
+
else
|
125
|
+
{
|
126
|
+
traceId: 'no span found',
|
127
|
+
sampled: false,
|
128
|
+
baggage: 'no span found'
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def call_downstream_http(downstream, server_span)
|
134
|
+
downstream_url = "http://#{downstream['host']}:#{downstream['port']}/join_trace"
|
135
|
+
|
136
|
+
client_span = tracer.start_span('client-span', child_of: server_span)
|
137
|
+
|
138
|
+
headers = { 'Content-Type' => 'application/json' }
|
139
|
+
tracer.inject(client_span.context, OpenTracing::FORMAT_RACK, headers)
|
140
|
+
|
141
|
+
response = Net::HTTP.post(
|
142
|
+
URI(downstream_url),
|
143
|
+
JSON.dump(
|
144
|
+
serverRole: downstream['serverRole'],
|
145
|
+
downstream: downstream['downstream']
|
146
|
+
),
|
147
|
+
headers
|
148
|
+
)
|
149
|
+
|
150
|
+
client_span.finish
|
151
|
+
|
152
|
+
if response.is_a?(Net::HTTPSuccess)
|
153
|
+
JSON.parse(response.body)
|
154
|
+
else
|
155
|
+
{ error: response.body }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def request_headers(request)
|
160
|
+
request.env.select do |key, _value|
|
161
|
+
key.start_with?('HTTP_')
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
threads = []
|
167
|
+
threads << Thread.new do
|
168
|
+
Rack::Handler::WEBrick.run(HealthServer, Port: 8080, Host: '0.0.0.0')
|
169
|
+
end
|
170
|
+
threads << Thread.new do
|
171
|
+
Rack::Handler::WEBrick.run(HttpServer, Port: 8081, Host: '0.0.0.0')
|
172
|
+
end
|
173
|
+
threads.each(&:join)
|
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|
|
@@ -20,11 +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
|
+
spec.add_development_dependency 'timecop', '~> 0.9'
|
29
|
+
spec.add_development_dependency 'webmock', '~> 3.4.2'
|
28
30
|
|
29
31
|
spec.add_dependency 'opentracing', '~> 0.3'
|
30
32
|
spec.add_dependency 'thrift'
|
data/lib/jaeger/client.rb
CHANGED
@@ -5,24 +5,42 @@ $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
|
-
require_relative '
|
10
|
-
require_relative '
|
11
|
-
require_relative '
|
12
|
-
require_relative '
|
13
|
-
require_relative '
|
14
|
-
require_relative '
|
15
|
-
require_relative '
|
16
|
-
require_relative '
|
17
|
-
require_relative '
|
13
|
+
require_relative 'tracer'
|
14
|
+
require_relative 'span'
|
15
|
+
require_relative 'span_context'
|
16
|
+
require_relative 'scope'
|
17
|
+
require_relative 'scope_manager'
|
18
|
+
require_relative 'trace_id'
|
19
|
+
require_relative 'udp_sender'
|
20
|
+
require_relative 'http_sender'
|
21
|
+
require_relative 'reporters'
|
18
22
|
require_relative 'client/version'
|
19
|
-
require_relative '
|
20
|
-
require_relative '
|
21
|
-
require_relative '
|
22
|
-
require_relative '
|
23
|
+
require_relative 'samplers'
|
24
|
+
require_relative 'encoders/thrift_encoder'
|
25
|
+
require_relative 'injectors'
|
26
|
+
require_relative 'extractors'
|
27
|
+
require_relative 'rate_limiter'
|
28
|
+
require_relative 'thrift_tag_builder'
|
29
|
+
require_relative 'recurring_executor'
|
23
30
|
|
24
31
|
module Jaeger
|
25
32
|
module Client
|
33
|
+
# We initially had everything under Jaeger::Client namespace. This however
|
34
|
+
# was not very useful and was removed. These assignments are here for
|
35
|
+
# backwards compatibility. Fine to remove in the next major version.
|
36
|
+
UdpSender = Jaeger::UdpSender
|
37
|
+
HttpSender = Jaeger::HttpSender
|
38
|
+
Encoders = Jaeger::Encoders
|
39
|
+
Samplers = Jaeger::Samplers
|
40
|
+
Reporters = Jaeger::Reporters
|
41
|
+
Injectors = Jaeger::Injectors
|
42
|
+
Extractors = Jaeger::Extractors
|
43
|
+
|
26
44
|
DEFAULT_FLUSH_INTERVAL = 10
|
27
45
|
|
28
46
|
def self.build(host: '127.0.0.1',
|
@@ -32,15 +50,21 @@ module Jaeger
|
|
32
50
|
sampler: Samplers::Const.new(true),
|
33
51
|
logger: Logger.new(STDOUT),
|
34
52
|
sender: nil,
|
53
|
+
reporter: nil,
|
35
54
|
injectors: {},
|
36
|
-
extractors: {}
|
37
|
-
|
55
|
+
extractors: {},
|
56
|
+
tags: {})
|
57
|
+
encoder = Encoders::ThriftEncoder.new(service_name: service_name, tags: tags)
|
38
58
|
|
39
|
-
if sender
|
40
|
-
|
59
|
+
if sender
|
60
|
+
warn '[DEPRECATION] Passing `sender` directly to Jaeger::Client.build is deprecated.' \
|
61
|
+
'Please use `reporter` instead.'
|
41
62
|
end
|
42
63
|
|
43
|
-
reporter
|
64
|
+
reporter ||= Reporters::RemoteReporter.new(
|
65
|
+
sender: sender || UdpSender.new(host: host, port: port, encoder: encoder, logger: logger),
|
66
|
+
flush_interval: flush_interval
|
67
|
+
)
|
44
68
|
|
45
69
|
Tracer.new(
|
46
70
|
reporter: reporter,
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Encoders
|
5
|
+
class ThriftEncoder
|
6
|
+
def initialize(service_name:, tags: {})
|
7
|
+
@service_name = service_name
|
8
|
+
@tags = prepare_tags(tags)
|
9
|
+
@process = Jaeger::Thrift::Process.new('serviceName' => @service_name, 'tags' => @tags)
|
10
|
+
end
|
11
|
+
|
12
|
+
def encode(spans)
|
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
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def encode_batch(encoded_spans)
|
36
|
+
Jaeger::Thrift::Batch.new('process' => @process, 'spans' => encoded_spans)
|
37
|
+
end
|
38
|
+
|
39
|
+
def encode_span(span)
|
40
|
+
context = span.context
|
41
|
+
start_ts, duration = build_timestamps(span)
|
42
|
+
|
43
|
+
Jaeger::Thrift::Span.new(
|
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)),
|
46
|
+
'spanId' => TraceId.uint64_id_to_int64(context.span_id),
|
47
|
+
'parentSpanId' => TraceId.uint64_id_to_int64(context.parent_id),
|
48
|
+
'operationName' => span.operation_name,
|
49
|
+
'references' => build_references(span.references || []),
|
50
|
+
'flags' => context.flags,
|
51
|
+
'startTime' => start_ts,
|
52
|
+
'duration' => duration,
|
53
|
+
'tags' => span.tags,
|
54
|
+
'logs' => span.logs
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def build_references(references)
|
59
|
+
references.map do |ref|
|
60
|
+
Jaeger::Thrift::SpanRef.new(
|
61
|
+
'refType' => span_ref_type(ref.type),
|
62
|
+
'traceIdLow' => TraceId.uint64_id_to_int64(ref.context.trace_id),
|
63
|
+
'traceIdHigh' => 0,
|
64
|
+
'spanId' => TraceId.uint64_id_to_int64(ref.context.span_id)
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def build_timestamps(span)
|
70
|
+
start_ts = (span.start_time.to_f * 1_000_000).to_i
|
71
|
+
end_ts = (span.end_time.to_f * 1_000_000).to_i
|
72
|
+
duration = end_ts - start_ts
|
73
|
+
[start_ts, duration]
|
74
|
+
end
|
75
|
+
|
76
|
+
def span_ref_type(type)
|
77
|
+
case type
|
78
|
+
when OpenTracing::Reference::CHILD_OF
|
79
|
+
Jaeger::Thrift::SpanRefType::CHILD_OF
|
80
|
+
when OpenTracing::Reference::FOLLOWS_FROM
|
81
|
+
Jaeger::Thrift::SpanRefType::FOLLOWS_FROM
|
82
|
+
else
|
83
|
+
warn "Jaeger::Client with format #{type} is not supported yet"
|
84
|
+
nil
|
85
|
+
end
|
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
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Extractors
|
5
|
+
class SerializedJaegerTrace
|
6
|
+
def self.parse(trace)
|
7
|
+
return nil if !trace || trace == ''
|
8
|
+
|
9
|
+
trace_arguments = trace.split(':')
|
10
|
+
return nil if trace_arguments.size != 4
|
11
|
+
|
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
|
+
|
15
|
+
return nil if trace_id.zero? || span_id.zero?
|
16
|
+
|
17
|
+
SpanContext.new(
|
18
|
+
trace_id: trace_id,
|
19
|
+
parent_id: parent_id,
|
20
|
+
span_id: span_id,
|
21
|
+
flags: flags
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class JaegerTextMapCodec
|
27
|
+
def self.extract(carrier)
|
28
|
+
context = SerializedJaegerTrace.parse(carrier['uber-trace-id'])
|
29
|
+
return nil unless context
|
30
|
+
|
31
|
+
carrier.each do |key, value|
|
32
|
+
baggage_match = key.match(/\Auberctx-([\w-]+)\Z/)
|
33
|
+
if baggage_match
|
34
|
+
context.set_baggage_item(baggage_match[1], value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class JaegerRackCodec
|
43
|
+
def self.extract(carrier)
|
44
|
+
serialized_trace = carrier['HTTP_UBER_TRACE_ID']
|
45
|
+
serialized_trace = CGI.unescape(serialized_trace) if serialized_trace
|
46
|
+
context = SerializedJaegerTrace.parse(serialized_trace)
|
47
|
+
return nil unless context
|
48
|
+
|
49
|
+
carrier.each do |key, value|
|
50
|
+
baggage_match = key.match(/\AHTTP_UBERCTX_(\w+)\Z/)
|
51
|
+
if baggage_match
|
52
|
+
key = baggage_match[1].downcase.tr('_', '-')
|
53
|
+
context.set_baggage_item(key, CGI.unescape(value))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class JaegerBinaryCodec
|
62
|
+
def self.extract(_carrier)
|
63
|
+
warn 'Jaeger::Client with binary format is not supported yet'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
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
|
+
|
76
|
+
def self.extract(carrier)
|
77
|
+
B3CodecCommon.extract(carrier, Keys)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class B3TextMapCodec
|
82
|
+
class Keys
|
83
|
+
TRACE_ID = 'x-b3-traceid'.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
|
+
return nil if carrier[keys::TRACE_ID].nil? || carrier[keys::SPAN_ID].nil?
|
98
|
+
|
99
|
+
trace_id = if carrier[keys::TRACE_ID].length <= 16
|
100
|
+
TraceId.base16_hex_id_to_uint64(carrier[keys::TRACE_ID])
|
101
|
+
else
|
102
|
+
TraceId.base16_hex_id_to_uint128(carrier[keys::TRACE_ID])
|
103
|
+
end
|
104
|
+
|
105
|
+
span_id = TraceId.base16_hex_id_to_uint64(carrier[keys::SPAN_ID])
|
106
|
+
parent_id = TraceId.base16_hex_id_to_uint64(carrier[keys::PARENT_SPAN_ID])
|
107
|
+
flags = parse_flags(carrier[keys::FLAGS], carrier[keys::SAMPLED])
|
108
|
+
|
109
|
+
return nil if span_id.zero? || trace_id.zero?
|
110
|
+
|
111
|
+
SpanContext.new(
|
112
|
+
trace_id: trace_id,
|
113
|
+
parent_id: parent_id,
|
114
|
+
span_id: span_id,
|
115
|
+
flags: flags
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
# if the flags header is '1' then the sampled header should not be present
|
120
|
+
def self.parse_flags(flags_header, sampled_header)
|
121
|
+
if flags_header == '1'
|
122
|
+
Jaeger::SpanContext::Flags::DEBUG
|
123
|
+
else
|
124
|
+
TraceId.base16_hex_id_to_uint64(sampled_header)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
private_class_method :parse_flags
|
128
|
+
end
|
129
|
+
|
130
|
+
class TraceContextRackCodec
|
131
|
+
# Internal regex used to identify the TraceContext version
|
132
|
+
VERSION_PATTERN = /^([0-9a-fA-F]{2})-(.+)$/
|
133
|
+
|
134
|
+
# Internal regex used to parse fields in version 0
|
135
|
+
HEADER_V0_PATTERN = /^([0-9a-fA-F]{32})-([0-9a-fA-F]{16})(-([0-9a-fA-F]{2}))?$/
|
136
|
+
|
137
|
+
def self.extract(carrier)
|
138
|
+
header_value = carrier['HTTP_TRACEPARENT']
|
139
|
+
|
140
|
+
version_match = VERSION_PATTERN.match(header_value)
|
141
|
+
return nil unless version_match
|
142
|
+
|
143
|
+
# We currently only support version 0
|
144
|
+
return nil if version_match[1].to_i(16) != 0
|
145
|
+
|
146
|
+
match = HEADER_V0_PATTERN.match(version_match[2])
|
147
|
+
return nil unless match
|
148
|
+
|
149
|
+
trace_id = TraceId.base16_hex_id_to_uint128(match[1])
|
150
|
+
span_id = TraceId.base16_hex_id_to_uint64(match[2])
|
151
|
+
flags = TraceId.base16_hex_id_to_uint64(match[4])
|
152
|
+
return nil if trace_id.zero? || span_id.zero?
|
153
|
+
|
154
|
+
SpanContext.new(trace_id: trace_id, span_id: span_id, flags: flags)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
DEFAULT_EXTRACTORS = {
|
159
|
+
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
160
|
+
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
161
|
+
OpenTracing::FORMAT_RACK => JaegerRackCodec
|
162
|
+
}.freeze
|
163
|
+
|
164
|
+
def self.prepare(extractors)
|
165
|
+
DEFAULT_EXTRACTORS.reduce(extractors) do |acc, (format, default)|
|
166
|
+
provided_extractors = Array(extractors[format])
|
167
|
+
provided_extractors += [default] if provided_extractors.empty?
|
168
|
+
|
169
|
+
acc.merge(format => provided_extractors)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|