instana 0.15.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Troubleshooting.md +32 -0
- data/lib/instana/agent.rb +1 -1
- data/lib/instana/instrumentation/excon.rb +3 -2
- data/lib/instana/instrumentation/net-http.rb +3 -2
- data/lib/instana/instrumentation/rack.rb +4 -4
- data/lib/instana/logger.rb +10 -4
- data/lib/instana/opentracing/carrier.rb +4 -0
- data/lib/instana/opentracing/tracer.rb +18 -0
- data/lib/instana/setup.rb +3 -0
- data/lib/instana/tracer.rb +107 -68
- data/lib/instana/tracing/processor.rb +5 -6
- data/lib/instana/tracing/span.rb +322 -2
- data/lib/instana/tracing/span_context.rb +31 -0
- data/lib/instana/tracing/trace.rb +51 -190
- data/lib/instana/util.rb +77 -0
- data/lib/instana/version.rb +1 -1
- data/lib/opentracing.rb +6 -0
- metadata +8 -3
@@ -147,21 +147,20 @@ module Instana
|
|
147
147
|
# are traces that have completed but may have outstanding
|
148
148
|
# asynchronous spans.
|
149
149
|
#
|
150
|
-
# @param
|
151
|
-
# :trace_id => 12345
|
152
|
-
# :span_id => 12345
|
150
|
+
# @param trace_id [Integer] the Trace ID to be searched for
|
153
151
|
#
|
154
|
-
def staged_trace(
|
152
|
+
def staged_trace(trace_id)
|
155
153
|
candidate = nil
|
156
154
|
@staging_lock.synchronize {
|
157
155
|
@staging_queue.each do |trace|
|
158
|
-
if trace.id ==
|
156
|
+
if trace.id == trace_id
|
159
157
|
candidate = trace
|
158
|
+
break
|
160
159
|
end
|
161
160
|
end
|
162
161
|
}
|
163
162
|
unless candidate
|
164
|
-
::Instana.logger.trace("Couldn't find staged trace with trace_id: #{
|
163
|
+
::Instana.logger.trace("Couldn't find staged trace with trace_id: #{trace_id}")
|
165
164
|
end
|
166
165
|
candidate
|
167
166
|
end
|
data/lib/instana/tracing/span.rb
CHANGED
@@ -1,19 +1,187 @@
|
|
1
1
|
module Instana
|
2
2
|
class Span
|
3
|
+
REGISTERED_SPANS = [ :rack, :'net-http', :excon ].freeze
|
4
|
+
ENTRY_SPANS = [ :rack ].freeze
|
5
|
+
EXIT_SPANS = [ :'net-http', :excon ].freeze
|
6
|
+
HTTP_SPANS = ENTRY_SPANS + EXIT_SPANS
|
7
|
+
|
3
8
|
attr_accessor :parent
|
9
|
+
attr_accessor :baggage
|
10
|
+
|
11
|
+
def initialize(name, trace_id, parent_id: nil, start_time: Time.now)
|
12
|
+
@data = {}
|
13
|
+
@data[:t] = trace_id # Trace ID
|
14
|
+
@data[:s] = ::Instana::Util.generate_id # Span ID
|
15
|
+
@data[:p] = parent_id if parent_id # Parent ID
|
16
|
+
@data[:ta] = :ruby # Agent
|
17
|
+
@data[:data] = {}
|
18
|
+
|
19
|
+
# Entity Source
|
20
|
+
@data[:f] = { :e => ::Instana.agent.report_pid,
|
21
|
+
:h => ::Instana.agent.agent_uuid }
|
22
|
+
# Start time
|
23
|
+
@data[:ts] = ::Instana::Util.time_to_ms(start_time)
|
24
|
+
|
25
|
+
@baggage = {}
|
26
|
+
|
27
|
+
# For entry spans, add a backtrace fingerprint
|
28
|
+
add_stack(limit: 2) if ENTRY_SPANS.include?(name)
|
29
|
+
|
30
|
+
# Attach a backtrace to all exit spans
|
31
|
+
add_stack if EXIT_SPANS.include?(name)
|
32
|
+
|
33
|
+
# Check for custom tracing
|
34
|
+
if REGISTERED_SPANS.include?(name.to_sym)
|
35
|
+
@data[:n] = name.to_sym
|
36
|
+
else
|
37
|
+
configure_custom(name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Adds a backtrace to this span
|
42
|
+
#
|
43
|
+
# @param limit [Integer] Limit the backtrace to the top <limit> frames
|
44
|
+
#
|
45
|
+
def add_stack(limit: nil, stack: Kernel.caller)
|
46
|
+
frame_count = 0
|
47
|
+
@data[:stack] = []
|
48
|
+
|
49
|
+
stack.each do |i|
|
50
|
+
# If the stack has the full instana gem version in it's path
|
51
|
+
# then don't include that frame. Also don't exclude the Rack module.
|
52
|
+
if !i.match(/instana\/instrumentation\/rack.rb/).nil? ||
|
53
|
+
(i.match(::Instana::VERSION_FULL).nil? && i.match('lib/instana/').nil?)
|
54
|
+
|
55
|
+
break if limit && frame_count >= limit
|
56
|
+
|
57
|
+
x = i.split(':')
|
58
|
+
|
59
|
+
@data[:stack] << {
|
60
|
+
:f => x[0],
|
61
|
+
:n => x[1],
|
62
|
+
:m => x[2]
|
63
|
+
}
|
64
|
+
frame_count = frame_count + 1 if limit
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Log an error into the span
|
70
|
+
#
|
71
|
+
# @param e [Exception] The exception to be logged
|
72
|
+
#
|
73
|
+
def add_error(e)
|
74
|
+
@data[:error] = true
|
75
|
+
|
76
|
+
if @data.key?(:ec)
|
77
|
+
@data[:ec] = @data[:ec] + 1
|
78
|
+
else
|
79
|
+
@data[:ec] = 1
|
80
|
+
end
|
81
|
+
|
82
|
+
# If a valid exception has been passed in, log the information about it
|
83
|
+
# In case of just logging an error for things such as HTTP client 5xx
|
84
|
+
# responses, an exception/backtrace may not exist.
|
85
|
+
if e
|
86
|
+
if e.backtrace.is_a?(Array)
|
87
|
+
add_stack(stack: e.backtrace)
|
88
|
+
end
|
89
|
+
|
90
|
+
if HTTP_SPANS.include?(@data[:n])
|
91
|
+
set_tags(:http => { :error => "#{e.class}: #{e.message}" })
|
92
|
+
else
|
93
|
+
set_tags(:log => { :message => e.message, :parameters => e.class })
|
94
|
+
end
|
95
|
+
e.instance_variable_set(:@instana_logged, true)
|
96
|
+
end
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Configure this span to be a custom span per the
|
102
|
+
# SDK generic span type.
|
103
|
+
#
|
104
|
+
# @param name [String] name of the span
|
105
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
106
|
+
#
|
107
|
+
def configure_custom(name)
|
108
|
+
@data[:n] = :sdk
|
109
|
+
@data[:data] = { :sdk => { :name => name.to_sym } }
|
4
110
|
|
5
|
-
|
6
|
-
@data =
|
111
|
+
#if kvs.is_a?(Hash)
|
112
|
+
# @data[:data][:sdk][:type] = kvs.key?(:type) ? kvs[:type] : :local
|
113
|
+
#
|
114
|
+
# if kvs.key?(:arguments)
|
115
|
+
# @data[:data][:sdk][:arguments] = kvs[:arguments]
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# if kvs.key?(:return)
|
119
|
+
# @data[:data][:sdk][:return] = kvs[:return]
|
120
|
+
# end
|
121
|
+
# @data[:data][:sdk][:custom] = kvs unless kvs.empty?
|
122
|
+
# end
|
123
|
+
self
|
7
124
|
end
|
8
125
|
|
126
|
+
# Closes out the span. This difference between this and
|
127
|
+
# the finish method tells us how the tracing is being
|
128
|
+
# performed (with OpenTracing or Instana default)
|
129
|
+
#
|
130
|
+
# @param end_time [Time] custom end time, if not now
|
131
|
+
# @return [Span]
|
132
|
+
#
|
133
|
+
def close(end_time = Time.now)
|
134
|
+
unless end_time.is_a?(Time)
|
135
|
+
::Instana.logger.debug "span.close: Passed #{end_time.class} instead of Time class"
|
136
|
+
end
|
137
|
+
|
138
|
+
@data[:d] = (::Instana::Util.time_to_ms(end_time) - @data[:ts])
|
139
|
+
self
|
140
|
+
end
|
141
|
+
|
142
|
+
#############################################################
|
143
|
+
# Accessors
|
144
|
+
#############################################################
|
145
|
+
|
146
|
+
# Retrieve the context of this span.
|
147
|
+
#
|
148
|
+
# @return [Instana::SpanContext]
|
149
|
+
#
|
150
|
+
def context
|
151
|
+
@context ||= ::Instana::SpanContext.new(@data[:t], @data[:s], @baggage)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Retrieve the ID for this span
|
155
|
+
#
|
156
|
+
# @return [Integer] the span ID
|
9
157
|
def id
|
10
158
|
@data[:s]
|
11
159
|
end
|
12
160
|
|
161
|
+
# Retrieve the Trace ID for this span
|
162
|
+
#
|
163
|
+
# @return [Integer] the Trace ID
|
164
|
+
def trace_id
|
165
|
+
@data[:t]
|
166
|
+
end
|
167
|
+
|
168
|
+
# Retrieve the parent ID of this span
|
169
|
+
#
|
170
|
+
# @return [Integer] parent span ID
|
13
171
|
def parent_id
|
14
172
|
@data[:p]
|
15
173
|
end
|
16
174
|
|
175
|
+
# Set the parent ID of this span
|
176
|
+
#
|
177
|
+
# @return [Integer] parent span ID
|
178
|
+
def parent_id=(id)
|
179
|
+
@data[:p] = id
|
180
|
+
end
|
181
|
+
|
182
|
+
# Get the name (operation) of this Span
|
183
|
+
#
|
184
|
+
# @return [String] or [Symbol] representing the span name
|
17
185
|
def name
|
18
186
|
if custom?
|
19
187
|
@data[:data][:sdk][:name]
|
@@ -22,32 +190,184 @@ module Instana
|
|
22
190
|
end
|
23
191
|
end
|
24
192
|
|
193
|
+
# Set the name (operation) for this Span
|
194
|
+
#
|
195
|
+
# @params name [String] or [Symbol]
|
196
|
+
#
|
197
|
+
def name=(n)
|
198
|
+
if custom?
|
199
|
+
@data[:data][:sdk][:name] = n
|
200
|
+
else
|
201
|
+
@data[:n] = n
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Get the duration value for this Span
|
206
|
+
#
|
207
|
+
# @return [Integer] the duration in milliseconds
|
25
208
|
def duration
|
26
209
|
@data[:d]
|
27
210
|
end
|
28
211
|
|
212
|
+
# Indicates whether this span in the root span
|
213
|
+
# in the Trace
|
214
|
+
#
|
215
|
+
# @return [Boolean]
|
216
|
+
#
|
29
217
|
def is_root?
|
30
218
|
@data[:s] == @data[:t]
|
31
219
|
end
|
32
220
|
|
221
|
+
# Hash accessor to the internal @data hash
|
222
|
+
#
|
33
223
|
def [](key)
|
34
224
|
@data[key.to_sym]
|
35
225
|
end
|
36
226
|
|
227
|
+
# Hash setter to the internal @data hash
|
228
|
+
#
|
37
229
|
def []=(key, value)
|
38
230
|
@data[key.to_sym] = value
|
39
231
|
end
|
40
232
|
|
233
|
+
# Hash key query to the internal @data hash
|
234
|
+
#
|
41
235
|
def key?(k)
|
42
236
|
@data.key?(k.to_sym)
|
43
237
|
end
|
44
238
|
|
239
|
+
# Get the raw @data hash that summarizes this span
|
240
|
+
#
|
45
241
|
def raw
|
46
242
|
@data
|
47
243
|
end
|
48
244
|
|
245
|
+
# Indicates whether this span is a custom or registered Span
|
49
246
|
def custom?
|
50
247
|
@data[:n] == :sdk
|
51
248
|
end
|
249
|
+
|
250
|
+
#############################################################
|
251
|
+
# OpenTracing Compatibility Methods
|
252
|
+
#############################################################
|
253
|
+
|
254
|
+
# Set the name of the operation
|
255
|
+
# Spec: OpenTracing API
|
256
|
+
#
|
257
|
+
# @params name [String] or [Symbol]
|
258
|
+
#
|
259
|
+
def operation_name=(name)
|
260
|
+
@data[:n] = name
|
261
|
+
end
|
262
|
+
|
263
|
+
# Set a tag value on this span
|
264
|
+
# Spec: OpenTracing API
|
265
|
+
#
|
266
|
+
# @param key [String] the key of the tag
|
267
|
+
# @param value [String, Numeric, Boolean] the value of the tag. If it's not
|
268
|
+
# a String, Numeric, or Boolean it will be encoded with to_s
|
269
|
+
#
|
270
|
+
def set_tag(key, value)
|
271
|
+
if custom?
|
272
|
+
@data[:data][:sdk][:custom] ||= {}
|
273
|
+
@data[:data][:sdk][:custom][key] = value
|
274
|
+
else
|
275
|
+
if !@data[:data].key?(key)
|
276
|
+
@data[:data][key] = value
|
277
|
+
elsif value.is_a?(Hash) && self[:data][key].is_a?(Hash)
|
278
|
+
@data[:data][key].merge!(value)
|
279
|
+
else
|
280
|
+
@data[:data][key] = value
|
281
|
+
end
|
282
|
+
end
|
283
|
+
self
|
284
|
+
end
|
285
|
+
|
286
|
+
# Helper method to add multiple tags to this span
|
287
|
+
#
|
288
|
+
# @params tags [Hash]
|
289
|
+
# @return [Span]
|
290
|
+
#
|
291
|
+
def set_tags(tags)
|
292
|
+
return unless tags.is_a?(Hash)
|
293
|
+
tags.each do |k,v|
|
294
|
+
set_tag(k, v)
|
295
|
+
end
|
296
|
+
self
|
297
|
+
end
|
298
|
+
|
299
|
+
# Set a baggage item on the span
|
300
|
+
# Spec: OpenTracing API
|
301
|
+
#
|
302
|
+
# @param key [String] the key of the baggage item
|
303
|
+
# @param value [String] the value of the baggage item
|
304
|
+
def set_baggage_item(key, value)
|
305
|
+
@baggage ||= {}
|
306
|
+
@baggage[key] = value
|
307
|
+
|
308
|
+
# Init/Update the SpanContext item
|
309
|
+
if @context
|
310
|
+
@context.baggage = @baggage
|
311
|
+
else
|
312
|
+
@context ||= ::Instana::SpanContext.new(@data[:t], @data[:s], @baggage)
|
313
|
+
end
|
314
|
+
self
|
315
|
+
end
|
316
|
+
|
317
|
+
# Get a baggage item
|
318
|
+
# Spec: OpenTracing API
|
319
|
+
#
|
320
|
+
# @param key [String] the key of the baggage item
|
321
|
+
# @return Value of the baggage item
|
322
|
+
#
|
323
|
+
def get_baggage_item(key)
|
324
|
+
@baggage[key]
|
325
|
+
end
|
326
|
+
|
327
|
+
# Retrieve the hash of tags for this span
|
328
|
+
#
|
329
|
+
def tags(key = nil)
|
330
|
+
if custom?
|
331
|
+
tags = @data[:data][:sdk][:custom]
|
332
|
+
else
|
333
|
+
tags = @data[:data][key]
|
334
|
+
end
|
335
|
+
key ? tags[key] : tags
|
336
|
+
end
|
337
|
+
|
338
|
+
# Add a log entry to this span
|
339
|
+
# Spec: OpenTracing API
|
340
|
+
#
|
341
|
+
# @param event [String] event name for the log
|
342
|
+
# @param timestamp [Time] time of the log
|
343
|
+
# @param fields [Hash] Additional information to log
|
344
|
+
#
|
345
|
+
def log(event = nil, _timestamp = Time.now, **fields)
|
346
|
+
set_tags(:log => { :message => event, :parameters => fields })
|
347
|
+
end
|
348
|
+
|
349
|
+
# Finish the {Span}
|
350
|
+
# Spec: OpenTracing API
|
351
|
+
#
|
352
|
+
# @param end_time [Time] custom end time, if not now
|
353
|
+
#
|
354
|
+
def finish(end_time = Time.now)
|
355
|
+
unless end_time.is_a?(Time)
|
356
|
+
::Instana.logger.debug "span.finish: Passed #{end_time.class} instead of Time class"
|
357
|
+
end
|
358
|
+
|
359
|
+
if ::Instana.tracer.current_span.id != id
|
360
|
+
::Instana.logger.tracing "Closing a span that isn't active. This will result in a broken trace: #{self.inspect}"
|
361
|
+
end
|
362
|
+
|
363
|
+
if is_root?
|
364
|
+
# This is the root span for the trace. Call log_end to close
|
365
|
+
# out and queue the trace
|
366
|
+
::Instana.tracer.log_end(name, {}, end_time)
|
367
|
+
else
|
368
|
+
::Instana.tracer.current_trace.end_span({}, end_time)
|
369
|
+
end
|
370
|
+
self
|
371
|
+
end
|
52
372
|
end
|
53
373
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Instana
|
2
|
+
class SpanContext
|
3
|
+
attr_accessor :trace_id
|
4
|
+
attr_accessor :span_id
|
5
|
+
attr_accessor :baggage
|
6
|
+
|
7
|
+
# Create a new SpanContext
|
8
|
+
#
|
9
|
+
# @param tid [Integer] the trace ID
|
10
|
+
# @param sid [Integer] the span ID
|
11
|
+
# @param baggage [Hash] baggage applied to this trace
|
12
|
+
#
|
13
|
+
def initialize(tid, sid, baggage = nil)
|
14
|
+
@trace_id = tid
|
15
|
+
@span_id = sid
|
16
|
+
@baggage = baggage
|
17
|
+
end
|
18
|
+
|
19
|
+
def trace_id_header
|
20
|
+
::Instana::Util.id_to_header(@trace_id)
|
21
|
+
end
|
22
|
+
|
23
|
+
def span_id_header
|
24
|
+
::Instana::Util.id_to_header(@span_id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_hash
|
28
|
+
{ :trace_id => @trace_id, :span_id => @span_id }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,10 +1,5 @@
|
|
1
1
|
module Instana
|
2
2
|
class Trace
|
3
|
-
REGISTERED_SPANS = [ :rack, :'net-http', :excon ].freeze
|
4
|
-
ENTRY_SPANS = [ :rack ].freeze
|
5
|
-
EXIT_SPANS = [ :'net-http', :excon ].freeze
|
6
|
-
HTTP_SPANS = ENTRY_SPANS + EXIT_SPANS
|
7
|
-
|
8
3
|
# @return [Integer] the ID for this trace
|
9
4
|
attr_reader :id
|
10
5
|
|
@@ -22,13 +17,13 @@ module Instana
|
|
22
17
|
# :span_id the ID of the parent span (must be an unsigned hex-string)
|
23
18
|
# :level specifies data collection level (optional)
|
24
19
|
#
|
25
|
-
def initialize(name, kvs =
|
20
|
+
def initialize(name, kvs = nil, incoming_context = {}, start_time = Time.now)
|
26
21
|
# The collection of spans that make
|
27
22
|
# up this trace.
|
28
23
|
@spans = Set.new
|
29
24
|
|
30
25
|
# Generate a random 64bit ID for this trace
|
31
|
-
@id = generate_id
|
26
|
+
@id = ::Instana::Util.generate_id
|
32
27
|
|
33
28
|
# Indicates the time when this trace was started. Used to timeout
|
34
29
|
# traces that have asynchronous spans that never close out.
|
@@ -39,29 +34,14 @@ module Instana
|
|
39
34
|
|
40
35
|
# This is a new trace so open the first span with the proper
|
41
36
|
# root span IDs.
|
42
|
-
@current_span = Span.new(
|
43
|
-
|
44
|
-
:ts => ts_now, # Timestamp
|
45
|
-
:ta => :ruby, # Agent
|
46
|
-
:f => { :e => ::Instana.agent.report_pid, :h => ::Instana.agent.agent_uuid } # Entity Source
|
47
|
-
})
|
48
|
-
|
49
|
-
# For entry spans, add a backtrace fingerprint
|
50
|
-
add_stack(2) if ENTRY_SPANS.include?(name)
|
51
|
-
|
52
|
-
# Check for custom tracing
|
53
|
-
if !REGISTERED_SPANS.include?(name.to_sym)
|
54
|
-
configure_custom_span(nil, name, kvs)
|
55
|
-
else
|
56
|
-
@current_span[:n] = name.to_sym
|
57
|
-
@current_span[:data] = kvs
|
58
|
-
end
|
37
|
+
@current_span = Span.new(name, @id, start_time: start_time)
|
38
|
+
@current_span.set_tags(kvs) if kvs
|
59
39
|
|
60
40
|
# Handle potential incoming context
|
61
|
-
if incoming_context.empty?
|
41
|
+
if !incoming_context || incoming_context.empty?
|
62
42
|
# No incoming context. Set trace ID the same
|
63
43
|
# as this first span.
|
64
|
-
@current_span[:
|
44
|
+
@current_span[:s] = @id
|
65
45
|
else
|
66
46
|
@id = incoming_context[:trace_id]
|
67
47
|
@current_span[:t] = incoming_context[:trace_id]
|
@@ -76,32 +56,22 @@ module Instana
|
|
76
56
|
# @param name [String] the name of the span to start
|
77
57
|
# @param kvs [Hash] list of key values to be reported in the span
|
78
58
|
#
|
79
|
-
def new_span(name, kvs =
|
59
|
+
def new_span(name, kvs = nil, start_time = Time.now, child_of = nil)
|
80
60
|
return unless @current_span
|
81
61
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
:ts => ts_now, # Timestamp
|
87
|
-
:ta => :ruby, # Agent
|
88
|
-
:f => { :e => Process.pid, :h => :agent_id } # Entity Source
|
89
|
-
})
|
90
|
-
|
91
|
-
new_span.parent = @current_span
|
92
|
-
@spans.add(new_span)
|
93
|
-
@current_span = new_span
|
94
|
-
|
95
|
-
# Check for custom tracing
|
96
|
-
if !REGISTERED_SPANS.include?(name.to_sym)
|
97
|
-
configure_custom_span(nil, name, kvs)
|
62
|
+
if child_of && child_of.is_a?(::Instana::Span)
|
63
|
+
new_span = Span.new(name, @id, parent_id: child_of.id, start_time: start_time)
|
64
|
+
new_span.parent = child_of
|
65
|
+
new_span.baggage = child_of.baggage.dup
|
98
66
|
else
|
99
|
-
@current_span
|
100
|
-
|
67
|
+
new_span = Span.new(name, @id, parent_id: @current_span.id, start_time: start_time)
|
68
|
+
new_span.parent = @current_span
|
69
|
+
new_span.baggage = @current_span.baggage.dup
|
101
70
|
end
|
71
|
+
new_span.set_tags(kvs) if kvs
|
102
72
|
|
103
|
-
|
104
|
-
|
73
|
+
@spans.add(new_span)
|
74
|
+
@current_span = new_span
|
105
75
|
end
|
106
76
|
|
107
77
|
# Add KVs to the current span
|
@@ -139,33 +109,8 @@ module Instana
|
|
139
109
|
# Return if we've already logged this exception and it
|
140
110
|
# is just propogating up the spans.
|
141
111
|
return if e && e.instance_variable_get(:@instana_logged)
|
142
|
-
|
143
112
|
span ||= @current_span
|
144
|
-
|
145
|
-
span[:error] = true
|
146
|
-
|
147
|
-
if span.key?(:ec)
|
148
|
-
span[:ec] = span[:ec] + 1
|
149
|
-
else
|
150
|
-
span[:ec] = 1
|
151
|
-
end
|
152
|
-
|
153
|
-
# If a valid exception has been passed in, log the information about it
|
154
|
-
# In case of just logging an error for things such as HTTP client 5xx
|
155
|
-
# responses, an exception/backtrace may not exist.
|
156
|
-
if e
|
157
|
-
if e.backtrace.is_a?(Array)
|
158
|
-
add_backtrace_to_span(e.backtrace, nil, span)
|
159
|
-
end
|
160
|
-
|
161
|
-
if HTTP_SPANS.include?(span.name)
|
162
|
-
add_info(:http => { :error => "#{e.class}: #{e.message}" })
|
163
|
-
else
|
164
|
-
add_info(:log => { :message => e.message, :parameters => e.class })
|
165
|
-
end
|
166
|
-
e.instance_variable_set(:@instana_logged, true)
|
167
|
-
end
|
168
|
-
|
113
|
+
span.add_error(e)
|
169
114
|
end
|
170
115
|
|
171
116
|
# Close out the current span and set the parent as
|
@@ -173,20 +118,20 @@ module Instana
|
|
173
118
|
#
|
174
119
|
# @param kvs [Hash] list of key values to be reported in the span
|
175
120
|
#
|
176
|
-
def end_span(kvs = {})
|
177
|
-
@current_span
|
121
|
+
def end_span(kvs = {}, end_time = Time.now)
|
122
|
+
@current_span.close(end_time)
|
178
123
|
add_info(kvs) if kvs && !kvs.empty?
|
179
124
|
@current_span = @current_span.parent unless @current_span.is_root?
|
180
125
|
end
|
181
126
|
|
182
127
|
# Closes out the final span in this trace and runs any finalizer
|
183
128
|
# steps required.
|
184
|
-
# This should be called only on the root span to end the trace.
|
129
|
+
# This should be called only when on the root span to end the trace.
|
185
130
|
#
|
186
131
|
# @param kvs [Hash] list of key values to be reported in the span
|
187
132
|
#
|
188
|
-
def finish(kvs = {})
|
189
|
-
end_span(kvs)
|
133
|
+
def finish(kvs = {}, end_time = Time.now)
|
134
|
+
end_span(kvs, end_time)
|
190
135
|
end
|
191
136
|
|
192
137
|
###########################################################################
|
@@ -202,77 +147,47 @@ module Instana
|
|
202
147
|
# @param name [String] the name of the span to start
|
203
148
|
# @param kvs [Hash] list of key values to be reported in the span
|
204
149
|
#
|
205
|
-
def new_async_span(name, kvs)
|
206
|
-
|
207
|
-
new_span
|
208
|
-
:s => generate_id, # Span ID
|
209
|
-
:t => @id, # Trace ID (same as :s for root span)
|
210
|
-
:p => @current_span.id, # Parent ID
|
211
|
-
:ts => ts_now, # Timestamp
|
212
|
-
:ta => :ruby, # Agent
|
213
|
-
:async => true, # Asynchonous
|
214
|
-
:f => { :e => Process.pid, :h => :agent_id } # Entity Source
|
215
|
-
})
|
216
|
-
|
150
|
+
def new_async_span(name, kvs = {})
|
151
|
+
new_span = Span.new(name, @id, parent_id: @current_span.id)
|
152
|
+
new_span.set_tags(kvs) unless kvs.empty?
|
217
153
|
new_span.parent = @current_span
|
218
|
-
@has_async = true
|
219
|
-
|
220
|
-
# Check for custom tracing
|
221
|
-
if !REGISTERED_SPANS.include?(name.to_sym)
|
222
|
-
configure_custom_span(new_span, name, kvs)
|
223
|
-
else
|
224
|
-
new_span[:n] = name.to_sym
|
225
|
-
new_span[:data] = kvs
|
226
|
-
end
|
227
|
-
|
228
|
-
# Attach a backtrace to all exit spans
|
229
|
-
add_stack(nil, new_span) if EXIT_SPANS.include?(name)
|
154
|
+
new_span[:async] = @has_async = true
|
230
155
|
|
231
156
|
# Add the new span to the span collection
|
232
157
|
@spans.add(new_span)
|
233
|
-
|
234
|
-
{ :trace_id => new_span[:t], :span_id => new_span.id }
|
158
|
+
new_span
|
235
159
|
end
|
236
160
|
|
237
161
|
# Log info into an asynchronous span
|
238
162
|
#
|
239
163
|
# @param kvs [Hash] list of key values to be reported in the span
|
240
|
-
# @param span [Span] the span
|
164
|
+
# @param span [Span] the span of this Async op (previously returned
|
165
|
+
# from `log_async_entry`)
|
241
166
|
#
|
242
|
-
def add_async_info(kvs,
|
243
|
-
|
244
|
-
if span.id == ids[:span_id]
|
245
|
-
add_info(kvs, span)
|
246
|
-
end
|
247
|
-
end
|
167
|
+
def add_async_info(kvs, span)
|
168
|
+
span.set_tags(kvs)
|
248
169
|
end
|
249
170
|
|
250
171
|
# Log an error into an asynchronous span
|
251
172
|
#
|
252
|
-
# @param span [Span] the span to configure
|
253
173
|
# @param e [Exception] Add exception to the current span
|
174
|
+
# @param span [Span] the span of this Async op (previously returned
|
175
|
+
# from `log_async_entry`)
|
254
176
|
#
|
255
|
-
def add_async_error(e,
|
256
|
-
|
257
|
-
add_error(e, span) if span.id == ids[:span_id]
|
258
|
-
end
|
177
|
+
def add_async_error(e, span)
|
178
|
+
span.add_error(e)
|
259
179
|
end
|
260
180
|
|
261
181
|
# End an asynchronous span
|
262
182
|
#
|
263
183
|
# @param name [Symbol] the name of the span
|
264
184
|
# @param kvs [Hash] list of key values to be reported in the span
|
265
|
-
# @param
|
266
|
-
#
|
267
|
-
# :span_id => 12345
|
185
|
+
# @param span [Span] the span of this Async op (previously returned
|
186
|
+
# from `log_async_entry`)
|
268
187
|
#
|
269
|
-
def end_async_span(kvs = {},
|
270
|
-
|
271
|
-
|
272
|
-
span[:d] = ts_now - span[:ts]
|
273
|
-
add_info(kvs, span) unless kvs.empty?
|
274
|
-
end
|
275
|
-
end
|
188
|
+
def end_async_span(kvs = {}, span)
|
189
|
+
span.set_tags(kvs) unless kvs.empty?
|
190
|
+
span.close
|
276
191
|
end
|
277
192
|
|
278
193
|
###########################################################################
|
@@ -290,6 +205,7 @@ module Instana
|
|
290
205
|
return false
|
291
206
|
end
|
292
207
|
end
|
208
|
+
true
|
293
209
|
end
|
294
210
|
|
295
211
|
# Indicates if every span of this trace has completed. Useful when
|
@@ -327,6 +243,14 @@ module Instana
|
|
327
243
|
false
|
328
244
|
end
|
329
245
|
|
246
|
+
# Get the current span.
|
247
|
+
#
|
248
|
+
# @return [Span]
|
249
|
+
#
|
250
|
+
def current_span
|
251
|
+
@current_span
|
252
|
+
end
|
253
|
+
|
330
254
|
# Get the ID of the current span for this trace.
|
331
255
|
# Used often to place in HTTP response headers.
|
332
256
|
#
|
@@ -379,53 +303,7 @@ module Instana
|
|
379
303
|
#
|
380
304
|
def configure_custom_span(span, name, kvs = {})
|
381
305
|
span ||= @current_span
|
382
|
-
|
383
|
-
span[:n] = :sdk
|
384
|
-
span[:data] = { :sdk => { :name => name.to_sym } }
|
385
|
-
span[:data][:sdk][:type] = kvs.key?(:type) ? kvs[:type] : :local
|
386
|
-
|
387
|
-
if kvs.key?(:arguments)
|
388
|
-
span[:data][:sdk][:arguments] = kvs[:arguments]
|
389
|
-
end
|
390
|
-
|
391
|
-
if kvs.key?(:return)
|
392
|
-
span[:data][:sdk][:return] = kvs[:return]
|
393
|
-
end
|
394
|
-
span[:data][:sdk][:custom] = kvs unless kvs.empty?
|
395
|
-
#span[:data][:sdk][:custom][:tags] = {}
|
396
|
-
#span[:data][:sdk][:custom][:logs] = {}
|
397
|
-
end
|
398
|
-
|
399
|
-
# Locates the span in the current_trace or
|
400
|
-
# in the staging queue. This is generally used by async
|
401
|
-
# operations.
|
402
|
-
#
|
403
|
-
# @param ids [Hash] the Trace ID and Span ID in the form of
|
404
|
-
# :trace_id => 12345
|
405
|
-
# :span_id => 12345
|
406
|
-
#
|
407
|
-
# @return [Span]
|
408
|
-
#
|
409
|
-
def find_span(ids)
|
410
|
-
if ids[:trace_id] == @id
|
411
|
-
@spans.each do |s|
|
412
|
-
return s if s[:s] == ids[:span_id]
|
413
|
-
end
|
414
|
-
else
|
415
|
-
#::Instana.processor.staged_trace(
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
# Adds a backtrace to the passed in span or on @current_span if not.
|
420
|
-
#
|
421
|
-
# @param limit [Integer] Limit the backtrace to the top <limit> frames
|
422
|
-
# @param span [Span] the span to add the backtrace to or if unspecified
|
423
|
-
# the current span
|
424
|
-
#
|
425
|
-
def add_stack(limit = nil, span = nil)
|
426
|
-
span ||= @current_span
|
427
|
-
|
428
|
-
add_backtrace_to_span(Kernel.caller, limit, span)
|
306
|
+
span.configure_custom(name, kvs)
|
429
307
|
end
|
430
308
|
|
431
309
|
# Adds the passed in backtrace to the specified span. Backtrace can be one
|
@@ -459,22 +337,5 @@ module Instana
|
|
459
337
|
end
|
460
338
|
end
|
461
339
|
end
|
462
|
-
|
463
|
-
# Get the current time in milliseconds
|
464
|
-
#
|
465
|
-
# @return [Integer] the current time in milliseconds
|
466
|
-
#
|
467
|
-
def ts_now
|
468
|
-
(Time.now.to_f * 1000).floor
|
469
|
-
end
|
470
|
-
|
471
|
-
# Generate a random 64bit ID
|
472
|
-
#
|
473
|
-
# @return [Integer] a random 64bit integer
|
474
|
-
#
|
475
|
-
def generate_id
|
476
|
-
# Max value is 9223372036854775807 (signed long in Java)
|
477
|
-
rand(-2**63..2**63-1)
|
478
|
-
end
|
479
340
|
end
|
480
341
|
end
|