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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbc400b87081fe4c927cb2f437faf8597ac217bf
|
4
|
+
data.tar.gz: 247eb9b4db84239ebbf7ec934c5427f94a5b1771
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9299e4b9ed9aaeabd40dd6c5df7f21b8a76e849b083a152e133b9d8f10e2e8c2787bc711cf5cae75ee9d9f4f2f624a8418bac1b38cf275ab1c1ad46045ccb42a
|
7
|
+
data.tar.gz: 38ea273e84533d1a9be4e3373a0962a44fa3bf8b96c8aa4937f466b77062995b168630bf146d79d8c21f0680beb26ead6ff0ae90b06c235f3f3f19cb6789e27c
|
data/Troubleshooting.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Troubleshooting
|
2
|
+
|
3
|
+
The Instana gem has been designed to be fully automatic in process metric reporting and trace reporting. But if something
|
4
|
+
goes wrong, you can use the following steps and tips to potentially diagnose any issues that may exist.
|
5
|
+
|
6
|
+
# Supported Components
|
7
|
+
|
8
|
+
Make sure that the component that you want to get visibility into has been added to the support matrix. A list of all
|
9
|
+
supported components can be found in the [documentation](https://instana.atlassian.net/wiki/display/DOCS/Ruby).
|
10
|
+
|
11
|
+
# Logging & Environment Variables
|
12
|
+
|
13
|
+
By default, the gem will log informational messages on boot that will indicate if any problems were encountered. If you
|
14
|
+
set the `INSTANA_GEM_DEV` environment variable, it will increase the amount of logging output.
|
15
|
+
|
16
|
+

|
17
|
+
|
18
|
+
In the example above, you can see that the host agent isn't available. Once the host agent is available, the Instana
|
19
|
+
gem will automatically re-connect without any intervention.
|
20
|
+
|
21
|
+
There are even more methods to control logging output. See the [Configuration](https://github.com/instana/ruby-sensor/blob/master/Configuration.md#logging)
|
22
|
+
document for details.
|
23
|
+
|
24
|
+
# Testing in your Application
|
25
|
+
|
26
|
+
To diagnose the Instana gem from your application, often simply opening an application console with verbose logging can be
|
27
|
+
enough to identify any potential issues:
|
28
|
+
|
29
|
+

|
30
|
+
|
31
|
+
In the example above, you can see the Instana Ruby gem initialize, instrument some components and a success notification: `Host agent available. We're
|
32
|
+
in business`.
|
data/lib/instana/agent.rb
CHANGED
@@ -215,7 +215,7 @@ module Instana
|
|
215
215
|
response = make_host_agent_request(req)
|
216
216
|
|
217
217
|
if response
|
218
|
-
if response.body.length > 2
|
218
|
+
if response.body && response.body.length > 2
|
219
219
|
# The host agent returned something indicating that is has a request for us that we
|
220
220
|
# need to process.
|
221
221
|
handle_response(response.body)
|
@@ -19,8 +19,9 @@ if defined?(::Excon) && ::Instana.config[:excon][:enabled]
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# Set request headers; encode IDs as hexadecimal strings
|
22
|
-
|
23
|
-
datum[:headers]['X-Instana-
|
22
|
+
t_context = ::Instana.tracer.context
|
23
|
+
datum[:headers]['X-Instana-T'] = t_context.trace_id_header
|
24
|
+
datum[:headers]['X-Instana-S'] = t_context.span_id_header
|
24
25
|
|
25
26
|
@stack.request_call(datum)
|
26
27
|
end
|
@@ -13,8 +13,9 @@ Net::HTTP.class_eval {
|
|
13
13
|
request = args[0]
|
14
14
|
|
15
15
|
# Set request headers; encode IDs as hexadecimal strings
|
16
|
-
|
17
|
-
request['X-Instana-
|
16
|
+
t_context = ::Instana.tracer.context
|
17
|
+
request['X-Instana-T'] = t_context.trace_id_header
|
18
|
+
request['X-Instana-S'] = t_context.span_id_header
|
18
19
|
|
19
20
|
# Collect up KV info now in case any exception is raised
|
20
21
|
kv_payload = { :http => {} }
|
@@ -18,8 +18,8 @@ module Instana
|
|
18
18
|
# Check incoming context
|
19
19
|
incoming_context = {}
|
20
20
|
if env.key?('HTTP_X_INSTANA_T')
|
21
|
-
incoming_context[:trace_id] = ::Instana.
|
22
|
-
incoming_context[:span_id] = ::Instana.
|
21
|
+
incoming_context[:trace_id] = ::Instana::Util.header_to_id(env['HTTP_X_INSTANA_T'])
|
22
|
+
incoming_context[:span_id] = ::Instana::Util.header_to_id(env['HTTP_X_INSTANA_S']) if env.key?('HTTP_X_INSTANA_S')
|
23
23
|
incoming_context[:level] = env['HTTP_X_INSTANA_L'] if env.key?('HTTP_X_INSTANA_L')
|
24
24
|
end
|
25
25
|
|
@@ -49,8 +49,8 @@ module Instana
|
|
49
49
|
ensure
|
50
50
|
if headers && ::Instana.tracer.tracing?
|
51
51
|
# Set reponse headers; encode as hex string
|
52
|
-
headers['X-Instana-T'] = ::Instana.
|
53
|
-
headers['X-Instana-S'] = ::Instana.
|
52
|
+
headers['X-Instana-T'] = ::Instana::Util.id_to_header(trace_id)
|
53
|
+
headers['X-Instana-S'] = ::Instana::Util.id_to_header(span_id)
|
54
54
|
end
|
55
55
|
::Instana.tracer.log_end(:rack, kvs)
|
56
56
|
end
|
data/lib/instana/logger.rb
CHANGED
@@ -2,7 +2,7 @@ require "logger"
|
|
2
2
|
|
3
3
|
module Instana
|
4
4
|
class XLogger < Logger
|
5
|
-
LEVELS = [:agent, :agent_comm, :trace, :agent_response].freeze
|
5
|
+
LEVELS = [:agent, :agent_comm, :trace, :agent_response, :tracing].freeze
|
6
6
|
STAMP = "Instana: ".freeze
|
7
7
|
|
8
8
|
def initialize(*args)
|
@@ -22,8 +22,9 @@ module Instana
|
|
22
22
|
#
|
23
23
|
# :agent - All agent related messages such as state & announcements
|
24
24
|
# :agent_comm - Output all payload comm sent between this Ruby gem and the host agent
|
25
|
-
# :trace - Output all traces reported to the host agent
|
26
25
|
# :agent_response - Outputs messages related to handling requests received by the host agent
|
26
|
+
# :trace - Output all traces reported to the host agent
|
27
|
+
# :tracing - Output messages related to tracing components, spans and management
|
27
28
|
#
|
28
29
|
# To use:
|
29
30
|
# ::Instana.logger.debug_level = [:agent_comm, :trace]
|
@@ -52,13 +53,18 @@ module Instana
|
|
52
53
|
self.debug(msg)
|
53
54
|
end
|
54
55
|
|
56
|
+
def agent_response(msg)
|
57
|
+
return unless @level_agent_response
|
58
|
+
self.debug(msg)
|
59
|
+
end
|
60
|
+
|
55
61
|
def trace(msg)
|
56
62
|
return unless @level_trace
|
57
63
|
self.debug(msg)
|
58
64
|
end
|
59
65
|
|
60
|
-
def
|
61
|
-
return unless @
|
66
|
+
def tracing(msg)
|
67
|
+
return unless @level_tracing
|
62
68
|
self.debug(msg)
|
63
69
|
end
|
64
70
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module OpenTracing
|
2
|
+
class << self
|
3
|
+
# Text format for #inject and #extract
|
4
|
+
FORMAT_TEXT_MAP = 1
|
5
|
+
|
6
|
+
# Binary format for #inject and #extract
|
7
|
+
FORMAT_BINARY = 2
|
8
|
+
|
9
|
+
# Ruby Specific format to handle how Rack changes environment variables.
|
10
|
+
FORMAT_RACK = 3
|
11
|
+
|
12
|
+
attr_accessor :global_tracer
|
13
|
+
|
14
|
+
def method_missing(method_name, *args, &block)
|
15
|
+
@global_tracer.send(method_name, *args, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/instana/setup.rb
CHANGED
@@ -11,6 +11,9 @@ require "instana/instrumentation"
|
|
11
11
|
|
12
12
|
::Instana.agent.setup
|
13
13
|
|
14
|
+
# Require supported OpenTracing interfaces
|
15
|
+
require "opentracing"
|
16
|
+
|
14
17
|
# The Instana agent is now setup. The only remaining
|
15
18
|
# task for a complete boot is to call
|
16
19
|
# `Instana.agent.start` in the thread of your choice.
|
data/lib/instana/tracer.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "instana/thread_local"
|
2
2
|
require "instana/tracing/trace"
|
3
3
|
require "instana/tracing/span"
|
4
|
+
require "instana/tracing/span_context"
|
4
5
|
|
5
6
|
module Instana
|
6
7
|
class Tracer
|
@@ -126,10 +127,10 @@ module Instana
|
|
126
127
|
# @param name [String] the name of the span to end
|
127
128
|
# @param kvs [Hash] list of key values to be reported in the span
|
128
129
|
#
|
129
|
-
def log_end(name, kvs = {})
|
130
|
+
def log_end(name, kvs = {}, end_time = Time.now)
|
130
131
|
return unless tracing?
|
131
132
|
|
132
|
-
self.current_trace.finish(kvs)
|
133
|
+
self.current_trace.finish(kvs, end_time)
|
133
134
|
|
134
135
|
if !self.current_trace.has_async? ||
|
135
136
|
(self.current_trace.has_async? && self.current_trace.complete?)
|
@@ -156,7 +157,7 @@ module Instana
|
|
156
157
|
# :trace_id => 12345
|
157
158
|
# :span_id => 12345
|
158
159
|
#
|
159
|
-
def log_async_entry(name, kvs
|
160
|
+
def log_async_entry(name, kvs)
|
160
161
|
return unless tracing?
|
161
162
|
self.current_trace.new_async_span(name, kvs)
|
162
163
|
end
|
@@ -164,41 +165,38 @@ module Instana
|
|
164
165
|
# Add info to an asynchronous span
|
165
166
|
#
|
166
167
|
# @param kvs [Hash] list of key values to be reported in the span
|
167
|
-
# @param
|
168
|
-
#
|
169
|
-
# :span_id => 12345
|
170
|
-
# This can be retrieved by using ::Instana.tracer.context
|
168
|
+
# @param span [Span] the span for this Async op (previously returned
|
169
|
+
# from `log_async_entry`)
|
171
170
|
#
|
172
|
-
def log_async_info(kvs,
|
171
|
+
def log_async_info(kvs, span)
|
173
172
|
# Asynchronous spans can persist longer than the parent
|
174
173
|
# trace. With the trace ID, we check the current trace
|
175
174
|
# but otherwise, we search staged traces.
|
176
175
|
|
177
|
-
if tracing? && self.current_trace.id ==
|
178
|
-
self.current_trace.add_async_info(kvs,
|
176
|
+
if tracing? && self.current_trace.id == span.context.trace_id
|
177
|
+
self.current_trace.add_async_info(kvs, span)
|
179
178
|
else
|
180
|
-
trace = ::Instana.processor.staged_trace(
|
181
|
-
trace.add_async_info(kvs,
|
179
|
+
trace = ::Instana.processor.staged_trace(span.context.trace_id)
|
180
|
+
trace.add_async_info(kvs, span)
|
182
181
|
end
|
183
182
|
end
|
184
183
|
|
185
184
|
# Add an error to an asynchronous span
|
186
185
|
#
|
187
186
|
# @param e [Exception] Add exception to the current span
|
188
|
-
# @param
|
189
|
-
#
|
190
|
-
# :span_id => 12345
|
187
|
+
# @param span [Span] the span for this Async op (previously returned
|
188
|
+
# from `log_async_entry`)
|
191
189
|
#
|
192
|
-
def log_async_error(e,
|
190
|
+
def log_async_error(e, span)
|
193
191
|
# Asynchronous spans can persist longer than the parent
|
194
192
|
# trace. With the trace ID, we check the current trace
|
195
193
|
# but otherwise, we search staged traces.
|
196
194
|
|
197
|
-
if tracing? && self.current_trace.id ==
|
198
|
-
self.current_trace.add_async_error(e,
|
195
|
+
if tracing? && self.current_trace.id == span.context.trace_id
|
196
|
+
self.current_trace.add_async_error(e, span)
|
199
197
|
else
|
200
|
-
trace = ::Instana.processor.staged_trace(
|
201
|
-
trace.add_async_error(e,
|
198
|
+
trace = ::Instana.processor.staged_trace(span.context.trace_id)
|
199
|
+
trace.add_async_error(e, span)
|
202
200
|
end
|
203
201
|
end
|
204
202
|
|
@@ -206,29 +204,92 @@ module Instana
|
|
206
204
|
#
|
207
205
|
# @param name [String] the name of the async span to exit (close out)
|
208
206
|
# @param kvs [Hash] list of key values to be reported in the span
|
209
|
-
# @param
|
210
|
-
#
|
211
|
-
# :span_id => 12345
|
207
|
+
# @param span [Span] the span for this Async op (previously returned
|
208
|
+
# from `log_async_entry`)
|
212
209
|
#
|
213
|
-
def log_async_exit(name, kvs,
|
210
|
+
def log_async_exit(name, kvs, span)
|
214
211
|
# An asynchronous span can end after the current trace has
|
215
212
|
# already completed so we make sure that we end the span
|
216
213
|
# on the right trace.
|
217
214
|
|
218
|
-
if tracing? &&
|
219
|
-
self.current_trace.end_async_span(kvs,
|
215
|
+
if tracing? && self.current_trace.id == span.context.trace_id
|
216
|
+
self.current_trace.end_async_span(kvs, span)
|
220
217
|
else
|
221
218
|
# Different trace from current so find the staged trace
|
222
219
|
# and close out the span on it.
|
223
|
-
trace = ::Instana.processor.staged_trace(
|
220
|
+
trace = ::Instana.processor.staged_trace(span.context.trace_id)
|
224
221
|
if trace
|
225
|
-
trace.end_async_span(kvs,
|
222
|
+
trace.end_async_span(kvs, span)
|
226
223
|
else
|
227
|
-
::Instana.logger.debug "log_async_exit: Couldn't find staged trace. #{
|
224
|
+
::Instana.logger.debug "log_async_exit: Couldn't find staged trace. #{span.inspect}"
|
228
225
|
end
|
229
226
|
end
|
230
227
|
end
|
231
228
|
|
229
|
+
###########################################################################
|
230
|
+
# OpenTracing Support
|
231
|
+
###########################################################################
|
232
|
+
|
233
|
+
# Start a new span
|
234
|
+
#
|
235
|
+
# @param operation_name [String] The name of the operation represented by the span
|
236
|
+
# @param child_of [Span] A span to be used as the ChildOf reference
|
237
|
+
# @param start_time [Time] the start time of the span
|
238
|
+
# @param tags [Hash] Starting tags for the span
|
239
|
+
#
|
240
|
+
# @return [Span]
|
241
|
+
#
|
242
|
+
def start_span(operation_name, child_of: nil, start_time: Time.now, tags: nil)
|
243
|
+
return unless ::Instana.agent.ready?
|
244
|
+
|
245
|
+
if tracing?
|
246
|
+
span = self.current_trace.new_span(operation_name, tags, start_time, child_of)
|
247
|
+
else
|
248
|
+
self.current_trace = ::Instana::Trace.new(operation_name, tags, nil, start_time)
|
249
|
+
span = self.current_trace.current_span
|
250
|
+
end
|
251
|
+
span.set_tags(tags)
|
252
|
+
span
|
253
|
+
end
|
254
|
+
|
255
|
+
# Inject a span into the given carrier
|
256
|
+
#
|
257
|
+
# @param span_context [SpanContext]
|
258
|
+
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
259
|
+
# @param carrier [Carrier]
|
260
|
+
#
|
261
|
+
def inject(span_context, format, carrier)
|
262
|
+
case format
|
263
|
+
when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY
|
264
|
+
::Instana.logger.debug 'Unsupported inject format'
|
265
|
+
when OpenTracing::FORMAT_RACK
|
266
|
+
carrier['X-Instana-T'] = ::Instana::Util.id_to_header(span_context.trace_id)
|
267
|
+
carrier['X-Instana-S'] = ::Instana::Util.id_to_header(span_context.span_id)
|
268
|
+
else
|
269
|
+
::Instana.logger.debug 'Unknown inject format'
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Extract a span from a carrier
|
274
|
+
#
|
275
|
+
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
276
|
+
# @param carrier [Carrier]
|
277
|
+
#
|
278
|
+
# @return [SpanContext]
|
279
|
+
#
|
280
|
+
def extract(format, carrier)
|
281
|
+
case format
|
282
|
+
when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY
|
283
|
+
::Instana.logger.debug 'Unsupported extract format'
|
284
|
+
when OpenTracing::FORMAT_RACK
|
285
|
+
::Instana::SpanContext.new(::Instana::Util.header_to_id(carrier['HTTP_X_INSTANA_T']),
|
286
|
+
::Instana::Util.header_to_id(carrier['HTTP_X_INSTANA_S']))
|
287
|
+
else
|
288
|
+
::Instana.logger.debug 'Unknown inject format'
|
289
|
+
nil
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
232
293
|
###########################################################################
|
233
294
|
# Helper methods
|
234
295
|
###########################################################################
|
@@ -248,11 +309,11 @@ module Instana
|
|
248
309
|
|
249
310
|
# Retrieve the current context of the tracer.
|
250
311
|
#
|
312
|
+
# @return [SpanContext] or nil if not tracing
|
313
|
+
#
|
251
314
|
def context
|
252
315
|
return nil unless tracing?
|
253
|
-
|
254
|
-
{ :trace_id => self.current_trace.id,
|
255
|
-
:span_id => self.current_trace.current_span_id }
|
316
|
+
self.current_trace.current_span.context
|
256
317
|
end
|
257
318
|
|
258
319
|
# Take the current trace_id and convert it to a header compatible
|
@@ -261,7 +322,7 @@ module Instana
|
|
261
322
|
# @return [String] a hexadecimal representation of the current trace ID
|
262
323
|
#
|
263
324
|
def trace_id_header
|
264
|
-
id_to_header(trace_id)
|
325
|
+
::Instana::Util.id_to_header(trace_id)
|
265
326
|
end
|
266
327
|
|
267
328
|
# Take the current span_id and convert it to a header compatible
|
@@ -270,41 +331,7 @@ module Instana
|
|
270
331
|
# @return [String] a hexadecimal representation of the current span ID
|
271
332
|
#
|
272
333
|
def span_id_header
|
273
|
-
id_to_header(span_id)
|
274
|
-
end
|
275
|
-
|
276
|
-
# Convert an ID to a value appropriate to pass in a header.
|
277
|
-
#
|
278
|
-
# @param id [Integer] the id to be converted
|
279
|
-
#
|
280
|
-
# @return [String]
|
281
|
-
#
|
282
|
-
def id_to_header(id)
|
283
|
-
unless id.is_a?(Integer) || id.is_a?(String)
|
284
|
-
Instana.logger.debug "id_to_header received a #{id.class}: returning empty string"
|
285
|
-
return String.new
|
286
|
-
end
|
287
|
-
[id.to_i].pack('q>').unpack('H*')[0]
|
288
|
-
rescue => e
|
289
|
-
Instana.logger.error "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
|
290
|
-
Instana.logger.debug e.backtrace.join("\r\n")
|
291
|
-
end
|
292
|
-
|
293
|
-
# Convert a received header value into a valid ID
|
294
|
-
#
|
295
|
-
# @param header_id [String] the header value to be converted
|
296
|
-
#
|
297
|
-
# @return [Integer]
|
298
|
-
#
|
299
|
-
def header_to_id(header_id)
|
300
|
-
if !header_id.is_a?(String)
|
301
|
-
Instana.logger.debug "header_to_id received a #{header_id.class}: returning 0"
|
302
|
-
return 0
|
303
|
-
end
|
304
|
-
[header_id].pack("H*").unpack("q>")[0]
|
305
|
-
rescue => e
|
306
|
-
Instana.logger.error "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
|
307
|
-
Instana.logger.debug e.backtrace.join("\r\n")
|
334
|
+
::Instana::Util.id_to_header(span_id)
|
308
335
|
end
|
309
336
|
|
310
337
|
# Returns the trace ID for the active trace (if there is one),
|
@@ -320,5 +347,17 @@ module Instana
|
|
320
347
|
def span_id
|
321
348
|
self.current_trace ? current_trace.current_span_id : nil
|
322
349
|
end
|
350
|
+
|
351
|
+
# Helper method to retrieve the currently active span for the active trace.
|
352
|
+
#
|
353
|
+
def current_span
|
354
|
+
self.current_trace ? self.current_trace.current_span : nil
|
355
|
+
end
|
356
|
+
|
357
|
+
# Used in the test suite, this resets the tracer to non-tracing state.
|
358
|
+
#
|
359
|
+
def clear!
|
360
|
+
self.current_trace = nil
|
361
|
+
end
|
323
362
|
end
|
324
363
|
end
|