Class: Yes::Core::OpenTelemetry::OtlSpan

Inherits:
Object
  • Object
show all
Defined in:
lib/yes/core/open_telemetry/otl_span.rb

Overview

Wraps OpenTelemetry span creation with SQL tracking support.

Examples:

span = OtlSpan.new(otl_data: OtlData.new(span_name: 'MySpan'), otl_tracer: tracer)
span.otl_span(arg1, arg2) { do_work }

Defined Under Namespace

Classes: OtlData

Constant Summary collapse

OUTCOME_ATTRIBUTE =

Span attribute that names the tolerated error a span ended with (see Yes::Core::OpenTelemetry::OtlSpan::OtlData#tolerated_errors).

'outcome'
RETRIES_ATTRIBUTE =

Span attribute with the number of retries a command needed before it settled.

'retries'
REVISION_CONFLICT =

A revision conflict is an optimistic-concurrency retry signal, not a failure: the command is re-run and almost always succeeds. Publishing spans tolerate it so the span status stays clean and the conflict is countable on its own.

{ PgEventstore::WrongExpectedRevisionError => 'revision_conflict' }.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(otl_data:, otl_tracer:) ⇒ OtlSpan

Returns a new instance of OtlSpan.

Parameters:

  • otl_data (OtlData) —

    span configuration

  • otl_tracer (Object) —

    OpenTelemetry tracer instance



58
59
60
61
# File 'lib/yes/core/open_telemetry/otl_span.rb', line 58

def initialize(otl_data:, otl_tracer:)
  @otl_data = otl_data
  @otl_tracer = otl_tracer
end

Instance Attribute Details

#otl_data ⇒ OtlData (readonly)

Returns span configuration.

Returns:



40
41
42
# File 'lib/yes/core/open_telemetry/otl_span.rb', line 40

def otl_data
  @otl_data
end

#otl_tracer ⇒ Object (readonly)

Returns OpenTelemetry tracer instance.

Returns:

  • (Object) —

    OpenTelemetry tracer instance



43
44
45
# File 'lib/yes/core/open_telemetry/otl_span.rb', line 43

def otl_tracer
  @otl_tracer
end

Class Method Details

.record_retries(retries) ⇒ void

This method returns an undefined value.

Stamps the number of retries a command needed on the span it is running in, so contention shows up per command and not only per publish attempt.

Parameters:

  • retries (Integer) —

    retries performed before the command settled



50
51
52
53
54
# File 'lib/yes/core/open_telemetry/otl_span.rb', line 50

def self.record_retries(retries)
  return if retries.zero? || Yes::Core.configuration.otl_tracer.nil?

  ::OpenTelemetry::Trace.current_span.set_attribute(RETRIES_ATTRIBUTE, retries)
end

Instance Method Details

#otl_span(*args, **kwargs) { ... } ⇒ Object

Creates a span and executes the given block within it.

A tolerated error (see Yes::Core::OpenTelemetry::OtlSpan::OtlData#tolerated_errors) is recorded on the span as an exception event and as the outcome attribute, but the span keeps a non-error status. The error is re-raised once the span has ended, so callers see exactly the same exception as before.

Parameters:

  • args (Array) —

    positional arguments passed to the links extractor

  • kwargs (Hash) —

    keyword arguments passed to the links extractor

Yields:

  • the block to execute within the span

Returns:

  • (Object) —

    the return value of the block



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/yes/core/open_telemetry/otl_span.rb', line 73

def otl_span(*args, **kwargs, &)
  parent_span = current_parent_span
  root_track_sql = root_track_sql?(parent_span)
  tolerated_error = nil

  result = otl_tracer.in_span(
    otl_data.span_name || 'UnknownName',
    links: otl_links(args, kwargs),
    kind: otl_data.span_kind,
    attributes: span_attributes(root_track_sql)
  ) do |span|
    run_block(parent_span, root_track_sql, &)
  rescue StandardError => e
    tolerated_error = tolerate(span, e)
    nil
  end

  raise tolerated_error if tolerated_error

  result
end