Module: Temporalio::Contrib::OpenTelemetry::Workflow

Defined in:
lib/temporalio/contrib/open_telemetry.rb

Overview

Contains workflow methods that can be used for OpenTelemetry.

Class Method Summary collapse

Class Method Details

.completed_span(name, attributes: {}, links: nil, kind: nil, exception: nil, even_during_replay: false) ⇒ OpenTelemetry::Trace::Span?

Note:

WARNING: It is UNSAFE to rely on the result of this method as it may be different/absent on replay.

Create a completed span only if not replaying (or ‘even_during_replay` is true).

Parameters:

  • name (String)

    Span name.

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

    Span attributes. These will have workflow and run ID automatically added.

  • links (Array, nil) (defaults to: nil)

    Span links.

  • kind (Symbol, nil) (defaults to: nil)

    Span kind.

  • exception (Exception, nil) (defaults to: nil)

    Exception to record on the span.

  • even_during_replay (Boolean) (defaults to: false)

    Set to true to record this span even during replay. Most users should never set this.

Returns:

  • (OpenTelemetry::Trace::Span, nil)

    Span if one was created. WARNING: It is UNSAFE to use this value.



443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'lib/temporalio/contrib/open_telemetry.rb', line 443

def self.completed_span(
  name,
  attributes: {},
  links: nil,
  kind: nil,
  exception: nil,
  even_during_replay: false
)
  # Get root interceptor, which also checks if in workflow
  root = Temporalio::Workflow.storage[:__temporal_opentelemetry_tracing_interceptor] #: TracingInterceptor?
  raise 'Tracing interceptor not configured' unless root

  # Do nothing if replaying and not wanted during replay
  return nil if !even_during_replay && Temporalio::Workflow::Unsafe.replaying?

  # If there is no span on the context and the user hasn't opted in to always creating, do not create. This
  # prevents orphans if there was no span originally created from the client start-workflow call.
  if ::OpenTelemetry::Trace.current_span == ::OpenTelemetry::Trace::Span::INVALID &&
     !root._always_create_workflow_spans
    return nil
  end

  # Create attributes, adding user-defined ones
  attributes = { 'temporalWorkflowID' => Temporalio::Workflow.info.workflow_id,
                 'temporalRunID' => Temporalio::Workflow.info.run_id }.merge(attributes)

  time = Temporalio::Workflow.now.dup
  # Disable durable scheduler because 1) synchronous/non-batch span processors in OTel use network (though could
  # have just used Unafe.io_enabled for this if not for the next point) and 2) OTel uses Ruby Timeout which we
  # don't want to use durable timers.
  Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
    span = root.tracer.start_span(name, attributes:, links:, start_timestamp: time, kind:) # steep:ignore
    # Record exception and set status if present
    if exception
      span.record_exception(exception)
      # Only set the status if it is not a benign application error
      unless exception.is_a?(Error::ApplicationError) &&
             exception.category == Error::ApplicationError::Category::BENIGN
        span.status = ::OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{exception.class}")
      end
    end
    # Finish the span (returns self)
    span.finish(end_timestamp: time)
  end
end

.with_completed_span(name, attributes: {}, links: nil, kind: nil, exception: nil, even_during_replay: false) { ... } ⇒ Object

Create a completed span and execute block with the span set on the context.

Parameters:

  • name (String)

    Span name.

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

    Span attributes. These will have workflow and run ID automatically added.

  • links (Array, nil) (defaults to: nil)

    Span links.

  • kind (Symbol, nil) (defaults to: nil)

    Span kind.

  • exception (Exception, nil) (defaults to: nil)

    Exception to record on the span.

  • even_during_replay (Boolean) (defaults to: false)

    Set to true to record this span even during replay. Most users should never set this.

Yields:

  • Block to call. It is UNSAFE to expect any parameters in this block.

Returns:

  • (Object)

    Result of the block.



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/temporalio/contrib/open_telemetry.rb', line 412

def self.with_completed_span(
  name,
  attributes: {},
  links: nil,
  kind: nil,
  exception: nil,
  even_during_replay: false
)
  span = completed_span(name, attributes:, links:, kind:, exception:, even_during_replay:)
  if span
    ::OpenTelemetry::Trace.with_span(span) do # rubocop:disable Style/ExplicitBlockArgument
      # Yield with no parameters
      yield
    end
  else
    yield
  end
end