jaeger-client 0.7.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|