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
readonly
Span attributes NOTE: In the future, we should drop the me.
-
#links ⇒ Object
Returns the value of attribute links.
-
#logger ⇒ Object
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.
-
#span_events ⇒ Object
Returns the value of attribute span_events.
-
#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
Span type.
Instance Method Summary collapse
- #duration ⇒ Object
- #finish(end_time = nil) ⇒ Object
- #finished? ⇒ Boolean
- #get_collector_or_initialize ⇒ Object
-
#initialize(name, logger: Datadog.logger, events: nil, on_error: nil, parent_id: 0, resource: name, service: nil, start_time: nil, tags: nil, trace_id: nil, type: nil, links: nil, span_events: nil, id: nil) ⇒ SpanOperation
constructor
A new instance of SpanOperation.
- #measure ⇒ Object
-
#pretty_print(q) ⇒ Object
Return a human readable version of the span.
- #root? ⇒ Boolean
- #set_error(e) ⇒ Object
- #start(start_time = nil) ⇒ Object
-
#started? ⇒ Boolean
Return whether the duration is started or not.
-
#stop(stop_time = nil, exception: 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, logger: Datadog.logger, events: nil, on_error: nil, parent_id: 0, resource: name, service: nil, start_time: nil, tags: nil, trace_id: nil, type: nil, links: nil, span_events: nil, id: nil) ⇒ SpanOperation
Returns a new instance of SpanOperation.
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 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/datadog/tracing/span_operation.rb', line 44 def initialize( name, logger: Datadog.logger, events: nil, on_error: nil, parent_id: 0, resource: name, service: nil, start_time: nil, tags: nil, trace_id: nil, type: nil, links: nil, span_events: nil, id: nil ) @logger = logger # 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 = id.nil? ? Tracing::Utils.next_id : id @parent_id = parent_id || 0 @trace_id = trace_id || Tracing::Utils::TraceId.next_id @status = 0 # stores array of span links @links = links || [] # stores array of span events @span_events = span_events || [] # 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 # Some other SpanOperation-specific behavior @events = events || Events.new(logger: logger) @span = nil if on_error.nil? # Nothing, default error handler is already set up. elsif on_error.is_a?(Proc) # Subscribe :on_error event @events.on_error.wrap_default(&on_error) else logger.warn("on_error argument to SpanOperation ignored because is not a Proc: #{on_error}") end # 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
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def end_time @end_time end |
#id ⇒ Object (readonly)
Span attributes NOTE: In the future, we should drop the me
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def id @id end |
#links ⇒ Object
Returns the value of attribute links.
42 43 44 |
# File 'lib/datadog/tracing/span_operation.rb', line 42 def links @links end |
#logger ⇒ Object (readonly)
Span attributes NOTE: In the future, we should drop the me
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def logger @logger end |
#name ⇒ String
Operation name.
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def name @name end |
#parent_id ⇒ Object (readonly)
Span attributes NOTE: In the future, we should drop the me
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def parent_id @parent_id end |
#resource ⇒ String
Span resource.
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def resource @resource end |
#service ⇒ String
Service name.
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def service @service end |
#span_events ⇒ Object
Returns the value of attribute span_events.
42 43 44 |
# File 'lib/datadog/tracing/span_operation.rb', line 42 def span_events @span_events end |
#start_time ⇒ Object
Span attributes NOTE: In the future, we should drop the me
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def start_time @start_time end |
#status ⇒ Object
Returns the value of attribute status.
42 43 44 |
# File 'lib/datadog/tracing/span_operation.rb', line 42 def status @status end |
#trace_id ⇒ Object (readonly)
Span attributes NOTE: In the future, we should drop the me
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def trace_id @trace_id end |
#type ⇒ String
Span type.
30 31 32 |
# File 'lib/datadog/tracing/span_operation.rb', line 30 def type @type end |
Instance Method Details
#duration ⇒ Object
289 290 291 292 293 |
# File 'lib/datadog/tracing/span_operation.rb', line 289 def duration return @duration_end - @duration_start if @duration_start && @duration_end @end_time - @start_time if @start_time && @end_time end |
#finish(end_time = nil) ⇒ Object
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/datadog/tracing/span_operation.rb', line 268 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
285 286 287 |
# File 'lib/datadog/tracing/span_operation.rb', line 285 def finished? !span.nil? end |
#get_collector_or_initialize ⇒ Object
144 145 146 |
# File 'lib/datadog/tracing/span_operation.rb', line 144 def get_collector_or_initialize @collector ||= yield end |
#measure ⇒ Object
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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/datadog/tracing/span_operation.rb', line 148 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 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(exception: e) # 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
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
# File 'lib/datadog/tracing/span_operation.rb', line 330 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: [', "]\n") do q.breakable q.seplist metrics.each do |key, value| q.text "#{key} => #{value}" end end q.group(2, 'Metastruct: [', ']') do .pretty_print(q) end end end |
#root? ⇒ Boolean
254 255 256 |
# File 'lib/datadog/tracing/span_operation.rb', line 254 def root? parent_id == 0 end |
#set_error(e) ⇒ Object
295 296 297 298 |
# File 'lib/datadog/tracing/span_operation.rb', line 295 def set_error(e) @status = Metadata::Ext::Errors::STATUS (e) end |
#start(start_time = nil) ⇒ Object
202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/datadog/tracing/span_operation.rb', line 202 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
245 246 247 |
# File 'lib/datadog/tracing/span_operation.rb', line 245 def started? !@start_time.nil? end |
#stop(stop_time = nil, exception: nil) ⇒ Object
Mark the span stopped at the current time
steep:ignore:start Steep issue fixed in github.com/soutaro/steep/pull/1467
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/datadog/tracing/span_operation.rb', line 220 def stop(stop_time = nil, exception: 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, exception) self end |
#stopped? ⇒ Boolean
Return whether the duration is stopped or not.
250 251 252 |
# File 'lib/datadog/tracing/span_operation.rb', line 250 def stopped? !@end_time.nil? end |
#to_hash ⇒ Object
Return the hash representation of the current span.
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/datadog/tracing/span_operation.rb', line 306 def to_hash h = { error: @status, id: @id, meta: , metrics: metrics, metastruct: , 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.
301 302 303 |
# File 'lib/datadog/tracing/span_operation.rb', line 301 def to_s "SpanOperation(name:#{@name},sid:#{@id},tid:#{@trace_id},pid:#{@parent_id})" end |