Class: Instana::Trace

Inherits:
Object
  • Object
show all
Defined in:
lib/instana/tracing/trace.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, kvs = nil, incoming_context = {}, start_time = Time.now) ⇒ Trace

Initializes a new instance of Trace

Parameters:

  • name (String)

    the name of the span to start

  • kvs (Hash) (defaults to: nil)

    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)
    


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/instana/tracing/trace.rb', line 20

def initialize(name, kvs = nil, incoming_context = {}, start_time = Time.now)
  # The collection of spans that make
  # up this trace.
  @spans = Set.new

  # Generate a random 64bit ID for this trace
  @id = ::Instana::Util.generate_id

  # Indicates the time when this trace was started.  Used to timeout
  # traces that have asynchronous spans that never close out.
  @started_at = Time.now

  # Indicates if this trace has any asynchronous spans within it
  @has_async = false

  # This is a new trace so open the first span with the proper
  # root span IDs.
  @current_span = Span.new(name, @id, start_time: start_time)
  @current_span.set_tags(kvs) if kvs

  # Handle potential incoming context
  if !incoming_context || incoming_context.empty?
    # No incoming context. Set trace ID the same
    # as this first span.
    @current_span[:s] = @id
  else
    @id = incoming_context[:trace_id]
    @current_span[:t] = incoming_context[:trace_id]
    @current_span[:p] = incoming_context[:span_id]
  end

  @spans.add(@current_span)
end

Instance Attribute Details

#idInteger (readonly)

Returns the ID for this trace.

Returns:

  • (Integer)

    the ID for this trace



4
5
6
# File 'lib/instana/tracing/trace.rb', line 4

def id
  @id
end

#spansSet (readonly)

The collection of ‘Span` for this trace

Returns:

  • (Set)

    the collection of spans for this trace



8
9
10
# File 'lib/instana/tracing/trace.rb', line 8

def spans
  @spans
end

Instance Method Details

#add_async_error(e, span) ⇒ Object

Log an error into an asynchronous span

Parameters:

  • e (Exception)

    Add exception to the current span

  • span (Span)

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



177
178
179
# File 'lib/instana/tracing/trace.rb', line 177

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

#add_async_info(kvs, span) ⇒ Object

Log info into an asynchronous span

Parameters:

  • kvs (Hash)

    list of key values to be reported in the span

  • span (Span)

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



167
168
169
# File 'lib/instana/tracing/trace.rb', line 167

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

#add_error(e, span = nil) ⇒ Object

Log an error into the current span

Parameters:

  • e (Exception)

    Add exception to the current span



108
109
110
111
112
113
114
# File 'lib/instana/tracing/trace.rb', line 108

def add_error(e, span = nil)
  # Return if we've already logged this exception and it
  # is just propogating up the spans.
  return if e && e.instance_variable_get(:@instana_logged)
  span ||= @current_span
  span.add_error(e)
end

#add_info(kvs, span = nil) ⇒ Object

Add KVs to the current span

Parameters:

  • span (Span) (defaults to: nil)

    the span to add kvs to or otherwise the current span

  • kvs (Hash)

    list of key values to be reported in the span



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

def add_info(kvs, span = nil)
  span ||= @current_span

  if span.custom?
    if span[:data][:sdk].key?(:custom)
      span[:data][:sdk][:custom].merge!(kvs)
    else
      span[:data][:sdk][:custom] = kvs
    end
  else
    kvs.each_pair do |k,v|
      if !span[:data].key?(k)
        span[:data][k] = v
      elsif v.is_a?(Hash) && span[:data][k].is_a?(Hash)
        span[:data][k].merge!(v)
      else
        span[:data][k] = v
      end
    end
  end
end

#complete?Boolean

Indicates if every span of this trace has completed. Useful when asynchronous spans potentially could run longer than the parent trace.

Returns:

  • (Boolean)


214
215
216
217
218
219
220
221
# File 'lib/instana/tracing/trace.rb', line 214

def complete?
  @spans.each do |span|
    if !span.duration
      return false
    end
  end
  true
end

#current_spanSpan

Get the current span.

Returns:



250
251
252
# File 'lib/instana/tracing/trace.rb', line 250

def current_span
  @current_span
end

#current_span_idInteger

Get the ID of the current span for this trace. Used often to place in HTTP response headers.

Returns:

  • (Integer)

    a random 64bit integer



259
260
261
# File 'lib/instana/tracing/trace.rb', line 259

def current_span_id
  @current_span.id
end

#current_span_nameObject

Get the name of the current span. Supports both registered spans and custom sdk spans.



266
267
268
# File 'lib/instana/tracing/trace.rb', line 266

def current_span_name
  @current_span.name
end

#current_span_name?(name) ⇒ Boolean

Check if the current span has the name value of <name>

Parameters:

  • name (Symbol)

    The name to be checked against.

Returns:

  • (Boolean)


276
277
278
# File 'lib/instana/tracing/trace.rb', line 276

def current_span_name?(name)
  @current_span.name == name
end

#discard?Boolean

For traces that have asynchronous spans, this method indicates whether we have hit the timeout on waiting for those async spans to close out.

Returns:

  • (Boolean)


286
287
288
289
290
291
292
293
# File 'lib/instana/tracing/trace.rb', line 286

def discard?
  # If this trace has async spans that have not closed
  # out in 5 minutes, then it's discarded.
  if has_async? && (Time.now.to_i - @started_at.to_i) > 601
    return true
  end
  false
end

#end_async_span(kvs = {}, span) ⇒ Object

End an asynchronous span

Parameters:

  • name (Symbol)

    the name of the span

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

    list of key values to be reported in the span

  • span (Span)

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



188
189
190
191
# File 'lib/instana/tracing/trace.rb', line 188

def end_async_span(kvs = {}, span)
  span.set_tags(kvs) unless kvs.empty?
  span.close
end

#end_span(kvs = {}, end_time = Time.now) ⇒ Object

Close out the current span and set the parent as the current span

Parameters:

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

    list of key values to be reported in the span



121
122
123
124
125
# File 'lib/instana/tracing/trace.rb', line 121

def end_span(kvs = {}, end_time = Time.now)
  @current_span.close(end_time)
  add_info(kvs) if kvs && !kvs.empty?
  @current_span = @current_span.parent unless @current_span.is_root?
end

#finish(kvs = {}, end_time = Time.now) ⇒ Object

Closes out the final span in this trace and runs any finalizer steps required. This should be called only when on the root span to end the trace.

Parameters:

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

    list of key values to be reported in the span



133
134
135
# File 'lib/instana/tracing/trace.rb', line 133

def finish(kvs = {}, end_time = Time.now)
  end_span(kvs, end_time)
end

#has_async?Boolean

Indicates whether this trace has any asynchronous spans.

Returns:

  • (Boolean)


225
226
227
# File 'lib/instana/tracing/trace.rb', line 225

def has_async?
  @has_async
end

#has_error?Boolean

Searches the set of spans and indicates if there is an error logged in one of them.

Returns:

  • (Boolean)

    true or false indicating the presence of an error



235
236
237
238
239
240
241
242
243
244
# File 'lib/instana/tracing/trace.rb', line 235

def has_error?
  @spans.each do |s|
    if s.key?(:error)
      if s[:error] == true
        return true
      end
    end
  end
  false
end

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

Start a new asynchronous span

The major differentiator between this method and simple new_span is that this method doesn’t affect @current_trace and instead returns an ID pair that can be used later to close out the created async span.

Parameters:

  • name (String)

    the name of the span to start

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

    list of key values to be reported in the span



150
151
152
153
154
155
156
157
158
159
# File 'lib/instana/tracing/trace.rb', line 150

def new_async_span(name, kvs = {})
  new_span = Span.new(name, @id, parent_id: @current_span.id)
  new_span.set_tags(kvs) unless kvs.empty?
  new_span.parent = @current_span
  new_span[:async] = @has_async = true

  # Add the new span to the span collection
  @spans.add(new_span)
  new_span
end

#new_span(name, kvs = nil, start_time = Time.now, child_of = nil) ⇒ Object

Start a new span as a child of @current_span

Parameters:

  • name (String)

    the name of the span to start

  • kvs (Hash) (defaults to: nil)

    list of key values to be reported in the span



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/instana/tracing/trace.rb', line 59

def new_span(name, kvs = nil, start_time = Time.now, child_of = nil)
  return unless @current_span

  if child_of && child_of.is_a?(::Instana::Span)
    new_span = Span.new(name, @id, parent_id: child_of.id, start_time: start_time)
    new_span.parent = child_of
    new_span.baggage = child_of.baggage.dup
  else
    new_span = Span.new(name, @id, parent_id: @current_span.id, start_time: start_time)
    new_span.parent = @current_span
    new_span.baggage = @current_span.baggage.dup
  end
  new_span.set_tags(kvs) if kvs

  @spans.add(new_span)
  @current_span = new_span
end

#valid?Boolean

Indicates whether all seems ok with this trace in it’s current state. Should be only called on finished traces.

Returns:

  • (Boolean)

    true or false on whether this trace is valid



202
203
204
205
206
207
208
209
# File 'lib/instana/tracing/trace.rb', line 202

def valid?
  @spans.each do |span|
    unless span.key?(:d)
      return false
    end
  end
  true
end