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 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