dox-jaeger-client 2.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 +7 -0
- data/.github/workflows/ci.yml +33 -0
- data/.gitignore +12 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +61 -0
- data/.rubocop_todo.yml +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/Makefile +1 -0
- data/README.md +210 -0
- data/Rakefile +9 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/crossdock/Dockerfile +31 -0
- data/crossdock/Gemfile +6 -0
- data/crossdock/Gemfile.lock +37 -0
- data/crossdock/docker-compose.yml +68 -0
- data/crossdock/jaeger-docker-compose.yml +53 -0
- data/crossdock/rules.mk +35 -0
- data/crossdock/server +175 -0
- data/jaeger-client.gemspec +37 -0
- data/lib/jaeger/client/version.rb +7 -0
- data/lib/jaeger/client.rb +77 -0
- data/lib/jaeger/encoders/thrift_encoder.rb +173 -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/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/reporters/remote_reporter/buffer.rb +29 -0
- data/lib/jaeger/reporters/remote_reporter.rb +42 -0
- data/lib/jaeger/reporters.rb +7 -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 +77 -0
- data/lib/jaeger/samplers/probabilistic.rb +40 -0
- data/lib/jaeger/samplers/rate_limiting.rb +51 -0
- data/lib/jaeger/samplers/remote_controlled/instructions_fetcher.rb +34 -0
- data/lib/jaeger/samplers/remote_controlled.rb +119 -0
- data/lib/jaeger/samplers.rb +8 -0
- data/lib/jaeger/scope.rb +39 -0
- data/lib/jaeger/scope_manager/scope_identifier.rb +13 -0
- data/lib/jaeger/scope_manager/scope_stack.rb +33 -0
- data/lib/jaeger/scope_manager.rb +48 -0
- data/lib/jaeger/span/thrift_log_builder.rb +18 -0
- data/lib/jaeger/span.rb +97 -0
- data/lib/jaeger/span_context.rb +57 -0
- data/lib/jaeger/thrift_tag_builder.rb +42 -0
- data/lib/jaeger/trace_id.rb +48 -0
- data/lib/jaeger/tracer.rb +214 -0
- data/lib/jaeger/udp_sender/transport.rb +41 -0
- data/lib/jaeger/udp_sender.rb +26 -0
- data/script/create_follows_from_trace +51 -0
- data/script/create_trace +52 -0
- data/thrift/agent.thrift +32 -0
- data/thrift/gen-rb/jaeger/thrift/agent/agent.rb +118 -0
- data/thrift/gen-rb/jaeger/thrift/agent/agent_constants.rb +15 -0
- data/thrift/gen-rb/jaeger/thrift/agent/agent_types.rb +17 -0
- data/thrift/gen-rb/jaeger/thrift/agent.rb +116 -0
- data/thrift/gen-rb/jaeger/thrift/agent_constants.rb +13 -0
- data/thrift/gen-rb/jaeger/thrift/agent_types.rb +15 -0
- data/thrift/gen-rb/jaeger/thrift/collector.rb +82 -0
- data/thrift/gen-rb/jaeger/thrift/jaeger_constants.rb +13 -0
- data/thrift/gen-rb/jaeger/thrift/jaeger_types.rb +211 -0
- data/thrift/gen-rb/jaeger/thrift/zipkin/zipkin_collector.rb +84 -0
- data/thrift/gen-rb/jaeger/thrift/zipkin/zipkincore_constants.rb +41 -0
- data/thrift/gen-rb/jaeger/thrift/zipkin/zipkincore_types.rb +220 -0
- data/thrift/jaeger.thrift +88 -0
- data/thrift/zipkincore.thrift +300 -0
- metadata +260 -0
@@ -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'
|
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,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'samplers/const'
|
4
|
+
require_relative 'samplers/guaranteed_throughput_probabilistic'
|
5
|
+
require_relative 'samplers/per_operation'
|
6
|
+
require_relative 'samplers/probabilistic'
|
7
|
+
require_relative 'samplers/rate_limiting'
|
8
|
+
require_relative 'samplers/remote_controlled'
|
data/lib/jaeger/scope.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
# Scope represents an OpenTracing Scope
|
5
|
+
#
|
6
|
+
# See http://www.opentracing.io for more information.
|
7
|
+
class Scope
|
8
|
+
def initialize(span, scope_stack, finish_on_close:)
|
9
|
+
@span = span
|
10
|
+
@scope_stack = scope_stack
|
11
|
+
@finish_on_close = finish_on_close
|
12
|
+
@closed = false
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return the Span scoped by this Scope
|
16
|
+
#
|
17
|
+
# @return [Span]
|
18
|
+
attr_reader :span
|
19
|
+
|
20
|
+
# Close scope
|
21
|
+
#
|
22
|
+
# Mark the end of the active period for the current thread and Scope,
|
23
|
+
# updating the ScopeManager#active in the process.
|
24
|
+
def close
|
25
|
+
raise "Tried to close already closed span: #{inspect}" if @closed
|
26
|
+
|
27
|
+
@closed = true
|
28
|
+
|
29
|
+
@span.finish if @finish_on_close
|
30
|
+
removed_scope = @scope_stack.pop
|
31
|
+
|
32
|
+
if removed_scope != self # rubocop:disable Style/GuardClause
|
33
|
+
raise 'Removed non-active scope, ' \
|
34
|
+
"removed: #{removed_scope.inspect}, "\
|
35
|
+
"expected: #{inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
class ScopeManager
|
5
|
+
# @api private
|
6
|
+
class ScopeIdentifier
|
7
|
+
def self.generate
|
8
|
+
# 65..90.chr are characters between A and Z
|
9
|
+
"opentracing_#{(0...8).map { rand(65..90).chr }.join}".to_sym
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
class ScopeManager
|
5
|
+
# @api private
|
6
|
+
class ScopeStack
|
7
|
+
def initialize
|
8
|
+
# Generate a random identifier to use as the Thread.current key. This is
|
9
|
+
# needed so that it would be possible to create multiple tracers in one
|
10
|
+
# thread (mostly useful for testing purposes)
|
11
|
+
@scope_identifier = ScopeIdentifier.generate
|
12
|
+
end
|
13
|
+
|
14
|
+
def push(scope)
|
15
|
+
store << scope
|
16
|
+
end
|
17
|
+
|
18
|
+
def pop
|
19
|
+
store.pop
|
20
|
+
end
|
21
|
+
|
22
|
+
def peek
|
23
|
+
store.last
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def store
|
29
|
+
Thread.current[@scope_identifier] ||= []
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'scope_manager/scope_stack'
|
4
|
+
require_relative 'scope_manager/scope_identifier'
|
5
|
+
|
6
|
+
module Jaeger
|
7
|
+
# ScopeManager represents an OpenTracing ScopeManager
|
8
|
+
#
|
9
|
+
# See http://www.opentracing.io for more information.
|
10
|
+
#
|
11
|
+
# The ScopeManager interface abstracts both the activation of Span instances
|
12
|
+
# via ScopeManager#activate and access to an active Span/Scope via
|
13
|
+
# ScopeManager#active
|
14
|
+
#
|
15
|
+
class ScopeManager
|
16
|
+
def initialize
|
17
|
+
@scope_stack = ScopeStack.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# Make a span instance active
|
21
|
+
#
|
22
|
+
# @param span [Span] the Span that should become active
|
23
|
+
# @param finish_on_close [Boolean] whether the Span should automatically be
|
24
|
+
# finished when Scope#close is called
|
25
|
+
# @return [Scope] instance to control the end of the active period for the
|
26
|
+
# Span. It is a programming error to neglect to call Scope#close on the
|
27
|
+
# returned instance.
|
28
|
+
def activate(span, finish_on_close: true)
|
29
|
+
return active if active && active.span == span
|
30
|
+
|
31
|
+
scope = Scope.new(span, @scope_stack, finish_on_close: finish_on_close)
|
32
|
+
@scope_stack.push(scope)
|
33
|
+
scope
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return active scope
|
37
|
+
#
|
38
|
+
# If there is a non-null Scope, its wrapped Span becomes an implicit parent
|
39
|
+
# (as Reference#CHILD_OF) of any newly-created Span at
|
40
|
+
# Tracer#start_active_span or Tracer#start_span time.
|
41
|
+
#
|
42
|
+
# @return [Scope] the currently active Scope which can be used to access the
|
43
|
+
# currently active Span.
|
44
|
+
def active
|
45
|
+
@scope_stack.peek
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
class Span
|
5
|
+
class ThriftLogBuilder
|
6
|
+
FIELDS = Jaeger::Thrift::Log::FIELDS
|
7
|
+
TIMESTAMP = FIELDS[Jaeger::Thrift::Log::TIMESTAMP].fetch(:name)
|
8
|
+
LOG_FIELDS = FIELDS[Jaeger::Thrift::Log::LOG_FIELDS].fetch(:name)
|
9
|
+
|
10
|
+
def self.build(timestamp, fields)
|
11
|
+
Jaeger::Thrift::Log.new(
|
12
|
+
TIMESTAMP => (timestamp.to_f * 1_000_000).to_i,
|
13
|
+
LOG_FIELDS => fields.map { |key, value| ThriftTagBuilder.build(key, value) }
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/jaeger/span.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'span/thrift_log_builder'
|
4
|
+
|
5
|
+
module Jaeger
|
6
|
+
class Span
|
7
|
+
attr_accessor :operation_name
|
8
|
+
|
9
|
+
attr_reader :context, :start_time, :end_time, :references, :tags, :logs
|
10
|
+
|
11
|
+
# Creates a new {Span}
|
12
|
+
#
|
13
|
+
# @param context [SpanContext] the context of the span
|
14
|
+
# @param operation_name [String] the operation name
|
15
|
+
# @param reporter [#report] span reporter
|
16
|
+
#
|
17
|
+
# @return [Span] a new Span
|
18
|
+
def initialize(context, operation_name, reporter, start_time: Time.now, references: [], tags: {})
|
19
|
+
@context = context
|
20
|
+
@operation_name = operation_name
|
21
|
+
@reporter = reporter
|
22
|
+
@start_time = start_time
|
23
|
+
@references = references
|
24
|
+
@tags = []
|
25
|
+
@logs = []
|
26
|
+
|
27
|
+
tags.each { |key, value| set_tag(key, value) }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set a tag value on this span
|
31
|
+
#
|
32
|
+
# @param key [String] the key of the tag
|
33
|
+
# @param value [String, Numeric, Boolean] the value of the tag. If it's not
|
34
|
+
# a String, Numeric, or Boolean it will be encoded with to_s
|
35
|
+
def set_tag(key, value)
|
36
|
+
if key == 'sampling.priority'
|
37
|
+
if value.to_i.positive?
|
38
|
+
return self if @context.debug?
|
39
|
+
|
40
|
+
@context.flags = @context.flags | SpanContext::Flags::SAMPLED | SpanContext::Flags::DEBUG
|
41
|
+
else
|
42
|
+
@context.flags = @context.flags & ~SpanContext::Flags::SAMPLED
|
43
|
+
end
|
44
|
+
return self
|
45
|
+
end
|
46
|
+
|
47
|
+
# Using Thrift::Tag to avoid unnecessary memory allocations
|
48
|
+
@tags << ThriftTagBuilder.build(key, value)
|
49
|
+
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Set a baggage item on the span
|
54
|
+
#
|
55
|
+
# @param key [String] the key of the baggage item
|
56
|
+
# @param value [String] the value of the baggage item
|
57
|
+
def set_baggage_item(key, value)
|
58
|
+
@context.set_baggage_item(key, value)
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get a baggage item
|
63
|
+
#
|
64
|
+
# @param key [String] the key of the baggage item
|
65
|
+
#
|
66
|
+
# @return Value of the baggage item
|
67
|
+
def get_baggage_item(key)
|
68
|
+
@context.get_baggage_item(key)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Add a log entry to this span
|
72
|
+
#
|
73
|
+
# @deprecated Use {#log_kv} instead.
|
74
|
+
def log(...)
|
75
|
+
warn 'Span#log is deprecated. Please use Span#log_kv instead.'
|
76
|
+
log_kv(...)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Add a log entry to this span
|
80
|
+
#
|
81
|
+
# @param timestamp [Time] time of the log
|
82
|
+
# @param fields [Hash] Additional information to log
|
83
|
+
def log_kv(timestamp: Time.now, **fields)
|
84
|
+
# Using Thrift::Log to avoid unnecessary memory allocations
|
85
|
+
@logs << ThriftLogBuilder.build(timestamp, fields)
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
|
89
|
+
# Finish the {Span}
|
90
|
+
#
|
91
|
+
# @param end_time [Time] custom end time, if not now
|
92
|
+
def finish(end_time: Time.now)
|
93
|
+
@end_time = end_time
|
94
|
+
@reporter.report(self)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
# SpanContext holds the data for a span that gets inherited to child spans
|
5
|
+
class SpanContext
|
6
|
+
module Flags
|
7
|
+
NONE = 0x00
|
8
|
+
SAMPLED = 0x01
|
9
|
+
DEBUG = 0x02
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.create_from_parent_context(span_context)
|
13
|
+
new(
|
14
|
+
trace_id: span_context.trace_id,
|
15
|
+
parent_id: span_context.span_id,
|
16
|
+
span_id: TraceId.generate,
|
17
|
+
flags: span_context.flags,
|
18
|
+
baggage: span_context.baggage.dup
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :flags
|
23
|
+
attr_reader :span_id, :parent_id, :trace_id, :baggage
|
24
|
+
|
25
|
+
def initialize(span_id:, trace_id:, flags:, parent_id: 0, baggage: {})
|
26
|
+
@span_id = span_id
|
27
|
+
@parent_id = parent_id
|
28
|
+
@trace_id = trace_id
|
29
|
+
@baggage = baggage
|
30
|
+
@flags = flags
|
31
|
+
end
|
32
|
+
|
33
|
+
def sampled?
|
34
|
+
@flags & Flags::SAMPLED == Flags::SAMPLED
|
35
|
+
end
|
36
|
+
|
37
|
+
def debug?
|
38
|
+
@flags & Flags::DEBUG == Flags::DEBUG
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_trace_id
|
42
|
+
@to_trace_id ||= @trace_id.to_s(16)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_span_id
|
46
|
+
@to_span_id ||= @span_id.to_s(16)
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_baggage_item(key, value)
|
50
|
+
@baggage[key.to_s] = value.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_baggage_item(key)
|
54
|
+
@baggage[key.to_s]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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
|
+
case value
|
15
|
+
when Integer
|
16
|
+
Jaeger::Thrift::Tag.new(
|
17
|
+
KEY => key.to_s,
|
18
|
+
VTYPE => Jaeger::Thrift::TagType::LONG,
|
19
|
+
VLONG => value
|
20
|
+
)
|
21
|
+
when Float
|
22
|
+
Jaeger::Thrift::Tag.new(
|
23
|
+
KEY => key.to_s,
|
24
|
+
VTYPE => Jaeger::Thrift::TagType::DOUBLE,
|
25
|
+
VDOUBLE => value
|
26
|
+
)
|
27
|
+
when TrueClass, 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
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jaeger
|
4
|
+
module TraceId
|
5
|
+
MAX_64BIT_SIGNED_INT = (1 << 63) - 1
|
6
|
+
MAX_64BIT_UNSIGNED_INT = (1 << 64) - 1
|
7
|
+
MAX_128BIT_UNSIGNED_INT = (1 << 128) - 1
|
8
|
+
TRACE_ID_UPPER_BOUND = MAX_64BIT_UNSIGNED_INT + 1
|
9
|
+
|
10
|
+
def self.generate
|
11
|
+
rand(TRACE_ID_UPPER_BOUND)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.base16_hex_id_to_uint64(id)
|
15
|
+
return nil unless id
|
16
|
+
|
17
|
+
value = id.to_i(16)
|
18
|
+
value > MAX_64BIT_UNSIGNED_INT || value.negative? ? 0 : value
|
19
|
+
end
|
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.negative? ? 0 : value
|
26
|
+
end
|
27
|
+
|
28
|
+
# Thrift defines ID fields as i64, which is signed, therefore we convert
|
29
|
+
# large IDs (> 2^63) to negative longs
|
30
|
+
def self.uint64_id_to_int64(id)
|
31
|
+
id > MAX_64BIT_SIGNED_INT ? id - MAX_64BIT_UNSIGNED_INT - 1 : id
|
32
|
+
end
|
33
|
+
|
34
|
+
# Convert an integer id into a 0 padded hex string.
|
35
|
+
# If the string is shorter than 16 characters, it will be padded to 16.
|
36
|
+
# If it is longer than 16 characters, it is padded to 32.
|
37
|
+
def self.to_hex(id)
|
38
|
+
hex_str = id.to_s(16)
|
39
|
+
|
40
|
+
# pad the string with '0's to 16 or 32 characters
|
41
|
+
if hex_str.length > 16
|
42
|
+
hex_str.rjust(32, '0')
|
43
|
+
else
|
44
|
+
hex_str.rjust(16, '0')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|