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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b08a1d3bea72c56da148e02e24c9095a49d4c0f6
4
- data.tar.gz: efcbc529c115a5dba077b4e590528b32c98698ba
3
+ metadata.gz: cbc400b87081fe4c927cb2f437faf8597ac217bf
4
+ data.tar.gz: 247eb9b4db84239ebbf7ec934c5427f94a5b1771
5
5
  SHA512:
6
- metadata.gz: 72c20b92c83aa59a7e0b21c5eb9127e696f782ddd7b077294adf9185469629e0f7922027e881dd52c717f1ac3c64929ffc04e1bcef2eb2893e59f94ddd2e0e67
7
- data.tar.gz: 9d9cd6654f148a0142faeeab2ef9875bdfa2f9d31db700859a1c44e3d3f195c364c99fbc9a0f33342ce8ea4f07c9caf71cb1a63c7100e90f924f471d345cf154
6
+ metadata.gz: 9299e4b9ed9aaeabd40dd6c5df7f21b8a76e849b083a152e133b9d8f10e2e8c2787bc711cf5cae75ee9d9f4f2f624a8418bac1b38cf275ab1c1ad46045ccb42a
7
+ data.tar.gz: 38ea273e84533d1a9be4e3373a0962a44fa3bf8b96c8aa4937f466b77062995b168630bf146d79d8c21f0680beb26ead6ff0ae90b06c235f3f3f19cb6789e27c
@@ -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`.
@@ -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
- datum[:headers]['X-Instana-T'] = ::Instana.tracer.trace_id_header
23
- datum[:headers]['X-Instana-S'] = ::Instana.tracer.span_id_header
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
- request['X-Instana-T'] = ::Instana.tracer.trace_id_header
17
- request['X-Instana-S'] = ::Instana.tracer.span_id_header
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.tracer.header_to_id(env['HTTP_X_INSTANA_T'])
22
- incoming_context[:span_id] = ::Instana.tracer.header_to_id(env['HTTP_X_INSTANA_S']) if env.key?('HTTP_X_INSTANA_S')
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.tracer.id_to_header(trace_id)
53
- headers['X-Instana-S'] = ::Instana.tracer.id_to_header(span_id)
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
@@ -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 agent_response(msg)
61
- return unless @level_agent_response
66
+ def tracing(msg)
67
+ return unless @level_tracing
62
68
  self.debug(msg)
63
69
  end
64
70
 
@@ -0,0 +1,4 @@
1
+ module OpenTracing
2
+ class Carrier < Hash
3
+ end
4
+ end
@@ -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
@@ -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.
@@ -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, incoming_context = nil)
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 t_context [Hash] the Trace ID and Span ID in the form of
168
- # :trace_id => 12345
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, ids)
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 == ids[:trace_id]
178
- self.current_trace.add_async_info(kvs, ids)
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(ids)
181
- trace.add_async_info(kvs, ids)
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 ids [Hash] the Trace ID and Span ID in the form of
189
- # :trace_id => 12345
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, ids)
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 == ids[:trace_id]
198
- self.current_trace.add_async_error(e, ids)
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(ids)
201
- trace.add_async_error(e, ids)
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 ids [Hash] the Trace ID and Span ID in the form of
210
- # :trace_id => 12345
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, ids)
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? && (self.current_trace.id == ids[:trace_id])
219
- self.current_trace.end_async_span(kvs, ids)
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(ids)
220
+ trace = ::Instana.processor.staged_trace(span.context.trace_id)
224
221
  if trace
225
- trace.end_async_span(kvs, ids)
222
+ trace.end_async_span(kvs, span)
226
223
  else
227
- ::Instana.logger.debug "log_async_exit: Couldn't find staged trace. #{ids.inspect}"
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