Class: Datadog::Span
- Inherits:
-
Object
- Object
- Datadog::Span
- Includes:
- Analytics::Span, ForcedTracing::Span
- Defined in:
- lib/ddtrace/span.rb
Overview
Represents a logical unit of work in the system. Each trace consists of one or more spans. Each span consists of a start time and a duration. For example, a span can describe the time spent on a distributed call on a separate machine, or the time spent in a small component within a larger operation. Spans can be nested within each other, and in those instances will have a parent-child relationship.
rubocop:disable Metrics/ClassLength
Constant Summary collapse
- MAX_ID =
The max value for a Span identifier. Span and trace identifiers should be strictly positive and strictly inferior to this limit.
Limited to 63-bit positive integers, as some other languages might be limited to this, and IDs need to be easy to port across various languages and platforms.
2**63
- EXTERNAL_MAX_ID =
While we only generate 63-bit integers due to limitations in other languages, we support parsing 64-bit integers for distributed tracing since an upstream system may generate one
2**64
- NUMERIC_TAG_SIZE_RANGE =
This limit is for numeric tags because uint64 could end up rounded.
(-2**53..2**53)
Instance Attribute Summary collapse
-
#context ⇒ Object
Returns the value of attribute context.
-
#end_time ⇒ Object
Returns the value of attribute end_time.
-
#name ⇒ Object
Returns the value of attribute name.
-
#parent ⇒ Object
Returns the value of attribute parent.
-
#parent_id ⇒ Object
Returns the value of attribute parent_id.
-
#resource ⇒ Object
Returns the value of attribute resource.
-
#sampled ⇒ Object
Returns the value of attribute sampled.
-
#service ⇒ Object
Returns the value of attribute service.
-
#span_id ⇒ Object
Returns the value of attribute span_id.
-
#span_type ⇒ Object
Returns the value of attribute span_type.
-
#start_time ⇒ Object
Returns the value of attribute start_time.
-
#status ⇒ Object
Returns the value of attribute status.
-
#trace_id ⇒ Object
Returns the value of attribute trace_id.
-
#tracer ⇒ Object
Returns the value of attribute tracer.
Instance Method Summary collapse
- #allocations ⇒ Object
-
#clear_metric(key) ⇒ Object
This method removes a metric for the given key.
-
#clear_tag(key) ⇒ Object
This method removes a tag for the given key.
-
#finish(finish_time = nil) ⇒ Object
Mark the span finished at the current time and submit it.
-
#finished? ⇒ Boolean
Return whether the span is finished or not.
-
#get_metric(key) ⇒ Object
Return the metric with the given key, nil if it doesn’t exist.
-
#get_tag(key) ⇒ Object
Return the tag with the given key, nil if it doesn’t exist.
-
#initialize(tracer, name, options = {}) ⇒ Span
constructor
Create a new span linked to the given tracer.
-
#pretty_print(q) ⇒ Object
Return a human readable version of the span.
-
#set_error(e) ⇒ Object
Mark the span with the given error.
-
#set_metric(key, value) ⇒ Object
This method sets a tag with a floating point value for the given key.
-
#set_parent(parent) ⇒ Object
DEPRECATED: remove this function in the next release, replaced by “parent=“.
-
#set_tag(key, value = nil) ⇒ Object
Set the given key / value tag pair on the span.
-
#set_tags(tags) ⇒ Object
Sets tags from given hash, for each key in hash it sets the tag with that key and associated value from the hash.
-
#to_hash ⇒ Object
Return the hash representation of the current span.
-
#to_s ⇒ Object
Return a string representation of the span.
Constructor Details
#initialize(tracer, name, options = {}) ⇒ Span
Create a new span linked to the given tracer. Call the Tracer method start_span()
and then finish()
once the tracer operation is over.
-
service
: the service name for this span -
resource
: the resource this span refers, orname
if it’s missing -
span_type
: the type of the span (such ashttp
,db
and so on) -
parent_id
: the identifier of the parent span -
trace_id
: the identifier of the root span for this trace -
context
: the context of the span
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/ddtrace/span.rb', line 54 def initialize(tracer, name, = {}) @tracer = tracer @name = name @service = .fetch(:service, nil) @resource = .fetch(:resource, name) @span_type = .fetch(:span_type, nil) @span_id = Datadog::Utils.next_id @parent_id = .fetch(:parent_id, 0) @trace_id = .fetch(:trace_id, Datadog::Utils.next_id) @context = .fetch(:context, nil) @meta = {} @metrics = {} @status = 0 @parent = nil @sampled = true @start_time = nil # set by Tracer.start_span @end_time = nil # set by Span.finish @allocation_count_start = now_allocations @allocation_count_finish = @allocation_count_start end |
Instance Attribute Details
#context ⇒ Object
Returns the value of attribute context.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def context @context end |
#end_time ⇒ Object
Returns the value of attribute end_time.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def end_time @end_time end |
#name ⇒ Object
Returns the value of attribute name.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def name @name end |
#parent ⇒ Object
Returns the value of attribute parent.
44 45 46 |
# File 'lib/ddtrace/span.rb', line 44 def parent @parent end |
#parent_id ⇒ Object
Returns the value of attribute parent_id.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def parent_id @parent_id end |
#resource ⇒ Object
Returns the value of attribute resource.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def resource @resource end |
#sampled ⇒ Object
Returns the value of attribute sampled.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def sampled @sampled end |
#service ⇒ Object
Returns the value of attribute service.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def service @service end |
#span_id ⇒ Object
Returns the value of attribute span_id.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def span_id @span_id end |
#span_type ⇒ Object
Returns the value of attribute span_type.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def span_type @span_type end |
#start_time ⇒ Object
Returns the value of attribute start_time.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def start_time @start_time end |
#status ⇒ Object
Returns the value of attribute status.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def status @status end |
#trace_id ⇒ Object
Returns the value of attribute trace_id.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def trace_id @trace_id end |
#tracer ⇒ Object
Returns the value of attribute tracer.
38 39 40 |
# File 'lib/ddtrace/span.rb', line 38 def tracer @tracer end |
Instance Method Details
#allocations ⇒ Object
229 230 231 |
# File 'lib/ddtrace/span.rb', line 229 def allocations @allocation_count_finish - @allocation_count_start end |
#clear_metric(key) ⇒ Object
This method removes a metric for the given key. It acts like #remove_tag.
144 145 146 |
# File 'lib/ddtrace/span.rb', line 144 def clear_metric(key) @metrics.delete(key) end |
#clear_tag(key) ⇒ Object
This method removes a tag for the given key.
121 122 123 |
# File 'lib/ddtrace/span.rb', line 121 def clear_tag(key) @meta.delete(key) end |
#finish(finish_time = nil) ⇒ Object
Mark the span finished at the current time and submit it.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/ddtrace/span.rb', line 164 def finish(finish_time = nil) # A span should not be finished twice. Note that this is not thread-safe, # finish is called from multiple threads, a given span might be finished # several times. Again, one should not do this, so this test is more a # fallback to avoid very bad things and protect you in most common cases. return if finished? @allocation_count_finish = now_allocations # Provide a default start_time if unset, but this should have been set by start_span. # Using now here causes 0-duration spans, still, this is expected, as we never # explicitely say when it started. @start_time ||= Time.now.utc @end_time = finish_time.nil? ? Time.now.utc : finish_time # finish this # Finish does not really do anything if the span is not bound to a tracer and a context. return self if @tracer.nil? || @context.nil? # spans without a service would be dropped, so here we provide a default. # This should really never happen with integrations in contrib, as a default # service is always set. It's only for custom instrumentation. @service ||= (@tracer && @tracer.default_service) begin @context.close_span(self) @tracer.record(self) rescue StandardError => e Datadog.logger.debug("error recording finished trace: #{e}") Datadog.health_metrics.error_span_finish(1, tags: ["error:#{e.class.name}"]) end self end |
#finished? ⇒ Boolean
Return whether the span is finished or not.
199 200 201 |
# File 'lib/ddtrace/span.rb', line 199 def finished? !@end_time.nil? end |
#get_metric(key) ⇒ Object
Return the metric with the given key, nil if it doesn’t exist.
149 150 151 |
# File 'lib/ddtrace/span.rb', line 149 def get_metric(key) @metrics[key] || @meta[key] end |
#get_tag(key) ⇒ Object
Return the tag with the given key, nil if it doesn’t exist.
126 127 128 |
# File 'lib/ddtrace/span.rb', line 126 def get_tag(key) @meta[key] || @metrics[key] end |
#pretty_print(q) ⇒ Object
Return a human readable version of the span
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/ddtrace/span.rb', line 258 def pretty_print(q) start_time = (@start_time.to_f * 1e9).to_i rescue '-' end_time = (@end_time.to_f * 1e9).to_i rescue '-' duration = ((@end_time - @start_time) * 1e9).to_i rescue 0 q.group 0 do q.breakable q.text "Name: #{@name}\n" q.text "Span ID: #{@span_id}\n" q.text "Parent ID: #{@parent_id}\n" q.text "Trace ID: #{@trace_id}\n" q.text "Type: #{@span_type}\n" q.text "Service: #{@service}\n" q.text "Resource: #{@resource}\n" q.text "Error: #{@status}\n" q.text "Start: #{start_time}\n" q.text "End: #{end_time}\n" q.text "Duration: #{duration}\n" q.text "Allocations: #{allocations}\n" q.group(2, 'Tags: [', "]\n") do q.breakable q.seplist @meta.each do |key, value| q.text "#{key} => #{value}" end end q.group(2, 'Metrics: [', ']') do q.breakable q.seplist @metrics.each do |key, value| q.text "#{key} => #{value}" end end end end |
#set_error(e) ⇒ Object
Mark the span with the given error.
154 155 156 157 158 159 160 161 |
# File 'lib/ddtrace/span.rb', line 154 def set_error(e) e = Error.build_from(e) @status = Ext::Errors::STATUS set_tag(Ext::Errors::TYPE, e.type) unless e.type.empty? set_tag(Ext::Errors::MSG, e.) unless e..empty? set_tag(Ext::Errors::STACK, e.backtrace) unless e.backtrace.empty? end |
#set_metric(key, value) ⇒ Object
This method sets a tag with a floating point value for the given key. It acts like ‘set_tag()` and it simply add a tag without further processing.
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/ddtrace/span.rb', line 132 def set_metric(key, value) # Keys must be unique between tags and metrics @meta.delete(key) # enforce that the value is a floating point number value = Float(value) @metrics[key] = value rescue StandardError => e Datadog.logger.debug("Unable to set the metric #{key}, ignoring it. Caused by: #{e}") end |
#set_parent(parent) ⇒ Object
DEPRECATED: remove this function in the next release, replaced by “parent=“
209 210 211 |
# File 'lib/ddtrace/span.rb', line 209 def set_parent(parent) self.parent = parent end |
#set_tag(key, value = nil) ⇒ Object
Set the given key / value tag pair on the span. Keys and values must be strings. A valid example is:
span.set_tag('http.method', request.method)
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/ddtrace/span.rb', line 86 def set_tag(key, value = nil) # Keys must be unique between tags and metrics @metrics.delete(key) # Ensure `http.status_code` is always a string so it is added to # @meta instead of @metrics # DEV: This is necessary because the agent looks to `meta['http.status_code']` for # tagging necessary metrics value = value.to_s if key == Ext::HTTP::STATUS_CODE # NOTE: Adding numeric tags as metrics is stop-gap support # for numeric typed tags. Eventually they will become # tags again. # Any numeric that is not an integer greater than max size is logged as a metric. # Everything else gets logged as a tag. if value.is_a?(Numeric) && !(value.is_a?(Integer) && !NUMERIC_TAG_SIZE_RANGE.cover?(value)) set_metric(key, value) else @meta[key] = value.to_s end rescue StandardError => e Datadog.logger.debug("Unable to set the tag #{key}, ignoring it. Caused by: #{e}") end |
#set_tags(tags) ⇒ Object
Sets tags from given hash, for each key in hash it sets the tag with that key and associated value from the hash. It is shortcut for ‘set_tag`. Keys and values of the hash must be strings. Note that nested hashes are not supported. A valid example is:
span.({ "http.method" => "GET", "user.id" => "234" })
116 117 118 |
# File 'lib/ddtrace/span.rb', line 116 def () .each { |k, v| set_tag(k, v) } end |
#to_hash ⇒ Object
Return the hash representation of the current span.
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/ddtrace/span.rb', line 234 def to_hash h = { span_id: @span_id, parent_id: @parent_id, trace_id: @trace_id, name: @name, service: @service, resource: @resource, type: @span_type, meta: @meta, metrics: @metrics, allocations: allocations, error: @status } if !@start_time.nil? && !@end_time.nil? h[:start] = (@start_time.to_f * 1e9).to_i h[:duration] = ((@end_time - @start_time) * 1e9).to_i end h end |
#to_s ⇒ Object
Return a string representation of the span.
204 205 206 |
# File 'lib/ddtrace/span.rb', line 204 def to_s "Span(name:#{@name},sid:#{@span_id},tid:#{@trace_id},pid:#{@parent_id})" end |