lightstep 0.12.0 → 0.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +32 -0
- data/.gitignore +1 -2
- data/.rubocop.yml +48 -0
- data/CHANGELOG.md +45 -0
- data/CONTRIBUTING.md +58 -0
- data/Gemfile.lock +52 -0
- data/Makefile +3 -3
- data/README.md +4 -1
- data/example.rb +2 -2
- data/examples/rack/inject_extract.rb +1 -1
- data/lib/lightstep.rb +4 -0
- data/lib/lightstep/propagation.rb +25 -0
- data/lib/lightstep/propagation/b3_propagator.rb +29 -0
- data/lib/lightstep/propagation/lightstep_propagator.rb +127 -0
- data/lib/lightstep/reporter.rb +14 -9
- data/lib/lightstep/scope.rb +23 -0
- data/lib/lightstep/scope_manager.rb +54 -0
- data/lib/lightstep/span.rb +44 -19
- data/lib/lightstep/span_context.rb +36 -3
- data/lib/lightstep/tracer.rb +131 -100
- data/lib/lightstep/transport/base.rb +0 -3
- data/lib/lightstep/transport/http_json.rb +74 -23
- data/lib/lightstep/version.rb +1 -1
- data/lightstep.gemspec +8 -4
- metadata +26 -17
- data/circle.yml +0 -3
data/lib/lightstep/reporter.rb
CHANGED
@@ -57,7 +57,10 @@ module LightStep
|
|
57
57
|
|
58
58
|
span_records = @span_records.slice!(0, @span_records.length)
|
59
59
|
dropped_spans = 0
|
60
|
-
@dropped_spans.update
|
60
|
+
@dropped_spans.update do |old|
|
61
|
+
dropped_spans = old
|
62
|
+
0
|
63
|
+
end
|
61
64
|
|
62
65
|
report_request = {
|
63
66
|
runtime: @runtime,
|
@@ -65,9 +68,10 @@ module LightStep
|
|
65
68
|
youngest_micros: now,
|
66
69
|
span_records: span_records,
|
67
70
|
internal_metrics: {
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
+
counts: [{
|
72
|
+
name: 'spans.dropped',
|
73
|
+
int64_value: dropped_spans
|
74
|
+
}]
|
71
75
|
}
|
72
76
|
}
|
73
77
|
|
@@ -75,9 +79,10 @@ module LightStep
|
|
75
79
|
|
76
80
|
begin
|
77
81
|
@transport.report(report_request)
|
78
|
-
rescue
|
79
|
-
|
80
|
-
|
82
|
+
rescue StandardError => e
|
83
|
+
LightStep.logger.error "LightStep error reporting to collector: #{e.message}"
|
84
|
+
# an error occurs, add the previous dropped_spans and count of spans
|
85
|
+
# that would have been recorded
|
81
86
|
@dropped_spans.increment(dropped_spans + span_records.length)
|
82
87
|
end
|
83
88
|
end
|
@@ -103,8 +108,8 @@ module LightStep
|
|
103
108
|
sleep(@period)
|
104
109
|
flush
|
105
110
|
end
|
106
|
-
rescue =>
|
107
|
-
|
111
|
+
rescue StandardError => e
|
112
|
+
LightStep.logger.error "LightStep failed to report spans: #{e.message}"
|
108
113
|
end
|
109
114
|
end
|
110
115
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module LightStep
|
2
|
+
# Scope represents an OpenTracing Scope
|
3
|
+
#
|
4
|
+
# See http://www.opentracing.io for more information.
|
5
|
+
class Scope
|
6
|
+
attr_reader :span
|
7
|
+
|
8
|
+
def initialize(manager:, span:, finish_on_close: true)
|
9
|
+
@manager = manager
|
10
|
+
@span = span
|
11
|
+
@finish_on_close = finish_on_close
|
12
|
+
end
|
13
|
+
|
14
|
+
# Mark the end of the active period for the current thread and Scope,
|
15
|
+
# updating the ScopeManager#active in the process.
|
16
|
+
def close
|
17
|
+
raise(LightStep::Error, 'already closed') if @closed
|
18
|
+
@closed = true
|
19
|
+
@span.finish if @finish_on_close
|
20
|
+
@manager.deactivate
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module LightStep
|
2
|
+
# ScopeManager represents an OpenTracing ScopeManager
|
3
|
+
#
|
4
|
+
# See http://www.opentracing.io for more information.
|
5
|
+
#
|
6
|
+
# The ScopeManager interface abstracts both the activation of Span instances
|
7
|
+
# via ScopeManager#activate and access to an active Span/Scope via
|
8
|
+
# ScopeManager#active
|
9
|
+
#
|
10
|
+
class ScopeManager
|
11
|
+
# Make a span instance active.
|
12
|
+
#
|
13
|
+
# @param span [Span] the Span that should become active
|
14
|
+
# @param finish_on_close [Boolean] whether the Span should automatically be
|
15
|
+
# finished when Scope#close is called
|
16
|
+
# @return [Scope] instance to control the end of the active period for the
|
17
|
+
# Span. It is a programming error to neglect to call Scope#close on the
|
18
|
+
# returned instance.
|
19
|
+
def activate(span:, finish_on_close: true)
|
20
|
+
return active if active && active.span == span
|
21
|
+
LightStep::Scope.new(manager: self, span: span, finish_on_close: finish_on_close).tap do |scope|
|
22
|
+
add_scope(scope)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Scope] the currently active Scope which can be used to access the
|
27
|
+
# currently active Span.
|
28
|
+
#
|
29
|
+
# If there is a non-null Scope, its wrapped Span becomes an implicit parent
|
30
|
+
# (as Reference#CHILD_OF) of any newly-created Span at Tracer#start_active_span
|
31
|
+
# or Tracer#start_span time.
|
32
|
+
def active
|
33
|
+
scopes.last
|
34
|
+
end
|
35
|
+
|
36
|
+
def deactivate
|
37
|
+
scopes.pop
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def scopes
|
43
|
+
Thread.current[object_id.to_s] || []
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_scope(scope)
|
47
|
+
if Thread.current[object_id.to_s].nil?
|
48
|
+
Thread.current[object_id.to_s] = [scope]
|
49
|
+
else
|
50
|
+
Thread.current[object_id.to_s] << scope
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/lightstep/span.rb
CHANGED
@@ -11,7 +11,10 @@ module LightStep
|
|
11
11
|
|
12
12
|
# Internal use only
|
13
13
|
# @private
|
14
|
-
attr_reader :start_micros, :end_micros, :tags, :operation_name, :
|
14
|
+
attr_reader :start_micros, :end_micros, :tags, :operation_name, :context
|
15
|
+
|
16
|
+
# To keep backwards compatibility
|
17
|
+
alias_method :span_context, :context
|
15
18
|
|
16
19
|
# Creates a new {Span}
|
17
20
|
#
|
@@ -37,8 +40,9 @@ module LightStep
|
|
37
40
|
tags: nil,
|
38
41
|
max_log_records:
|
39
42
|
)
|
43
|
+
|
40
44
|
@tags = Concurrent::Hash.new
|
41
|
-
@tags.update(tags) unless tags.nil?
|
45
|
+
@tags.update(tags.each { |k, v| tags[k] = v.to_s }) unless tags.nil?
|
42
46
|
@log_records = Concurrent::Array.new
|
43
47
|
@dropped_logs = Concurrent::AtomicFixnum.new
|
44
48
|
@max_log_records = max_log_records
|
@@ -49,14 +53,18 @@ module LightStep
|
|
49
53
|
|
50
54
|
ref = child_of ? child_of : references
|
51
55
|
ref = ref[0] if (Array === ref)
|
52
|
-
ref = ref.
|
56
|
+
ref = ref.context if (Span === ref)
|
53
57
|
|
54
58
|
if SpanContext === ref
|
55
|
-
@
|
59
|
+
@context = SpanContext.new(
|
60
|
+
id: LightStep.guid,
|
61
|
+
trace_id: ref.trace_id,
|
62
|
+
trace_id_upper64: ref.trace_id_upper64,
|
63
|
+
sampled: ref.sampled?)
|
56
64
|
set_baggage(ref.baggage)
|
57
65
|
set_tag(:parent_span_guid, ref.id)
|
58
66
|
else
|
59
|
-
@
|
67
|
+
@context = SpanContext.new(id: LightStep.guid, trace_id: LightStep.guid)
|
60
68
|
end
|
61
69
|
end
|
62
70
|
|
@@ -76,10 +84,12 @@ module LightStep
|
|
76
84
|
# @param key [String] the key of the baggage item
|
77
85
|
# @param value [String] the value of the baggage item
|
78
86
|
def set_baggage_item(key, value)
|
79
|
-
@
|
80
|
-
id:
|
81
|
-
trace_id:
|
82
|
-
|
87
|
+
@context = SpanContext.new(
|
88
|
+
id: context.id,
|
89
|
+
trace_id: context.trace_id,
|
90
|
+
trace_id_upper64: context.trace_id_upper64,
|
91
|
+
sampled: context.sampled?,
|
92
|
+
baggage: context.baggage.merge({key => value})
|
83
93
|
)
|
84
94
|
self
|
85
95
|
end
|
@@ -87,9 +97,11 @@ module LightStep
|
|
87
97
|
# Set all baggage at once. This will reset the baggage to the given param.
|
88
98
|
# @param baggage [Hash] new baggage for the span
|
89
99
|
def set_baggage(baggage = {})
|
90
|
-
@
|
91
|
-
id:
|
92
|
-
trace_id:
|
100
|
+
@context = SpanContext.new(
|
101
|
+
id: context.id,
|
102
|
+
trace_id: context.trace_id,
|
103
|
+
trace_id_upper64: context.trace_id_upper64,
|
104
|
+
sampled: context.sampled?,
|
93
105
|
baggage: baggage
|
94
106
|
)
|
95
107
|
end
|
@@ -98,25 +110,38 @@ module LightStep
|
|
98
110
|
# @param key [String] the key of the baggage item
|
99
111
|
# @return Value of the baggage item
|
100
112
|
def get_baggage_item(key)
|
101
|
-
|
113
|
+
context.baggage[key]
|
102
114
|
end
|
103
115
|
|
116
|
+
# @deprecated Use {#log_kv} instead.
|
104
117
|
# Add a log entry to this span
|
105
118
|
# @param event [String] event name for the log
|
106
119
|
# @param timestamp [Time] time of the log
|
107
|
-
# @param fields [Hash] Additional information to log
|
120
|
+
# @param fields [Hash{Symbol=>Object}] Additional information to log
|
108
121
|
def log(event: nil, timestamp: Time.now, **fields)
|
122
|
+
warn 'Span#log is deprecated. Please use Span#log_kv instead.'
|
109
123
|
return unless tracer.enabled?
|
110
124
|
|
111
125
|
fields = {} if fields.nil?
|
112
126
|
unless event.nil?
|
113
127
|
fields[:event] = event.to_s
|
114
128
|
end
|
129
|
+
|
130
|
+
log_kv(timestamp: timestamp, **fields)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Add a log entry to this span
|
134
|
+
# @param timestamp [Time] time of the log
|
135
|
+
# @param fields [Hash{Symbol=>Object}] Additional information to log
|
136
|
+
def log_kv(timestamp: Time.now, **fields)
|
137
|
+
return unless tracer.enabled?
|
138
|
+
|
139
|
+
fields = {} if fields.nil?
|
115
140
|
record = {
|
116
141
|
timestamp_micros: LightStep.micros(timestamp),
|
117
|
-
fields: fields.to_a.map
|
118
|
-
{Key: key.to_s, Value: value.to_s}
|
119
|
-
|
142
|
+
fields: fields.to_a.map do |key, value|
|
143
|
+
{ Key: key.to_s, Value: value.to_s }
|
144
|
+
end
|
120
145
|
}
|
121
146
|
|
122
147
|
log_records.push(record)
|
@@ -140,8 +165,8 @@ module LightStep
|
|
140
165
|
def to_h
|
141
166
|
{
|
142
167
|
runtime_guid: tracer.guid,
|
143
|
-
span_guid:
|
144
|
-
trace_guid:
|
168
|
+
span_guid: context.id,
|
169
|
+
trace_guid: context.trace_id,
|
145
170
|
span_name: operation_name,
|
146
171
|
attributes: tags.map {|key, value|
|
147
172
|
{Key: key.to_s, Value: value}
|
@@ -1,12 +1,45 @@
|
|
1
|
+
#frozen_string_literal: true
|
2
|
+
|
1
3
|
module LightStep
|
2
4
|
# SpanContext holds the data for a span that gets inherited to child spans
|
3
5
|
class SpanContext
|
4
|
-
attr_reader :id, :trace_id, :baggage
|
6
|
+
attr_reader :id, :trace_id, :trace_id_upper64, :sampled, :baggage
|
7
|
+
alias_method :trace_id64, :trace_id
|
8
|
+
alias_method :sampled?, :sampled
|
9
|
+
|
10
|
+
ZERO_PADDING = '0' * 16
|
5
11
|
|
6
|
-
def initialize(id:, trace_id:, baggage: {})
|
12
|
+
def initialize(id:, trace_id:, trace_id_upper64: nil, sampled: true, baggage: {})
|
7
13
|
@id = id.freeze
|
8
|
-
@trace_id = trace_id.freeze
|
14
|
+
@trace_id = truncate_id(trace_id).freeze
|
15
|
+
@trace_id_upper64 = trace_id_upper64 || extended_bits(trace_id).freeze
|
16
|
+
@sampled = sampled
|
9
17
|
@baggage = baggage.freeze
|
10
18
|
end
|
19
|
+
|
20
|
+
# Lazily initializes and returns a 128-bit representation of a 64-bit trace id
|
21
|
+
def trace_id128
|
22
|
+
@trace_id128 ||= "#{trace_id_upper64 || ZERO_PADDING}#{trace_id}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns true if the original trace_id was 128 bits
|
26
|
+
def id_truncated?
|
27
|
+
!@trace_id_upper64.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Truncates an id to 64 bits
|
33
|
+
def truncate_id(id)
|
34
|
+
return id unless id && id.size == 32
|
35
|
+
id[16..-1]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the most significant 64 bits of a 128 bit id or nil if the id
|
39
|
+
# is 64 bits
|
40
|
+
def extended_bits(id)
|
41
|
+
return unless id && id.size == 32
|
42
|
+
id[0...16]
|
43
|
+
end
|
11
44
|
end
|
12
45
|
end
|
data/lib/lightstep/tracer.rb
CHANGED
@@ -5,6 +5,7 @@ require 'opentracing'
|
|
5
5
|
|
6
6
|
require 'lightstep/span'
|
7
7
|
require 'lightstep/reporter'
|
8
|
+
require 'lightstep/propagation'
|
8
9
|
require 'lightstep/transport/http_json'
|
9
10
|
require 'lightstep/transport/nil'
|
10
11
|
require 'lightstep/transport/callback'
|
@@ -14,6 +15,11 @@ module LightStep
|
|
14
15
|
class Error < LightStep::Error; end
|
15
16
|
class ConfigurationError < LightStep::Tracer::Error; end
|
16
17
|
|
18
|
+
DEFAULT_MAX_LOG_RECORDS = 1000
|
19
|
+
MIN_MAX_LOG_RECORDS = 1
|
20
|
+
DEFAULT_MAX_SPAN_RECORDS = 1000
|
21
|
+
MIN_MAX_SPAN_RECORDS = 1
|
22
|
+
|
17
23
|
attr_reader :access_token, :guid
|
18
24
|
|
19
25
|
# Initialize a new tracer. Either an access_token or a transport must be
|
@@ -22,10 +28,20 @@ module LightStep
|
|
22
28
|
# @param access_token [String] The project access token when pushing to LightStep
|
23
29
|
# @param transport [LightStep::Transport] How the data should be transported
|
24
30
|
# @param tags [Hash] Tracer-level tags
|
31
|
+
# @param propagator [Propagator] Symbol one of :lightstep, :b3 indicating the propagator
|
32
|
+
# to use
|
25
33
|
# @return LightStep::Tracer
|
26
34
|
# @raise LightStep::ConfigurationError if the group name or access token is not a valid string.
|
27
|
-
def initialize(component_name:,
|
28
|
-
|
35
|
+
def initialize(component_name:,
|
36
|
+
access_token: nil,
|
37
|
+
transport: nil,
|
38
|
+
tags: {},
|
39
|
+
propagator: :lightstep)
|
40
|
+
configure(component_name: component_name,
|
41
|
+
access_token: access_token,
|
42
|
+
transport: transport,
|
43
|
+
tags: tags,
|
44
|
+
propagator: propagator)
|
29
45
|
end
|
30
46
|
|
31
47
|
def max_log_records
|
@@ -53,6 +69,83 @@ module LightStep
|
|
53
69
|
|
54
70
|
# TODO(bhs): Support FollowsFrom and multiple references
|
55
71
|
|
72
|
+
# Creates a scope manager or returns the already-created one.
|
73
|
+
#
|
74
|
+
# @return [ScopeManager] the current ScopeManager, which may be a no-op but
|
75
|
+
# may not be nil.
|
76
|
+
def scope_manager
|
77
|
+
@scope_manager ||= LightStep::ScopeManager.new
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns a newly started and activated Scope.
|
81
|
+
#
|
82
|
+
# If ScopeManager#active is not nil, no explicit references are provided,
|
83
|
+
# and `ignore_active_scope` is false, then an inferred References#CHILD_OF
|
84
|
+
# reference is created to the ScopeManager#active's SpanContext when
|
85
|
+
# start_active_span is invoked.
|
86
|
+
#
|
87
|
+
# @param operation_name [String] The operation name for the Span
|
88
|
+
# @param child_of [SpanContext, Span] SpanContext that acts as a parent to
|
89
|
+
# the newly-started Span. If a Span instance is provided, its
|
90
|
+
# context is automatically substituted. See [Reference] for more
|
91
|
+
# information.
|
92
|
+
#
|
93
|
+
# If specified, the `references` parameter must be omitted.
|
94
|
+
# @param references [Array<Reference>] An array of reference
|
95
|
+
# objects that identify one or more parent SpanContexts.
|
96
|
+
# @param start_time [Time] When the Span started, if not now
|
97
|
+
# @param tags [Hash] Tags to assign to the Span at start time
|
98
|
+
# @param ignore_active_scope [Boolean] whether to create an implicit
|
99
|
+
# References#CHILD_OF reference to the ScopeManager#active.
|
100
|
+
# @param finish_on_close [Boolean] whether span should automatically be
|
101
|
+
# finished when Scope#close is called
|
102
|
+
# @yield [Scope] If an optional block is passed to start_active_span it will
|
103
|
+
# yield the newly-started Scope. If `finish_on_close` is true then the
|
104
|
+
# Span will be finished automatically after the block is executed.
|
105
|
+
# @return [Scope, Object] If passed an optional block, start_active_span
|
106
|
+
# returns the block's return value, otherwise it returns the newly-started
|
107
|
+
# and activated Scope
|
108
|
+
def start_active_span(operation_name,
|
109
|
+
child_of: nil,
|
110
|
+
references: nil,
|
111
|
+
start_time: Time.now,
|
112
|
+
tags: nil,
|
113
|
+
ignore_active_scope: false,
|
114
|
+
finish_on_close: true)
|
115
|
+
if child_of.nil? && references.nil? && !ignore_active_scope
|
116
|
+
child_of = active_span
|
117
|
+
end
|
118
|
+
|
119
|
+
span = start_span(
|
120
|
+
operation_name,
|
121
|
+
child_of: child_of,
|
122
|
+
references: references,
|
123
|
+
start_time: start_time,
|
124
|
+
tags: tags,
|
125
|
+
ignore_active_scope: ignore_active_scope
|
126
|
+
)
|
127
|
+
|
128
|
+
scope_manager.activate(span: span, finish_on_close: finish_on_close).tap do |scope|
|
129
|
+
if block_given?
|
130
|
+
begin
|
131
|
+
return yield scope
|
132
|
+
ensure
|
133
|
+
scope.close
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns the span from the active scope, if any.
|
140
|
+
#
|
141
|
+
# @return [Span, nil] the active span. This is a shorthand for
|
142
|
+
# `scope_manager.active.span`, and nil will be returned if
|
143
|
+
# Scope#active is nil.
|
144
|
+
def active_span
|
145
|
+
scope = scope_manager.active
|
146
|
+
scope.span if scope
|
147
|
+
end
|
148
|
+
|
56
149
|
# Starts a new span.
|
57
150
|
#
|
58
151
|
# @param operation_name [String] The operation name for the Span
|
@@ -64,10 +157,21 @@ module LightStep
|
|
64
157
|
# are provided, their .span_context is automatically substituted.
|
65
158
|
# @param start_time [Time] When the Span started, if not now
|
66
159
|
# @param tags [Hash] Tags to assign to the Span at start time
|
67
|
-
# @
|
68
|
-
|
160
|
+
# @param ignore_active_scope [Boolean] whether to create an implicit
|
161
|
+
# References#CHILD_OF reference to the ScopeManager#active.
|
162
|
+
# @yield [Span] If passed an optional block, start_span will yield the
|
163
|
+
# newly-created span to the block. The span will be finished automatically
|
164
|
+
# after the block is executed.
|
165
|
+
# @return [Span, Object] If passed an optional block, start_span will return
|
166
|
+
# the block's return value, otherwise it returns the newly-started Span
|
167
|
+
# instance, which has not been automatically registered via the
|
168
|
+
# ScopeManager
|
169
|
+
def start_span(operation_name, child_of: nil, references: nil, start_time: nil, tags: nil, ignore_active_scope: false)
|
170
|
+
if child_of.nil? && references.nil? && !ignore_active_scope
|
171
|
+
child_of = active_span
|
172
|
+
end
|
69
173
|
|
70
|
-
|
174
|
+
span_options = {
|
71
175
|
tracer: self,
|
72
176
|
operation_name: operation_name,
|
73
177
|
child_of: child_of,
|
@@ -75,25 +179,27 @@ module LightStep
|
|
75
179
|
start_micros: start_time.nil? ? LightStep.micros(Time.now) : LightStep.micros(start_time),
|
76
180
|
tags: tags,
|
77
181
|
max_log_records: max_log_records,
|
78
|
-
|
182
|
+
}
|
183
|
+
|
184
|
+
Span.new(span_options).tap do |span|
|
185
|
+
if block_given?
|
186
|
+
begin
|
187
|
+
return yield span
|
188
|
+
ensure
|
189
|
+
span.finish
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
79
193
|
end
|
80
194
|
|
195
|
+
|
81
196
|
# Inject a SpanContext into the given carrier
|
82
197
|
#
|
83
198
|
# @param spancontext [SpanContext]
|
84
199
|
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY]
|
85
200
|
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
86
201
|
def inject(span_context, format, carrier)
|
87
|
-
|
88
|
-
when OpenTracing::FORMAT_TEXT_MAP
|
89
|
-
inject_to_text_map(span_context, carrier)
|
90
|
-
when OpenTracing::FORMAT_BINARY
|
91
|
-
warn 'Binary inject format not yet implemented'
|
92
|
-
when OpenTracing::FORMAT_RACK
|
93
|
-
inject_to_rack(span_context, carrier)
|
94
|
-
else
|
95
|
-
warn 'Unknown inject format'
|
96
|
-
end
|
202
|
+
@propagator.inject(span_context, format, carrier)
|
97
203
|
end
|
98
204
|
|
99
205
|
# Extract a SpanContext from a carrier
|
@@ -101,18 +207,7 @@ module LightStep
|
|
101
207
|
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
102
208
|
# @return [SpanContext] the extracted SpanContext or nil if none could be found
|
103
209
|
def extract(format, carrier)
|
104
|
-
|
105
|
-
when OpenTracing::FORMAT_TEXT_MAP
|
106
|
-
extract_from_text_map(carrier)
|
107
|
-
when OpenTracing::FORMAT_BINARY
|
108
|
-
warn 'Binary join format not yet implemented'
|
109
|
-
nil
|
110
|
-
when OpenTracing::FORMAT_RACK
|
111
|
-
extract_from_rack(carrier)
|
112
|
-
else
|
113
|
-
warn 'Unknown join format'
|
114
|
-
nil
|
115
|
-
end
|
210
|
+
@propagator.extract(format, carrier)
|
116
211
|
end
|
117
212
|
|
118
213
|
# @return true if the tracer is enabled
|
@@ -149,8 +244,12 @@ module LightStep
|
|
149
244
|
|
150
245
|
protected
|
151
246
|
|
152
|
-
def configure(component_name:,
|
153
|
-
|
247
|
+
def configure(component_name:,
|
248
|
+
access_token: nil,
|
249
|
+
transport: nil, tags: {},
|
250
|
+
propagator: :lightstep)
|
251
|
+
|
252
|
+
raise ConfigurationError, "component_name must be a string" unless component_name.is_a?(String)
|
154
253
|
raise ConfigurationError, "component_name cannot be blank" if component_name.empty?
|
155
254
|
|
156
255
|
if transport.nil? and !access_token.nil?
|
@@ -160,6 +259,8 @@ module LightStep
|
|
160
259
|
raise ConfigurationError, "you must provide an access token or a transport" if transport.nil?
|
161
260
|
raise ConfigurationError, "#{transport} is not a LightStep transport class" if !(LightStep::Transport::Base === transport)
|
162
261
|
|
262
|
+
@propagator = Propagation[propagator]
|
263
|
+
|
163
264
|
@guid = LightStep.guid
|
164
265
|
|
165
266
|
@reporter = LightStep::Reporter.new(
|
@@ -170,75 +271,5 @@ module LightStep
|
|
170
271
|
tags: tags
|
171
272
|
)
|
172
273
|
end
|
173
|
-
|
174
|
-
private
|
175
|
-
|
176
|
-
CARRIER_TRACER_STATE_PREFIX = 'ot-tracer-'.freeze
|
177
|
-
CARRIER_BAGGAGE_PREFIX = 'ot-baggage-'.freeze
|
178
|
-
|
179
|
-
CARRIER_SPAN_ID = (CARRIER_TRACER_STATE_PREFIX + 'spanid').freeze
|
180
|
-
CARRIER_TRACE_ID = (CARRIER_TRACER_STATE_PREFIX + 'traceid').freeze
|
181
|
-
CARRIER_SAMPLED = (CARRIER_TRACER_STATE_PREFIX + 'sampled').freeze
|
182
|
-
|
183
|
-
DEFAULT_MAX_LOG_RECORDS = 1000
|
184
|
-
MIN_MAX_LOG_RECORDS = 1
|
185
|
-
DEFAULT_MAX_SPAN_RECORDS = 1000
|
186
|
-
MIN_MAX_SPAN_RECORDS = 1
|
187
|
-
|
188
|
-
def inject_to_text_map(span_context, carrier)
|
189
|
-
carrier[CARRIER_SPAN_ID] = span_context.id
|
190
|
-
carrier[CARRIER_TRACE_ID] = span_context.trace_id unless span_context.trace_id.nil?
|
191
|
-
carrier[CARRIER_SAMPLED] = 'true'
|
192
|
-
|
193
|
-
span_context.baggage.each do |key, value|
|
194
|
-
carrier[CARRIER_BAGGAGE_PREFIX + key] = value
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def extract_from_text_map(carrier)
|
199
|
-
# If the carrier does not have both the span_id and trace_id key
|
200
|
-
# skip the processing and just return a normal span
|
201
|
-
if !carrier.has_key?(CARRIER_SPAN_ID) || !carrier.has_key?(CARRIER_TRACE_ID)
|
202
|
-
return nil
|
203
|
-
end
|
204
|
-
|
205
|
-
baggage = carrier.reduce({}) do |baggage, tuple|
|
206
|
-
key, value = tuple
|
207
|
-
if key.start_with?(CARRIER_BAGGAGE_PREFIX)
|
208
|
-
plain_key = key.to_s[CARRIER_BAGGAGE_PREFIX.length..key.to_s.length]
|
209
|
-
baggage[plain_key] = value
|
210
|
-
end
|
211
|
-
baggage
|
212
|
-
end
|
213
|
-
SpanContext.new(
|
214
|
-
id: carrier[CARRIER_SPAN_ID],
|
215
|
-
trace_id: carrier[CARRIER_TRACE_ID],
|
216
|
-
baggage: baggage,
|
217
|
-
)
|
218
|
-
end
|
219
|
-
|
220
|
-
def inject_to_rack(span_context, carrier)
|
221
|
-
carrier[CARRIER_SPAN_ID] = span_context.id
|
222
|
-
carrier[CARRIER_TRACE_ID] = span_context.trace_id unless span_context.trace_id.nil?
|
223
|
-
carrier[CARRIER_SAMPLED] = 'true'
|
224
|
-
|
225
|
-
span_context.baggage.each do |key, value|
|
226
|
-
if key =~ /[^A-Za-z0-9\-_]/
|
227
|
-
# TODO: log the error internally
|
228
|
-
next
|
229
|
-
end
|
230
|
-
carrier[CARRIER_BAGGAGE_PREFIX + key] = value
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def extract_from_rack(env)
|
235
|
-
extract_from_text_map(env.reduce({}){|memo, tuple|
|
236
|
-
raw_header, value = tuple
|
237
|
-
header = raw_header.gsub(/^HTTP_/, '').gsub("_", "-").downcase
|
238
|
-
|
239
|
-
memo[header] = value if header.start_with?(CARRIER_TRACER_STATE_PREFIX, CARRIER_BAGGAGE_PREFIX)
|
240
|
-
memo
|
241
|
-
})
|
242
|
-
end
|
243
274
|
end
|
244
275
|
end
|