Class: Instana::Tracer

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

Instance Method Summary collapse

Methods included from ThreadLocal

thread_local

Instance Method Details

#contextObject

Retrieve the current context of the tracer.



251
252
253
254
# File 'lib/instana/tracer.rb', line 251

def context
  { :trace_id => self.current_trace.id,
    :span_id => self.current_trace.current_span_id }
end

#header_to_id(header_id) ⇒ Integer

Convert a received header value into a valid ID

Parameters:

  • header_id (String)

    the header value to be converted

Returns:

  • (Integer)


297
298
299
300
301
302
303
304
305
306
# File 'lib/instana/tracer.rb', line 297

def header_to_id(header_id)
  if !header_id.is_a?(String)
    Instana.logger.debug "header_to_id received a #{header_id.class}: returning 0"
    return 0
  end
  [header_id].pack("H*").unpack("q>")[0]
rescue => e
  Instana.logger.error "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
  Instana.logger.debug e.backtrace.join("\r\n")
end

#id_to_header(id) ⇒ String

Convert an ID to a value appropriate to pass in a header.

Parameters:

  • id (Integer)

    the id to be converted

Returns:

  • (String)


280
281
282
283
284
285
286
287
288
289
# File 'lib/instana/tracer.rb', line 280

def id_to_header(id)
  unless id.is_a?(Integer) || id.is_a?(String)
    Instana.logger.debug "id_to_header received a #{id.class}: returning empty string"
    return String.new
  end
  [id.to_i].pack('q>').unpack('H*')[0]
rescue => e
  Instana.logger.error "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
  Instana.logger.debug e.backtrace.join("\r\n")
end

#log_async_entry(name, kvs, incoming_context = nil) ⇒ 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



159
160
161
162
# File 'lib/instana/tracer.rb', line 159

def log_async_entry(name, kvs, incoming_context = nil)
  return unless tracing?
  self.current_trace.new_async_span(name, kvs)
end

#log_async_error(e, ids) ⇒ Object

Add an error to an asynchronous span

Parameters:

  • e (Exception)

    Add exception to the current span

  • ids (Hash)

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



192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/instana/tracer.rb', line 192

def log_async_error(e, ids)
  # Asynchronous spans can persist longer than the parent
  # trace.  With the trace ID, we check the current trace
  # but otherwise, we search staged traces.

  if tracing? && self.current_trace.id == ids[:trace_id]
    self.current_trace.add_async_error(e, ids)
  else
    trace = ::Instana.processor.staged_trace(ids)
    trace.add_async_error(e, ids)
  end
end

#log_async_exit(name, kvs, ids) ⇒ Object

Closes out an asynchronous span

Parameters:

  • name (String)

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

  • kvs (Hash)

    list of key values to be reported in the span

  • ids (Hash)

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



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/instana/tracer.rb', line 213

def log_async_exit(name, kvs, ids)
  # An asynchronous span can end after the current trace has
  # already completed so we make sure that we end the span
  # on the right trace.

  if tracing? && (self.current_trace.id == ids[:trace_id])
    self.current_trace.end_async_span(kvs, ids)
  else
    # Different trace from current so find the staged trace
    # and close out the span on it.
    trace = ::Instana.processor.staged_trace(ids)
    if trace
      trace.end_async_span(kvs, ids)
    else
      ::Instana.logger.debug "log_async_exit: Couldn't find staged trace. #{ids.inspect}"
    end
  end
end

#log_async_info(kvs, ids) ⇒ Object

Add info to an asynchronous span

Parameters:

  • kvs (Hash)

    list of key values to be reported in the span

  • t_context (Hash)

    the Trace ID and Span ID in the form of :trace_id => 12345 :span_id => 12345 This can be retrieved by using ::Instana.tracer.context



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/instana/tracer.rb', line 172

def log_async_info(kvs, ids)
  # Asynchronous spans can persist longer than the parent
  # trace.  With the trace ID, we check the current trace
  # but otherwise, we search staged traces.

  if tracing? && self.current_trace.id == ids[:trace_id]
    self.current_trace.add_async_info(kvs, ids)
  else
    trace = ::Instana.processor.staged_trace(ids)
    trace.add_async_info(kvs, ids)
  end
end

#log_end(name, kvs = {}) ⇒ 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



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/instana/tracer.rb', line 129

def log_end(name, kvs = {})
  return unless tracing?

  self.current_trace.finish(kvs)

  if !self.current_trace.has_async? ||
      (self.current_trace.has_async? && self.current_trace.complete?)
    Instana.processor.add(self.current_trace)
  else
    # This trace still has outstanding/uncompleted asynchronous spans.
    # Put it in the staging queue until the async span closes out or
    # 5 minutes has passed.  Whichever comes first.
    Instana.processor.stage(self.current_trace)
  end
  self.current_trace = nil
end

#log_entry(name, kvs = {}) ⇒ 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: {})

    list of key values to be reported in the span



84
85
86
87
# File 'lib/instana/tracer.rb', line 84

def log_entry(name, kvs = {})
  return unless tracing?
  self.current_trace.new_span(name, kvs)
end

#log_error(e) ⇒ Object

Add an error to the current span

Parameters:

  • e (Exception)

    Add exception to the current span



102
103
104
105
# File 'lib/instana/tracer.rb', line 102

def log_error(e)
  return unless tracing?
  self.current_trace.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



115
116
117
118
# File 'lib/instana/tracer.rb', line 115

def log_exit(name, kvs = {})
  return unless tracing?
  self.current_trace.end_span(kvs)
end

#log_info(kvs) ⇒ Object

Add info to the current span

Parameters:

  • kvs (Hash)

    list of key values to be reported in the span



93
94
95
96
# File 'lib/instana/tracer.rb', line 93

def log_info(kvs)
  return unless tracing?
  self.current_trace.add_info(kvs)
end

#log_start_or_continue(name, kvs = {}, incoming_context = {}) ⇒ 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: {})

    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)
    


73
74
75
76
# File 'lib/instana/tracer.rb', line 73

def log_start_or_continue(name, kvs = {}, incoming_context = {})
  return unless ::Instana.agent.ready?
  self.current_trace = ::Instana::Trace.new(name, kvs, incoming_context)
end

#span_idObject

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



318
319
320
# File 'lib/instana/tracer.rb', line 318

def span_id
  self.current_trace  ? current_trace.current_span_id : nil
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



270
271
272
# File 'lib/instana/tracer.rb', line 270

def span_id_header
  id_to_header(span_id)
end

#start_or_continue_trace(name, kvs = {}, incoming_context = {}, &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: {})

    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)
    


26
27
28
29
30
31
32
33
34
# File 'lib/instana/tracer.rb', line 26

def start_or_continue_trace(name, kvs = {}, incoming_context = {}, &block)
  log_start_or_continue(name, kvs, incoming_context)
  block.call
rescue Exception => e
  log_error(e)
  raise
ensure
  log_end(name)
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



47
48
49
50
51
52
53
54
55
56
# File 'lib/instana/tracer.rb', line 47

def trace(name, kvs = {}, &block)
  log_entry(name, kvs)
  result = block.call
  result
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.



311
312
313
# File 'lib/instana/tracer.rb', line 311

def trace_id
  self.current_trace ? self.current_trace.id : nil
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



261
262
263
# File 'lib/instana/tracer.rb', line 261

def trace_id_header
  id_to_header(trace_id)
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



242
243
244
245
246
247
# File 'lib/instana/tracer.rb', line 242

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