Class: Instana::Tracer

Inherits:
Object
  • Object
show all
Extended by:
ThreadLocal
Defined in:
lib/instana/tracer.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ThreadLocal

thread_local

Class Method Details

.method_missing(method, *args, &block) ⇒ Object



13
14
15
16
17
18
19
# File 'lib/instana/tracer.rb', line 13

def method_missing(method, *args, &block)
  if ::Instana.tracer.respond_to?(method)
    ::Instana.tracer.send(method, *args, &block)
  else
    super
  end
end

Instance Method Details

#clear!Object

Used in the test suite, this resets the tracer to non-tracing state.



388
389
390
# File 'lib/instana/tracer.rb', line 388

def clear!
  self.current_span = nil
end

#contextSpanContext

Retrieve the current context of the tracer.

Returns:



339
340
341
342
# File 'lib/instana/tracer.rb', line 339

def context
  return unless self.current_span
  self.current_span.context
end

#extract(format, carrier) ⇒ SpanContext

Extract a span from a carrier



291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/instana/tracer.rb', line 291

def extract(format, carrier)
  case format
  when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY
    ::Instana.logger.debug 'Unsupported extract format'
  when OpenTracing::FORMAT_RACK
    ::Instana::SpanContext.new(::Instana::Util.header_to_id(carrier['HTTP_X_INSTANA_T']),
                                 ::Instana::Util.header_to_id(carrier['HTTP_X_INSTANA_S']))
  else
    ::Instana.logger.debug 'Unknown inject format'
    nil
  end
end

#inject(span_context, format, carrier) ⇒ Object

Inject a span into the given carrier

Parameters:



272
273
274
275
276
277
278
279
280
281
282
# File 'lib/instana/tracer.rb', line 272

def inject(span_context, format, carrier)
  case format
  when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY
    ::Instana.logger.debug 'Unsupported inject format'
  when OpenTracing::FORMAT_RACK
    carrier['X-Instana-T'] = ::Instana::Util.id_to_header(span_context.trace_id)
    carrier['X-Instana-S'] = ::Instana::Util.id_to_header(span_context.span_id)
  else
    ::Instana.logger.debug 'Unknown inject format'
  end
end

#log_async_entry(name, kvs) ⇒ Hash

Starts a new asynchronous span on the current trace.

Parameters:

  • name (String)

    the name of the span to create

  • kvs (Hash)

    list of key values to be reported in the span

Returns:

  • (Hash)

    the context: Trace ID and Span ID in the form of :trace_id => 12345 :span_id => 12345



206
207
208
209
210
211
212
# File 'lib/instana/tracer.rb', line 206

def log_async_entry(name, kvs)
  return unless self.current_span

  new_span = Span.new(name, parent_ctx: self.current_span)
  new_span.set_tags(kvs) unless kvs.empty?
  new_span
end

#log_async_error(e, span) ⇒ Object

Add an error to an asynchronous span

Parameters:

  • e (Exception)

    Add exception to the current span

  • span (Span)

    the span for this Async op (previously returned from ‘log_async_entry`)



228
229
230
# File 'lib/instana/tracer.rb', line 228

def log_async_error(e, span)
  span.add_error(e)
end

#log_async_exit(_name, kvs, span) ⇒ Object

Closes out an asynchronous span

Parameters:

  • name (String)

    the name of the async span to exit (close out)

  • kvs (Hash)

    list of additional key/values to be reported in the span (or use {})

  • span (Span)

    the span for this Async op (previously returned from ‘log_async_entry`)



238
239
240
241
# File 'lib/instana/tracer.rb', line 238

def log_async_exit(_name, kvs, span)
  span.set_tags(kvs) unless kvs.empty?
  span.close
end

#log_async_info(kvs, span) ⇒ Object

Add info to an asynchronous span

Parameters:

  • kvs (Hash)

    list of key values to be reported in the span

  • span (Span)

    the span for this Async op (previously returned from ‘log_async_entry`)



219
220
221
# File 'lib/instana/tracer.rb', line 219

def log_async_info(kvs, span)
  span.set_tags(kvs)
end

#log_end(name, kvs = {}, end_time = ::Instana::Util.now_in_ms) ⇒ Object

Note:

‘name` isn’t really required but helps keep sanity that

Closes out the current span in the current trace and queues the trace for reporting

we’re ending the span that we really want to close out.

Parameters:

  • name (String)

    the name of the span to end

  • kvs (Hash) (defaults to: {})

    list of key values to be reported in the span



179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/instana/tracer.rb', line 179

def log_end(name, kvs = {}, end_time = ::Instana::Util.now_in_ms)
  return unless self.current_span

  if ENV.key?('INSTANA_DEBUG') || ENV.key?('INSTANA_TEST')
    unless self.current_span.name == name
      ::Instana.logger.debug "Span mismatch: Attempt to end #{name} span but #{self.current_span.name} is active."
    end
  end

  self.current_span.set_tags(kvs)
  self.current_span.close(end_time)
  self.current_span = nil
end

#log_entry(name, kvs = nil, start_time = ::Instana::Util.now_in_ms, child_of = nil) ⇒ Object

Will establish a new span as a child of the current span in an existing trace

Parameters:

  • name (String)

    the name of the span to create

  • kvs (Hash) (defaults to: nil)

    list of key values to be reported in the span



113
114
115
116
117
118
119
120
121
122
123
# File 'lib/instana/tracer.rb', line 113

def log_entry(name, kvs = nil, start_time = ::Instana::Util.now_in_ms, child_of = nil)
  return unless self.current_span || child_of

  if child_of && (child_of.is_a?(::Instana::Span) || child_of.is_a?(::Instana::SpanContext))
    new_span = Span.new(name, parent_ctx: child_of, start_time: start_time)
  else
    new_span = Span.new(name, parent_ctx: self.current_span, start_time: start_time)
  end
  new_span.set_tags(kvs) if kvs
  self.current_span = new_span
end

#log_error(e) ⇒ Object

Add an error to the current span

Parameters:

  • e (Exception)

    Add exception to the current span



138
139
140
141
# File 'lib/instana/tracer.rb', line 138

def log_error(e)
  return unless self.current_span
  self.current_span.add_error(e)
end

#log_exit(name, kvs = {}) ⇒ Object

Note:

‘name` isn’t really required but helps keep sanity that

Closes out the current span

we’re closing out the span that we really want to close out.

Parameters:

  • name (String)

    the name of the span to exit (close out)

  • kvs (Hash) (defaults to: {})

    list of key values to be reported in the span



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/instana/tracer.rb', line 151

def log_exit(name, kvs = {})
  return unless self.current_span

  if ENV.key?('INSTANA_DEBUG') || ENV.key?('INSTANA_TEST')
    unless self.current_span.name == name
      ::Instana.logger.debug "Span mismatch: Attempt to exit #{name} span but #{self.current_span.name} is active."
    end
  end

  self.current_span.set_tags(kvs)
  self.current_span.close

  if self.current_span.parent
    self.current_span = self.current_span.parent
  else
    self.current_span = nil
  end
end

#log_info(kvs) ⇒ Object

Add info to the current span

Parameters:

  • kvs (Hash)

    list of key values to be reported in the span



129
130
131
132
# File 'lib/instana/tracer.rb', line 129

def log_info(kvs)
  return unless self.current_span
  self.current_span.set_tags(kvs)
end

#log_start_or_continue(name, kvs = {}, incoming_context = nil) ⇒ Object

Will start a new trace or continue an on-going one (such as from incoming remote requests with context headers).

Parameters:

  • name (String)

    the name of the span to start

  • kvs (Hash) (defaults to: {})

    list of key values to be reported in the span

  • incoming_context (SpanContext or Hash) (defaults to: nil)

    specifies the incoming context. At a minimum, it should specify :trace_id and :span_id from the following:

    :trace_id the trace ID (must be an unsigned hex-string)
    :span_id the ID of the parent span (must be an unsigned hex-string)
    :level specifies data collection level (optional)
    


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/instana/tracer.rb', line 83

def log_start_or_continue(name, kvs = {}, incoming_context = nil)
  return if !::Instana.agent.ready? || !::Instana.config[:tracing][:enabled]
  ::Instana.logger.debug { "#{__method__} passed a block.  Use `start_or_continue` instead!" } if block_given?

  # Handle the potential variations on `incoming_context`
  if incoming_context
    if incoming_context.is_a?(Hash)
      if !incoming_context.empty?
        parent_context = SpanContext.new(incoming_context[:trace_id], incoming_context[:span_id], incoming_context[:level])
      end
    else
      parent_context = incoming_context
    end
  end

  if parent_context
    self.current_span = Span.new(name, parent_ctx: parent_context)
  else
    self.current_span = Span.new(name)
  end
  self.current_span.set_tags(kvs) unless kvs.empty?
  self.current_span
end

#span_idObject

Returns the current [Span] ID for the active trace (if there is one), otherwise nil.



381
382
383
384
# File 'lib/instana/tracer.rb', line 381

def span_id
  self.current_span  ? self.current_span.span_id : nil
  ::Instana.logger.debug("tracer.span_id will deprecated in a future version.")
end

#span_id_headerString

Take the current span_id and convert it to a header compatible formate.

Returns:

  • (String)

    a hexadecimal representation of the current span ID



362
363
364
365
366
367
368
# File 'lib/instana/tracer.rb', line 362

def span_id_header
  if self.current_span
    self.current_span.context.span_id_header
  else
    ""
  end
end

#start_or_continue_trace(name, kvs = {}, incoming_context = nil, &block) ⇒ Object

Will start a new trace or continue an on-going one (such as from incoming remote requests with context headers).

Parameters:

  • name (String)

    the name of the span to start

  • kvs (Hash) (defaults to: {})

    list of key values to be reported in the span

  • incoming_context (Hash) (defaults to: nil)

    specifies the incoming context. At a minimum, it should specify :trace_id and :span_id from the following:

    @:trace_id the trace ID (must be an unsigned hex-string)
    :span_id the ID of the parent span (must be an unsigned hex-string)
    :level specifies data collection level (optional)
    


37
38
39
40
41
42
43
44
45
# File 'lib/instana/tracer.rb', line 37

def start_or_continue_trace(name, kvs = {}, incoming_context = nil, &block)
  log_start_or_continue(name, kvs, incoming_context)
  yield
rescue Exception => e
  log_error(e)
  raise
ensure
  log_end(name)
end

#start_span(operation_name, child_of: nil, start_time: ::Instana::Util.now_in_ms, tags: nil) ⇒ Span

Start a new span

Parameters:

  • operation_name (String)

    The name of the operation represented by the span

  • child_of (Span) (defaults to: nil)

    A span to be used as the ChildOf reference

  • start_time (Time) (defaults to: ::Instana::Util.now_in_ms)

    the start time of the span

  • tags (Hash) (defaults to: nil)

    Starting tags for the span

Returns:



256
257
258
259
260
261
262
263
264
# File 'lib/instana/tracer.rb', line 256

def start_span(operation_name, child_of: nil, start_time: ::Instana::Util.now_in_ms, tags: nil)
  if child_of && (child_of.is_a?(::Instana::Span) || child_of.is_a?(::Instana::SpanContext))
    new_span = Span.new(operation_name, parent_ctx: child_of, start_time: start_time)
  else
    new_span = Span.new(operation_name, start_time: start_time)
  end
  new_span.set_tags(tags) if tags
  new_span
end

#trace(name, kvs = {}, &block) ⇒ Object

Trace a block of code within the context of the exiting trace

Example usage:

::Instana.tracer.trace(:dbwork, { :db_name => @db.name }) do

@db.select(1)

end

Parameters:

  • name (String)

    the name of the span to start

  • kvs (Hash) (defaults to: {})

    list of key values to be reported in this new span



58
59
60
61
62
63
64
65
66
# File 'lib/instana/tracer.rb', line 58

def trace(name, kvs = {}, &block)
  log_entry(name, kvs)
  yield
rescue Exception => e
  log_error(e)
  raise
ensure
  log_exit(name)
end

#trace_idObject

Returns the trace ID for the active trace (if there is one), otherwise nil.



373
374
375
376
# File 'lib/instana/tracer.rb', line 373

def trace_id
  self.current_span ? self.current_span.id : nil
  ::Instana.logger.debug("tracer.trace_id will deprecated in a future version.")
end

#trace_id_headerString

Take the current trace_id and convert it to a header compatible format.

Returns:

  • (String)

    a hexadecimal representation of the current trace ID



349
350
351
352
353
354
355
# File 'lib/instana/tracer.rb', line 349

def trace_id_header
  if self.current_span
    self.current_span.context.trace_id_header
  else
    ""
  end
end

#tracing?Boolean

Indicates if we’re are currently in the process of collecting a trace. This is false when the host agent isn available.

Returns:

  • (Boolean)

    true or false on whether we are currently tracing or not



314
315
316
317
318
319
# File 'lib/instana/tracer.rb', line 314

def tracing?
  # The non-nil value of this instance variable
  # indicates if we are currently tracing
  # in this thread or not.
  self.current_span ? true : false
end

#tracing_span?(name) ⇒ Boolean

Indicates if we’re tracing and the current span name matches <name>

Parameters:

  • name (Symbol)

    the name to check against the current span

Returns:

  • (Boolean)


328
329
330
331
332
333
# File 'lib/instana/tracer.rb', line 328

def tracing_span?(name)
  if self.current_span
    return self.current_span.name == name
  end
  false
end