Class: Datadog::Tracing::SpanOperation
- Inherits:
-
Object
- Object
- Datadog::Tracing::SpanOperation
- Includes:
- Metadata
- Defined in:
- lib/datadog/tracing/span_operation.rb
Overview
Represents the act of taking a span measurement. It gives a Span a context which can be used to build a Span. When completed, it yields the Span.
Defined Under Namespace
Classes: AlreadyStartedError, Events
Instance Attribute Summary collapse
-
#end_time ⇒ Object
Span attributes NOTE: In the future, we should drop the me.
-
#id ⇒ Object
(also: #span_id)
readonly
Span attributes NOTE: In the future, we should drop the me.
-
#name ⇒ String
Operation name.
-
#parent_id ⇒ Object
readonly
Span attributes NOTE: In the future, we should drop the me.
-
#resource ⇒ String
Span resource.
-
#service ⇒ String
Service name.
-
#start_time ⇒ Object
Span attributes NOTE: In the future, we should drop the me.
-
#status ⇒ Object
Returns the value of attribute status.
-
#trace_id ⇒ Object
readonly
Span attributes NOTE: In the future, we should drop the me.
-
#type ⇒ String
(also: #span_type)
Span type.
Instance Method Summary collapse
- #duration ⇒ Object
- #finish(end_time = nil) ⇒ Object
- #finished? ⇒ Boolean
-
#initialize(name, child_of: nil, events: nil, on_error: nil, parent_id: 0, resource: name, service: nil, start_time: nil, tags: nil, trace_id: nil, type: nil) ⇒ SpanOperation
constructor
A new instance of SpanOperation.
- #measure ⇒ Object
-
#pretty_print(q) ⇒ Object
Return a human readable version of the span.
- #set_error(e) ⇒ Object
- #start(start_time = nil) ⇒ Object
-
#started? ⇒ Boolean
Return whether the duration is started or not.
-
#stop(stop_time = nil) ⇒ Object
Mark the span stopped at the current time.
-
#stopped? ⇒ Boolean
Return whether the duration is stopped or not.
-
#to_hash ⇒ Object
Return the hash representation of the current span.
-
#to_s ⇒ Object
Return a string representation of the span.
Methods included from Metadata
Constructor Details
#initialize(name, child_of: nil, events: nil, on_error: nil, parent_id: 0, resource: name, service: nil, start_time: nil, tags: nil, trace_id: nil, type: nil) ⇒ SpanOperation
Returns a new instance of SpanOperation.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/datadog/tracing/span_operation.rb', line 40 def initialize( name, child_of: nil, events: nil, on_error: nil, parent_id: 0, resource: name, service: nil, start_time: nil, tags: nil, trace_id: nil, type: nil ) # Ensure dynamically created strings are UTF-8 encoded. # # All strings created in Ruby land are UTF-8. The only sources of non-UTF-8 string are: # * Strings explicitly encoded as non-UTF-8. # * Some natively created string, although most natively created strings are UTF-8. self.name = name self.service = service self.type = type self.resource = resource @id = Tracing::Utils.next_id @parent_id = parent_id || 0 @trace_id = trace_id || Tracing::Utils::TraceId.next_id @status = 0 # start_time and end_time track wall clock. In Ruby, wall clock # has less accuracy than monotonic clock, so if possible we look to only use wall clock # to measure duration when a time is supplied by the user, or if monotonic clock # is unsupported. @start_time = nil @end_time = nil # duration_start and duration_end track monotonic clock, and may remain nil in cases where it # is known that we have to use wall clock to measure duration. @duration_start = nil @duration_end = nil # Set tags if provided. () if # Only set parent if explicitly provided. # We don't want it to override context-derived # IDs if it's a distributed trace w/o a parent span. parent = child_of self.parent = parent if parent # Some other SpanOperation-specific behavior @events = events || Events.new @span = nil # Subscribe :on_error event @events.on_error.wrap_default(&on_error) if on_error.is_a?(Proc) # Start the span with start time, if given. start(start_time) if start_time end |
Instance Attribute Details
#end_time ⇒ Object
Span attributes NOTE: In the future, we should drop the me
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def end_time @end_time end |
#id ⇒ Object (readonly) Also known as: span_id
Span attributes NOTE: In the future, we should drop the me
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def id @id end |
#name ⇒ String
Operation name.
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def name @name end |
#parent_id ⇒ Object (readonly)
Span attributes NOTE: In the future, we should drop the me
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def parent_id @parent_id end |
#resource ⇒ String
Span resource.
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def resource @resource end |
#service ⇒ String
Service name.
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def service @service end |
#start_time ⇒ Object
Span attributes NOTE: In the future, we should drop the me
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def start_time @start_time end |
#status ⇒ Object
Returns the value of attribute status.
37 38 39 |
# File 'lib/datadog/tracing/span_operation.rb', line 37 def status @status end |
#trace_id ⇒ Object (readonly)
Span attributes NOTE: In the future, we should drop the me
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def trace_id @trace_id end |
#type ⇒ String Also known as: span_type
Span type.
26 27 28 |
# File 'lib/datadog/tracing/span_operation.rb', line 26 def type @type end |
Instance Method Details
#duration ⇒ Object
264 265 266 267 |
# File 'lib/datadog/tracing/span_operation.rb', line 264 def duration return @duration_end - @duration_start if @duration_start && @duration_end return @end_time - @start_time if @start_time && @end_time end |
#finish(end_time = nil) ⇒ Object
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/datadog/tracing/span_operation.rb', line 243 def finish(end_time = nil) # Returned memoized span if already finished return span if finished? # Stop timing stop(end_time) # Build span # Memoize for performance reasons @span = build_span # Trigger after_finish event events.after_finish.publish(span, self) span end |
#finished? ⇒ Boolean
260 261 262 |
# File 'lib/datadog/tracing/span_operation.rb', line 260 def finished? !span.nil? end |
#measure ⇒ Object
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/datadog/tracing/span_operation.rb', line 131 def measure raise ArgumentError, 'Must provide block to measure!' unless block_given? # TODO: Should we just invoke the block and skip tracing instead? raise AlreadyStartedError if started? return_value = nil begin # If span fails to start, don't prevent the operation from # running, to minimize impact on normal application function. begin start rescue StandardError => e Datadog.logger.debug { "Failed to start span: #{e}" } ensure # We should yield to the provided block when possible, as this # block is application code that we don't want to hinder. # * We don't yield during a fatal error, as the application is likely trying to # end its execution (either due to a system error or graceful shutdown). return_value = yield(self) unless e && !e.is_a?(StandardError) end # rubocop:disable Lint/RescueException # Here we really want to catch *any* exception, not only StandardError, # as we really have no clue of what is in the block, # and it is user code which should be executed no matter what. # It's not a problem since we re-raise it afterwards so for example a # SignalException::Interrupt would still bubble up. rescue Exception => e # Stop the span first, so timing is a more accurate. # If the span failed to start, timing may be inaccurate, # but this is not really a serious concern. stop # Trigger the on_error event events.on_error.publish(self, e) # We must finish the span to trigger callbacks, # and build the final span. finish raise e # Use an ensure block here to make sure the span closes. # NOTE: It's not sufficient to use "else": when a function # uses "return", it will skip "else". ensure # Finish the span # NOTE: If an error was raised, this "finish" might be redundant. finish unless finished? end # rubocop:enable Lint/RescueException return_value end |
#pretty_print(q) ⇒ Object
Return a human readable version of the span
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/datadog/tracing/span_operation.rb', line 303 def pretty_print(q) start_time = (self.start_time.to_f * 1e9).to_i end_time = (self.end_time.to_f * 1e9).to_i q.group 0 do q.breakable q.text "Name: #{@name}\n" q.text "Span ID: #{@id}\n" q.text "Parent ID: #{@parent_id}\n" q.text "Trace ID: #{@trace_id}\n" q.text "Type: #{@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.to_f if stopped?}\n" q.group(2, 'Tags: [', "]\n") do q.breakable q.seplist .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
269 270 271 272 |
# File 'lib/datadog/tracing/span_operation.rb', line 269 def set_error(e) @status = Metadata::Ext::Errors::STATUS super end |
#start(start_time = nil) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/datadog/tracing/span_operation.rb', line 185 def start(start_time = nil) # Span can only be started once return self if started? # Trigger before_start event events.before_start.publish(self) # Start the span @start_time = start_time || Core::Utils::Time.now.utc @duration_start = start_time.nil? ? duration_marker : nil self end |
#started? ⇒ Boolean
Return whether the duration is started or not
224 225 226 |
# File 'lib/datadog/tracing/span_operation.rb', line 224 def started? !@start_time.nil? end |
#stop(stop_time = nil) ⇒ Object
Mark the span stopped at the current time
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/datadog/tracing/span_operation.rb', line 200 def stop(stop_time = nil) # A span should not be stopped twice. Note that this is not thread-safe, # stop is called from multiple threads, a given span might be stopped # 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 stopped? now = Core::Utils::Time.now.utc # Provide a default start_time if unset. # Using `now` here causes duration to be 0; this is expected # behavior when start_time is unknown. start(stop_time || now) unless started? @end_time = stop_time || now @duration_end = stop_time.nil? ? duration_marker : nil # Trigger after_stop event events.after_stop.publish(self) self end |
#stopped? ⇒ Boolean
Return whether the duration is stopped or not.
229 230 231 |
# File 'lib/datadog/tracing/span_operation.rb', line 229 def stopped? !@end_time.nil? end |
#to_hash ⇒ Object
Return the hash representation of the current span.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/datadog/tracing/span_operation.rb', line 280 def to_hash h = { error: @status, id: @id, meta: , metrics: metrics, name: @name, parent_id: @parent_id, resource: @resource, service: @service, trace_id: @trace_id, type: @type } if stopped? h[:start] = start_time_nano h[:duration] = duration_nano end h end |
#to_s ⇒ Object
Return a string representation of the span.
275 276 277 |
# File 'lib/datadog/tracing/span_operation.rb', line 275 def to_s "SpanOperation(name:#{@name},sid:#{@id},tid:#{@trace_id},pid:#{@parent_id})" end |