instana 0.15.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![instana console output](https://s3.amazonaws.com/instana/Instana+Ruby+boot+console+logging+output.png)
|
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
|
+
![rails console](https://s3.amazonaws.com/instana/Instana+Ruby+Rails+console+output.png)
|
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
|