diff --git a/temporalio/lib/temporalio/contrib/open_telemetry.rb b/temporalio/lib/temporalio/contrib/open_telemetry.rb index a894e300..e39886f3 100644 --- a/temporalio/lib/temporalio/contrib/open_telemetry.rb +++ b/temporalio/lib/temporalio/contrib/open_telemetry.rb @@ -455,13 +455,12 @@ def self.completed_span( # Create span, which has to be done with illegal call disabling because OTel asks for full exception message # which uses error highlighting and such which accesses File#path Temporalio::Workflow::Unsafe.illegal_call_tracing_disabled do - time = Temporalio::Workflow.now - timestamp = (time.to_i * 1_000_000_000) + time.nsec - span = root.tracer.start_span(name, attributes:, links:, start_timestamp: timestamp, kind:) # steep:ignore + time = Temporalio::Workflow.now.dup + span = root.tracer.start_span(name, attributes:, links:, start_timestamp: time, kind:) # steep:ignore # Record exception if present span.record_exception(exception) if exception # Finish the span (returns self) - span.finish(end_timestamp: timestamp) + span.finish(end_timestamp: time) end end end diff --git a/temporalio/test/contrib/open_telemetry_test.rb b/temporalio/test/contrib/open_telemetry_test.rb index fed1eaa1..bc9f2c3e 100644 --- a/temporalio/test/contrib/open_telemetry_test.rb +++ b/temporalio/test/contrib/open_telemetry_test.rb @@ -143,6 +143,7 @@ def trace( tracer_and_exporter: init_tracer_and_exporter, always_create_workflow_spans: false, check_root: true, + append_finished_spans_to: nil, & ) tracer, exporter = tracer_and_exporter @@ -160,6 +161,7 @@ def trace( end # Convert spans, confirm there is only the outer, and return children + append_finished_spans_to&.append(*exporter.finished_spans) spans = ExpectedSpan.from_span_data(exporter.finished_spans) if check_root assert_equal 1, spans.size @@ -174,9 +176,10 @@ def trace_workflow( start_with_untraced_client: false, always_create_workflow_spans: false, check_root: true, + append_finished_spans_to: nil, & ) - trace(tracer_and_exporter:, always_create_workflow_spans:, check_root:) do |client| + trace(tracer_and_exporter:, always_create_workflow_spans:, check_root:, append_finished_spans_to:) do |client| # Must capture and attach outer context outer_context = OpenTelemetry::Context.current attach_token = nil @@ -318,7 +321,8 @@ def test_handler_failures def test_activity exp_root = ExpectedSpan.new(name: 'root') - act_root = trace_workflow(:wait_on_signal) do |handle| + raw_finished_spans = [] + act_root = trace_workflow(:wait_on_signal, append_finished_spans_to: raw_finished_spans) do |handle| exp_cl_attrs = { 'temporalWorkflowID' => handle.id } exp_run_attrs = exp_cl_attrs.merge({ 'temporalRunID' => handle.result_run_id }) exp_start_wf = exp_root.add_child(name: 'StartWorkflow:TestWorkflow', attributes: exp_cl_attrs) @@ -375,6 +379,11 @@ def test_activity handle.execute_update(TestWorkflow.update, :call_local_activity, id: 'my-update-id2') end assert_equal exp_root.to_s_indented, act_root.to_s_indented + + # Confirm the custom in-workflow span time is within 5m of the given time + custom_span = raw_finished_spans.find { |span| span.name == 'custom-workflow-span' } || raise + assert_equal custom_span.start_timestamp, custom_span.end_timestamp + assert_in_delta Time.now, Time.at(0, custom_span.start_timestamp, :nanosecond), 5 * 60.0 end def test_client_fail diff --git a/temporalio/test/sig/contrib/open_telemetry_test.rbs b/temporalio/test/sig/contrib/open_telemetry_test.rbs index 9043264d..b1eae7f7 100644 --- a/temporalio/test/sig/contrib/open_telemetry_test.rbs +++ b/temporalio/test/sig/contrib/open_telemetry_test.rbs @@ -4,14 +4,16 @@ module Contrib def trace: ( ?tracer_and_exporter: [untyped, untyped], ?always_create_workflow_spans: bool, - ?check_root: bool + ?check_root: bool, + ?append_finished_spans_to: Array[untyped]? ) { (Temporalio::Client) -> void } -> untyped def trace_workflow: ( Symbol scenario, ?tracer_and_exporter: [untyped, untyped], ?start_with_untraced_client: bool, ?always_create_workflow_spans: bool, - ?check_root: bool + ?check_root: bool, + ?append_finished_spans_to: Array[untyped]? ) { (Temporalio::Client::WorkflowHandle) -> void } -> untyped class ExpectedSpan