jaeger-client 0.6.1 → 0.7.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 +34 -0
- data/lib/jaeger/client.rb +21 -12
- data/lib/jaeger/client/async_reporter.rb +41 -0
- data/lib/jaeger/client/async_reporter/buffer.rb +29 -0
- data/lib/jaeger/client/encoders/thrift_encoder.rb +94 -0
- data/lib/jaeger/client/extractors.rb +88 -0
- data/lib/jaeger/client/http_sender.rb +30 -0
- data/lib/jaeger/client/injectors.rb +54 -0
- data/lib/jaeger/client/span.rb +6 -5
- data/lib/jaeger/client/trace_id.rb +14 -0
- data/lib/jaeger/client/tracer.rb +13 -44
- data/lib/jaeger/client/udp_sender.rb +4 -53
- data/lib/jaeger/client/version.rb +1 -1
- data/script/create_follows_from_trace +1 -2
- data/script/create_trace +1 -2
- metadata +9 -4
- data/lib/jaeger/client/collector.rb +0 -91
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f0b04e0c6c305df9d1f5ec5c0b76ad40c60a5e8b27c5475b29e414ade9ef59b
|
4
|
+
data.tar.gz: 672aa006cb7ad30269615cda53b05eed141205689d37b472b0acdc91b257d074
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 188e7434f62b4023b9a4d03ec1c18589c6d9b3a79810a2a000b6ef987b8532d1e5ec9f7d0e21ba2383b197b3f1bd6064c602839e49d185b3241365a664a7a5f2
|
7
|
+
data.tar.gz: 6335ba661fbfbd92ee543ba30d794fe9cffa4a7b30c36e300a63f48331bbcc81b33a5f2585ebe266f51faefddd3600d481f9a0326b6c5740e0fe95bf34b01cf5
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -28,6 +28,18 @@ OpenTracing.start_active_span('span name') do
|
|
28
28
|
end
|
29
29
|
```
|
30
30
|
|
31
|
+
The tracer can also take an externally configured sender. For example, the `HttpSender` can be configured with a different endpoint and headers for authentication.
|
32
|
+
```ruby
|
33
|
+
require 'jaeger/client'
|
34
|
+
require 'jaeger/client/http_sender'
|
35
|
+
|
36
|
+
headers = { "auth_token" => token }
|
37
|
+
encoder = Jaeger::Client::Encoders::ThriftEncoder.new(service_name: "service_name")
|
38
|
+
sender = Jaeger::Client::HttpSender.new(url: "http://localhost:14268/api/traces", headers: headers, encoder: encoder)
|
39
|
+
|
40
|
+
OpenTracing.global_tracer = Jaeger::Client.build(service_name: "service_name", sender: sender)
|
41
|
+
```
|
42
|
+
|
31
43
|
See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more examples.
|
32
44
|
|
33
45
|
### Samplers
|
@@ -40,6 +52,28 @@ See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more
|
|
40
52
|
|
41
53
|
`Probabilistic` sampler samples traces with probability equal to `rate` (must be between 0.0 and 1.0). This can be enabled by setting `Jaeger::Client::Samplers::Probabilistic.new(rate: 0.1)`
|
42
54
|
|
55
|
+
### Zipkin HTTP B3 compatible header propagation
|
56
|
+
|
57
|
+
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.
|
58
|
+
|
59
|
+
To set it up you need to change FORMAT_RACK injector and extractor.
|
60
|
+
|
61
|
+
```
|
62
|
+
OpenTracing.global_tracer = Jaeger::Client.build(
|
63
|
+
service_name: 'service_name',
|
64
|
+
injectors: {
|
65
|
+
OpenTracing::FORMAT_RACK => [Jaeger::Client::Injectors::B3RackCodec]
|
66
|
+
},
|
67
|
+
extractors: {
|
68
|
+
OpenTracing::FORMAT_RACK => [Jaeger::Client::Extractors::B3RackCodec]
|
69
|
+
}
|
70
|
+
)
|
71
|
+
```
|
72
|
+
|
73
|
+
It's also possible to set up multiple injectors and extractors. Each injector will be called in sequence. Note that if multiple injectors are using the same keys then the values will be overwritten.
|
74
|
+
|
75
|
+
If multiple extractors is used then the span context from the first match will be returned.
|
76
|
+
|
43
77
|
## Development
|
44
78
|
|
45
79
|
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/lib/jaeger/client.rb
CHANGED
@@ -14,9 +14,12 @@ require_relative 'client/scope_manager'
|
|
14
14
|
require_relative 'client/carrier'
|
15
15
|
require_relative 'client/trace_id'
|
16
16
|
require_relative 'client/udp_sender'
|
17
|
-
require_relative 'client/
|
17
|
+
require_relative 'client/async_reporter'
|
18
18
|
require_relative 'client/version'
|
19
19
|
require_relative 'client/samplers'
|
20
|
+
require_relative 'client/encoders/thrift_encoder'
|
21
|
+
require_relative 'client/injectors'
|
22
|
+
require_relative 'client/extractors'
|
20
23
|
|
21
24
|
module Jaeger
|
22
25
|
module Client
|
@@ -27,18 +30,24 @@ module Jaeger
|
|
27
30
|
service_name:,
|
28
31
|
flush_interval: DEFAULT_FLUSH_INTERVAL,
|
29
32
|
sampler: Samplers::Const.new(true),
|
30
|
-
logger: Logger.new(STDOUT)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
logger: Logger.new(STDOUT),
|
34
|
+
sender: nil,
|
35
|
+
injectors: {},
|
36
|
+
extractors: {})
|
37
|
+
encoder = Encoders::ThriftEncoder.new(service_name: service_name)
|
38
|
+
|
39
|
+
if sender.nil?
|
40
|
+
sender = UdpSender.new(host: host, port: port, encoder: encoder, logger: logger)
|
41
|
+
end
|
42
|
+
|
43
|
+
reporter = AsyncReporter.create(sender: sender, flush_interval: flush_interval)
|
44
|
+
|
45
|
+
Tracer.new(
|
46
|
+
reporter: reporter,
|
47
|
+
sampler: sampler,
|
48
|
+
injectors: Injectors.prepare(injectors),
|
49
|
+
extractors: Extractors.prepare(extractors)
|
39
50
|
)
|
40
|
-
sender.start
|
41
|
-
Tracer.new(collector, sender, sampler)
|
42
51
|
end
|
43
52
|
end
|
44
53
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
require_relative './async_reporter/buffer'
|
6
|
+
|
7
|
+
module Jaeger
|
8
|
+
module Client
|
9
|
+
class AsyncReporter
|
10
|
+
def self.create(sender:, flush_interval:)
|
11
|
+
reporter = new(sender)
|
12
|
+
|
13
|
+
# start flush thread
|
14
|
+
Thread.new do
|
15
|
+
loop do
|
16
|
+
reporter.flush
|
17
|
+
sleep(flush_interval)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
reporter
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(sender)
|
25
|
+
@sender = sender
|
26
|
+
@buffer = Buffer.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def flush
|
30
|
+
spans = @buffer.retrieve
|
31
|
+
@sender.send_spans(spans) if spans.any?
|
32
|
+
spans
|
33
|
+
end
|
34
|
+
|
35
|
+
def report(span)
|
36
|
+
return if !span.context.sampled? && !span.context.debug?
|
37
|
+
@buffer << span
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
class AsyncReporter
|
6
|
+
class Buffer
|
7
|
+
def initialize
|
8
|
+
@buffer = []
|
9
|
+
@mutex = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(element)
|
13
|
+
@mutex.synchronize do
|
14
|
+
@buffer << element
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def retrieve
|
20
|
+
@mutex.synchronize do
|
21
|
+
elements = @buffer.dup
|
22
|
+
@buffer.clear
|
23
|
+
elements
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Encoders
|
6
|
+
class ThriftEncoder
|
7
|
+
def initialize(service_name:)
|
8
|
+
@service_name = service_name
|
9
|
+
@tags = [
|
10
|
+
Jaeger::Thrift::Tag.new(
|
11
|
+
'key' => 'jaeger.version',
|
12
|
+
'vType' => Jaeger::Thrift::TagType::STRING,
|
13
|
+
'vStr' => 'Ruby-' + Jaeger::Client::VERSION
|
14
|
+
),
|
15
|
+
Jaeger::Thrift::Tag.new(
|
16
|
+
'key' => 'hostname',
|
17
|
+
'vType' => Jaeger::Thrift::TagType::STRING,
|
18
|
+
'vStr' => Socket.gethostname
|
19
|
+
)
|
20
|
+
]
|
21
|
+
ipv4 = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }
|
22
|
+
unless ipv4.nil? # rubocop:disable Style/GuardClause
|
23
|
+
@tags << Jaeger::Thrift::Tag.new(
|
24
|
+
'key' => 'ip',
|
25
|
+
'vType' => Jaeger::Thrift::TagType::STRING,
|
26
|
+
'vStr' => ipv4.ip_address
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def encode(spans)
|
32
|
+
Jaeger::Thrift::Batch.new(
|
33
|
+
'process' => Jaeger::Thrift::Process.new(
|
34
|
+
'serviceName' => @service_name,
|
35
|
+
'tags' => @tags
|
36
|
+
),
|
37
|
+
'spans' => spans.map(&method(:encode_span))
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def encode_span(span)
|
44
|
+
context = span.context
|
45
|
+
start_ts, duration = build_timestamps(span)
|
46
|
+
|
47
|
+
Jaeger::Thrift::Span.new(
|
48
|
+
'traceIdLow' => TraceId.uint64_id_to_int64(context.trace_id),
|
49
|
+
'traceIdHigh' => 0,
|
50
|
+
'spanId' => TraceId.uint64_id_to_int64(context.span_id),
|
51
|
+
'parentSpanId' => TraceId.uint64_id_to_int64(context.parent_id),
|
52
|
+
'operationName' => span.operation_name,
|
53
|
+
'references' => build_references(span.references || []),
|
54
|
+
'flags' => context.flags,
|
55
|
+
'startTime' => start_ts,
|
56
|
+
'duration' => duration,
|
57
|
+
'tags' => span.tags,
|
58
|
+
'logs' => span.logs
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_references(references)
|
63
|
+
references.map do |ref|
|
64
|
+
Jaeger::Thrift::SpanRef.new(
|
65
|
+
'refType' => span_ref_type(ref.type),
|
66
|
+
'traceIdLow' => ref.context.trace_id,
|
67
|
+
'traceIdHigh' => 0,
|
68
|
+
'spanId' => ref.context.span_id
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_timestamps(span)
|
74
|
+
start_ts = (span.start_time.to_f * 1_000_000).to_i
|
75
|
+
end_ts = (span.end_time.to_f * 1_000_000).to_i
|
76
|
+
duration = end_ts - start_ts
|
77
|
+
[start_ts, duration]
|
78
|
+
end
|
79
|
+
|
80
|
+
def span_ref_type(type)
|
81
|
+
case type
|
82
|
+
when OpenTracing::Reference::CHILD_OF
|
83
|
+
Jaeger::Thrift::SpanRefType::CHILD_OF
|
84
|
+
when OpenTracing::Reference::FOLLOWS_FROM
|
85
|
+
Jaeger::Thrift::SpanRefType::FOLLOWS_FROM
|
86
|
+
else
|
87
|
+
warn "Jaeger::Client with format #{type} is not supported yet"
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Extractors
|
6
|
+
class SerializedJaegerTrace
|
7
|
+
def self.parse(trace)
|
8
|
+
return nil if !trace || trace == ''
|
9
|
+
|
10
|
+
trace_arguments = trace.split(':').map(&TraceId.method(:base16_hex_id_to_uint64))
|
11
|
+
return nil if trace_arguments.size != 4
|
12
|
+
|
13
|
+
trace_id, span_id, parent_id, flags = trace_arguments
|
14
|
+
return nil if trace_id.zero? || span_id.zero?
|
15
|
+
|
16
|
+
SpanContext.new(
|
17
|
+
trace_id: trace_id,
|
18
|
+
parent_id: parent_id,
|
19
|
+
span_id: span_id,
|
20
|
+
flags: flags
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class JaegerTextMapCodec
|
26
|
+
def self.extract(carrier)
|
27
|
+
SerializedJaegerTrace.parse(carrier['uber-trace-id'])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class JaegerRackCodec
|
32
|
+
def self.extract(carrier)
|
33
|
+
SerializedJaegerTrace.parse(carrier['HTTP_UBER_TRACE_ID'])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class JaegerBinaryCodec
|
38
|
+
def self.extract(_carrier)
|
39
|
+
warn 'Jaeger::Client with binary format is not supported yet'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class B3RackCodec
|
44
|
+
def self.extract(carrier)
|
45
|
+
trace_id = TraceId.base16_hex_id_to_uint64(carrier['HTTP_X_B3_TRACEID'])
|
46
|
+
span_id = TraceId.base16_hex_id_to_uint64(carrier['HTTP_X_B3_SPANID'])
|
47
|
+
parent_id = TraceId.base16_hex_id_to_uint64(carrier['HTTP_X_B3_PARENTSPANID'])
|
48
|
+
flags = parse_flags(carrier['HTTP_X_B3_FLAGS'], carrier['HTTP_X_B3_SAMPLED'])
|
49
|
+
|
50
|
+
return nil if span_id.nil? || trace_id.nil?
|
51
|
+
return nil if span_id.zero? || trace_id.zero?
|
52
|
+
|
53
|
+
SpanContext.new(
|
54
|
+
trace_id: trace_id,
|
55
|
+
parent_id: parent_id,
|
56
|
+
span_id: span_id,
|
57
|
+
flags: flags
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
# if the flags header is '1' then the sampled header should not be present
|
62
|
+
def self.parse_flags(flags_header, sampled_header)
|
63
|
+
if flags_header == '1'
|
64
|
+
Jaeger::Client::SpanContext::Flags::DEBUG
|
65
|
+
else
|
66
|
+
TraceId.base16_hex_id_to_uint64(sampled_header)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
private_class_method :parse_flags
|
70
|
+
end
|
71
|
+
|
72
|
+
DEFAULT_EXTRACTORS = {
|
73
|
+
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
74
|
+
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
75
|
+
OpenTracing::FORMAT_RACK => JaegerRackCodec
|
76
|
+
}.freeze
|
77
|
+
|
78
|
+
def self.prepare(extractors)
|
79
|
+
DEFAULT_EXTRACTORS.reduce(extractors) do |acc, (format, default)|
|
80
|
+
provided_extractors = Array(extractors[format])
|
81
|
+
provided_extractors += [default] if provided_extractors.empty?
|
82
|
+
|
83
|
+
acc.merge(format => provided_extractors)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Jaeger
|
6
|
+
module Client
|
7
|
+
class HttpSender
|
8
|
+
def initialize(url:, headers: {}, encoder:, logger: Logger.new(STDOUT))
|
9
|
+
@encoder = encoder
|
10
|
+
@logger = logger
|
11
|
+
|
12
|
+
@uri = URI(url)
|
13
|
+
@uri.query = 'format=jaeger.thrift'
|
14
|
+
|
15
|
+
@transport = ::Thrift::HTTPClientTransport.new(@uri.to_s)
|
16
|
+
@transport.add_headers(headers)
|
17
|
+
|
18
|
+
@serializer = ::Thrift::Serializer.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def send_spans(spans)
|
22
|
+
batch = @encoder.encode(spans)
|
23
|
+
@transport.write(@serializer.serialize(batch))
|
24
|
+
@transport.flush
|
25
|
+
rescue StandardError => error
|
26
|
+
@logger.error("Failure while sending a batch of spans: #{error}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module Client
|
5
|
+
module Injectors
|
6
|
+
class JaegerTextMapCodec
|
7
|
+
def self.inject(span_context, carrier)
|
8
|
+
carrier['uber-trace-id'] = [
|
9
|
+
span_context.trace_id.to_s(16),
|
10
|
+
span_context.span_id.to_s(16),
|
11
|
+
span_context.parent_id.to_s(16),
|
12
|
+
span_context.flags.to_s(16)
|
13
|
+
].join(':')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class JaegerBinaryCodec
|
18
|
+
def self.inject(_span_context, _carrier)
|
19
|
+
warn 'Jaeger::Client with binary format is not supported yet'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class B3RackCodec
|
24
|
+
def self.inject(span_context, carrier)
|
25
|
+
carrier['x-b3-traceid'] = TraceId.to_hex(span_context.trace_id)
|
26
|
+
carrier['x-b3-spanid'] = TraceId.to_hex(span_context.span_id)
|
27
|
+
carrier['x-b3-parentspanid'] = TraceId.to_hex(span_context.parent_id)
|
28
|
+
|
29
|
+
# flags (for debug) and sampled headers are mutually exclusive
|
30
|
+
if span_context.flags == Jaeger::Client::SpanContext::Flags::DEBUG
|
31
|
+
carrier['x-b3-flags'] = '1'
|
32
|
+
else
|
33
|
+
carrier['x-b3-sampled'] = span_context.flags.to_s(16)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
DEFAULT_INJECTORS = {
|
39
|
+
OpenTracing::FORMAT_TEXT_MAP => JaegerTextMapCodec,
|
40
|
+
OpenTracing::FORMAT_BINARY => JaegerBinaryCodec,
|
41
|
+
OpenTracing::FORMAT_RACK => JaegerTextMapCodec
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
def self.prepare(extractors)
|
45
|
+
DEFAULT_INJECTORS.reduce(extractors) do |acc, (format, default)|
|
46
|
+
provided_extractors = Array(extractors[format])
|
47
|
+
provided_extractors += [default] if provided_extractors.empty?
|
48
|
+
|
49
|
+
acc.merge(format => provided_extractors)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/jaeger/client/span.rb
CHANGED
@@ -8,19 +8,19 @@ module Jaeger
|
|
8
8
|
class Span
|
9
9
|
attr_accessor :operation_name
|
10
10
|
|
11
|
-
attr_reader :context, :start_time, :references, :tags, :logs
|
11
|
+
attr_reader :context, :start_time, :end_time, :references, :tags, :logs
|
12
12
|
|
13
13
|
# Creates a new {Span}
|
14
14
|
#
|
15
15
|
# @param context [SpanContext] the context of the span
|
16
16
|
# @param operation_name [String] the operation name
|
17
|
-
# @param
|
17
|
+
# @param reporter [#report] span reporter
|
18
18
|
#
|
19
19
|
# @return [Span] a new Span
|
20
|
-
def initialize(context, operation_name,
|
20
|
+
def initialize(context, operation_name, reporter, start_time: Time.now, references: [], tags: {})
|
21
21
|
@context = context
|
22
22
|
@operation_name = operation_name
|
23
|
-
@
|
23
|
+
@reporter = reporter
|
24
24
|
@start_time = start_time
|
25
25
|
@references = references
|
26
26
|
@tags = tags.map { |key, value| ThriftTagBuilder.build(key, value) }
|
@@ -76,7 +76,8 @@ module Jaeger
|
|
76
76
|
#
|
77
77
|
# @param end_time [Time] custom end time, if not now
|
78
78
|
def finish(end_time: Time.now)
|
79
|
-
@
|
79
|
+
@end_time = end_time
|
80
|
+
@reporter.report(self)
|
80
81
|
end
|
81
82
|
end
|
82
83
|
end
|
@@ -22,6 +22,20 @@ module Jaeger
|
|
22
22
|
def self.uint64_id_to_int64(id)
|
23
23
|
id > MAX_64BIT_SIGNED_INT ? id - MAX_64BIT_UNSIGNED_INT - 1 : id
|
24
24
|
end
|
25
|
+
|
26
|
+
# Convert an integer id into a 0 padded hex string.
|
27
|
+
# If the string is shorter than 16 characters, it will be padded to 16.
|
28
|
+
# If it is longer than 16 characters, it is padded to 32.
|
29
|
+
def self.to_hex(id)
|
30
|
+
hex_str = id.to_s(16)
|
31
|
+
|
32
|
+
# pad the string with '0's to 16 or 32 characters
|
33
|
+
if hex_str.length > 16
|
34
|
+
hex_str.rjust(32, '0')
|
35
|
+
else
|
36
|
+
hex_str.rjust(16, '0')
|
37
|
+
end
|
38
|
+
end
|
25
39
|
end
|
26
40
|
end
|
27
41
|
end
|
data/lib/jaeger/client/tracer.rb
CHANGED
@@ -3,17 +3,14 @@
|
|
3
3
|
module Jaeger
|
4
4
|
module Client
|
5
5
|
class Tracer
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@sender = sender
|
6
|
+
def initialize(reporter:, sampler:, injectors:, extractors:)
|
7
|
+
@reporter = reporter
|
9
8
|
@sampler = sampler
|
9
|
+
@injectors = injectors
|
10
|
+
@extractors = extractors
|
10
11
|
@scope_manager = ScopeManager.new
|
11
12
|
end
|
12
13
|
|
13
|
-
def stop
|
14
|
-
@sender.stop
|
15
|
-
end
|
16
|
-
|
17
14
|
# @return [ScopeManager] the current ScopeManager, which may be a no-op
|
18
15
|
# but may not be nil.
|
19
16
|
attr_reader :scope_manager
|
@@ -61,7 +58,7 @@ module Jaeger
|
|
61
58
|
Span.new(
|
62
59
|
context,
|
63
60
|
operation_name,
|
64
|
-
@
|
61
|
+
@reporter,
|
65
62
|
start_time: start_time,
|
66
63
|
references: references,
|
67
64
|
tags: tags.merge(
|
@@ -132,16 +129,8 @@ module Jaeger
|
|
132
129
|
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
133
130
|
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
134
131
|
def inject(span_context, format, carrier)
|
135
|
-
|
136
|
-
|
137
|
-
carrier['uber-trace-id'] = [
|
138
|
-
span_context.trace_id.to_s(16),
|
139
|
-
span_context.span_id.to_s(16),
|
140
|
-
span_context.parent_id.to_s(16),
|
141
|
-
span_context.flags.to_s(16)
|
142
|
-
].join(':')
|
143
|
-
else
|
144
|
-
warn "Jaeger::Client with format #{format} is not supported yet"
|
132
|
+
@injectors.fetch(format).each do |injector|
|
133
|
+
injector.inject(span_context, carrier)
|
145
134
|
end
|
146
135
|
end
|
147
136
|
|
@@ -151,36 +140,16 @@ module Jaeger
|
|
151
140
|
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
152
141
|
# @return [SpanContext] the extracted SpanContext or nil if none could be found
|
153
142
|
def extract(format, carrier)
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
warn "Jaeger::Client with format #{format} is not supported yet"
|
161
|
-
nil
|
162
|
-
end
|
143
|
+
@extractors
|
144
|
+
.fetch(format)
|
145
|
+
.lazy
|
146
|
+
.map { |extractor| extractor.extract(carrier) }
|
147
|
+
.reject(&:nil?)
|
148
|
+
.first
|
163
149
|
end
|
164
150
|
|
165
151
|
private
|
166
152
|
|
167
|
-
def parse_context(trace)
|
168
|
-
return nil if !trace || trace == ''
|
169
|
-
|
170
|
-
trace_arguments = trace.split(':').map(&TraceId.method(:base16_hex_id_to_uint64))
|
171
|
-
return nil if trace_arguments.size != 4
|
172
|
-
|
173
|
-
trace_id, span_id, parent_id, flags = trace_arguments
|
174
|
-
return nil if trace_id.zero? || span_id.zero?
|
175
|
-
|
176
|
-
SpanContext.new(
|
177
|
-
trace_id: trace_id,
|
178
|
-
parent_id: parent_id,
|
179
|
-
span_id: span_id,
|
180
|
-
flags: flags
|
181
|
-
)
|
182
|
-
end
|
183
|
-
|
184
153
|
def prepare_span_context(child_of:, references:, ignore_active_scope:)
|
185
154
|
context =
|
186
155
|
context_from_child_of(child_of) ||
|
@@ -7,66 +7,17 @@ require 'thread'
|
|
7
7
|
module Jaeger
|
8
8
|
module Client
|
9
9
|
class UdpSender
|
10
|
-
def initialize(
|
11
|
-
@
|
12
|
-
@collector = collector
|
13
|
-
@flush_interval = flush_interval
|
10
|
+
def initialize(host:, port:, encoder:, logger:)
|
11
|
+
@encoder = encoder
|
14
12
|
@logger = logger
|
15
13
|
|
16
|
-
@tags = [
|
17
|
-
Jaeger::Thrift::Tag.new(
|
18
|
-
'key' => 'jaeger.version',
|
19
|
-
'vType' => Jaeger::Thrift::TagType::STRING,
|
20
|
-
'vStr' => 'Ruby-' + Jaeger::Client::VERSION
|
21
|
-
),
|
22
|
-
Jaeger::Thrift::Tag.new(
|
23
|
-
'key' => 'hostname',
|
24
|
-
'vType' => Jaeger::Thrift::TagType::STRING,
|
25
|
-
'vStr' => Socket.gethostname
|
26
|
-
)
|
27
|
-
]
|
28
|
-
ipv4 = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }
|
29
|
-
unless ipv4.nil?
|
30
|
-
@tags << Jaeger::Thrift::Tag.new(
|
31
|
-
'key' => 'ip',
|
32
|
-
'vType' => Jaeger::Thrift::TagType::STRING,
|
33
|
-
'vStr' => ipv4.ip_address
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
14
|
transport = Transport.new(host, port)
|
38
15
|
protocol = ::Thrift::CompactProtocol.new(transport)
|
39
16
|
@client = Jaeger::Thrift::Agent::Client.new(protocol)
|
40
17
|
end
|
41
18
|
|
42
|
-
def
|
43
|
-
|
44
|
-
@thread = Thread.new do
|
45
|
-
loop do
|
46
|
-
emit_batch(@collector.retrieve)
|
47
|
-
sleep @flush_interval
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def stop
|
53
|
-
@thread.terminate if @thread
|
54
|
-
emit_batch(@collector.retrieve)
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def emit_batch(thrift_spans)
|
60
|
-
return if thrift_spans.empty?
|
61
|
-
|
62
|
-
batch = Jaeger::Thrift::Batch.new(
|
63
|
-
'process' => Jaeger::Thrift::Process.new(
|
64
|
-
'serviceName' => @service_name,
|
65
|
-
'tags' => @tags
|
66
|
-
),
|
67
|
-
'spans' => thrift_spans
|
68
|
-
)
|
69
|
-
|
19
|
+
def send_spans(spans)
|
20
|
+
batch = @encoder.encode(spans)
|
70
21
|
@client.emitBatch(batch)
|
71
22
|
rescue StandardError => error
|
72
23
|
@logger.error("Failure while sending a batch of spans: #{error}")
|
data/script/create_trace
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jaeger-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SaleMove TechMovers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -127,8 +127,13 @@ files:
|
|
127
127
|
- bin/setup
|
128
128
|
- jaeger-client.gemspec
|
129
129
|
- lib/jaeger/client.rb
|
130
|
+
- lib/jaeger/client/async_reporter.rb
|
131
|
+
- lib/jaeger/client/async_reporter/buffer.rb
|
130
132
|
- lib/jaeger/client/carrier.rb
|
131
|
-
- lib/jaeger/client/
|
133
|
+
- lib/jaeger/client/encoders/thrift_encoder.rb
|
134
|
+
- lib/jaeger/client/extractors.rb
|
135
|
+
- lib/jaeger/client/http_sender.rb
|
136
|
+
- lib/jaeger/client/injectors.rb
|
132
137
|
- lib/jaeger/client/samplers.rb
|
133
138
|
- lib/jaeger/client/samplers/const.rb
|
134
139
|
- lib/jaeger/client/samplers/probabilistic.rb
|
@@ -182,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
187
|
version: '0'
|
183
188
|
requirements: []
|
184
189
|
rubyforge_project:
|
185
|
-
rubygems_version: 2.7.
|
190
|
+
rubygems_version: 2.7.7
|
186
191
|
signing_key:
|
187
192
|
specification_version: 4
|
188
193
|
summary: OpenTracing Tracer implementation for Jaeger in Ruby
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'thread'
|
4
|
-
|
5
|
-
module Jaeger
|
6
|
-
module Client
|
7
|
-
class Collector
|
8
|
-
def initialize
|
9
|
-
@buffer = Buffer.new
|
10
|
-
end
|
11
|
-
|
12
|
-
def send_span(span, end_time)
|
13
|
-
context = span.context
|
14
|
-
start_ts, duration = build_timestamps(span, end_time)
|
15
|
-
return if !context.sampled? && !context.debug?
|
16
|
-
|
17
|
-
@buffer << Jaeger::Thrift::Span.new(
|
18
|
-
'traceIdLow' => TraceId.uint64_id_to_int64(context.trace_id),
|
19
|
-
'traceIdHigh' => 0,
|
20
|
-
'spanId' => TraceId.uint64_id_to_int64(context.span_id),
|
21
|
-
'parentSpanId' => TraceId.uint64_id_to_int64(context.parent_id),
|
22
|
-
'operationName' => span.operation_name,
|
23
|
-
'references' => build_references(span.references || []),
|
24
|
-
'flags' => context.flags,
|
25
|
-
'startTime' => start_ts,
|
26
|
-
'duration' => duration,
|
27
|
-
'tags' => span.tags,
|
28
|
-
'logs' => span.logs
|
29
|
-
)
|
30
|
-
end
|
31
|
-
|
32
|
-
def retrieve
|
33
|
-
@buffer.retrieve
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def build_references(references)
|
39
|
-
references.map do |ref|
|
40
|
-
Jaeger::Thrift::SpanRef.new(
|
41
|
-
'refType' => span_ref_type(ref.type),
|
42
|
-
'traceIdLow' => ref.context.trace_id,
|
43
|
-
'traceIdHigh' => 0,
|
44
|
-
'spanId' => ref.context.span_id
|
45
|
-
)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def build_timestamps(span, end_time)
|
50
|
-
start_ts = (span.start_time.to_f * 1_000_000).to_i
|
51
|
-
end_ts = (end_time.to_f * 1_000_000).to_i
|
52
|
-
duration = end_ts - start_ts
|
53
|
-
[start_ts, duration]
|
54
|
-
end
|
55
|
-
|
56
|
-
def span_ref_type(type)
|
57
|
-
case type
|
58
|
-
when OpenTracing::Reference::CHILD_OF
|
59
|
-
Jaeger::Thrift::SpanRefType::CHILD_OF
|
60
|
-
when OpenTracing::Reference::FOLLOWS_FROM
|
61
|
-
Jaeger::Thrift::SpanRefType::FOLLOWS_FROM
|
62
|
-
else
|
63
|
-
warn "Jaeger::Client with format #{type} is not supported yet"
|
64
|
-
nil
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
class Buffer
|
69
|
-
def initialize
|
70
|
-
@buffer = []
|
71
|
-
@mutex = Mutex.new
|
72
|
-
end
|
73
|
-
|
74
|
-
def <<(element)
|
75
|
-
@mutex.synchronize do
|
76
|
-
@buffer << element
|
77
|
-
true
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def retrieve
|
82
|
-
@mutex.synchronize do
|
83
|
-
elements = @buffer.dup
|
84
|
-
@buffer.clear
|
85
|
-
elements
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|