@@ -149,10 +149,10 @@ def trace(
149149 context = call_context
150150 active_trace = context . active_trace
151151 trace = if continue_from || active_trace . nil?
152- start_trace ( continue_from : continue_from )
153- else
154- active_trace
155- end
152+ start_trace ( continue_from : continue_from )
153+ else
154+ active_trace
155+ end
156156 rescue => e
157157 logger . debug { "Failed to trace: #{ e } " }
158158
@@ -241,10 +241,21 @@ def active_correlation(key = nil)
241241 trace . to_correlation
242242 end
243243
244- # Setup a new trace to continue from where another
244+ # Setup a new trace execution context to continue from where another
245245 # trace left off.
246+ # This is useful to continue distributed or async traces.
247+ #
248+ # The first span created in the restored context is a direct child of the
249+ # active span from when the {Datadog::Tracing::TraceDigest} was created.
250+ #
251+ # When no block is given, the trace context is restored in the current thread.
252+ # It remains active until the first span created in this restored context is finished.
253+ # After that, if a new span is created, it start a new, unrelated trace.
246254 #
247- # Used to continue distributed or async traces.
255+ # When a block is given, the trace context is restored inside the block execution.
256+ # It remains active until the block ends, even when the first span created inside
257+ # the block finishes. This means that multiple spans can be direct children of the
258+ # active span from when the {Datadog::Tracing::TraceDigest} was created.
248259 #
249260 # @param [Datadog::Tracing::TraceDigest] digest continue from the {Datadog::Tracing::TraceDigest}.
250261 # @param [Thread] key Thread to retrieve trace from. Defaults to current thread. For internal use only.
@@ -260,13 +271,32 @@ def continue_trace!(digest, key = nil, &block)
260271 # Start a new trace from the digest
261272 context = call_context ( key )
262273 original_trace = active_trace ( key )
263- trace = start_trace ( continue_from : digest )
274+ # When we want the trace to be bound to a block, we cannot let
275+ # it auto finish when the local root span finishes. This would
276+ # create mutiple traces inside the block. Instead, we'll
277+ # expliclity finish the trace after the block finishes.
278+ auto_finish = !block
279+
280+ trace = start_trace ( continue_from : digest , auto_finish : auto_finish )
264281
265282 # If block hasn't been given; we need to manually deactivate
266283 # this trace. Subscribe to the trace finished event to do this.
267284 subscribe_trace_deactivation! ( context , trace , original_trace ) unless block
268285
269- context . activate! ( trace , &block )
286+ if block
287+ # When a block is given, the trace will be active until the block finishes.
288+ context . activate! ( trace ) do
289+ yield
290+ ensure # We have to flush even when an error occurs
291+ # On block completion, force the trace to finish and flush its finished spans.
292+ # Unfinished spans are lost as the {TraceOperation} has ended.
293+ trace . finish!
294+ flush_trace ( trace )
295+ end
296+ else
297+ # Otherwise, the trace will be bound to the current thread after this point
298+ context . activate! ( trace )
299+ end
270300 end
271301
272302 # Sample a span, tagging the trace as appropriate.
@@ -329,15 +359,15 @@ def call_context(key = nil)
329359 @provider . context ( key )
330360 end
331361
332- def build_trace ( digest = nil )
362+ def build_trace ( digest , auto_finish )
333363 # Resolve hostname if configured
334364 hostname = Core ::Environment ::Socket . hostname if Datadog . configuration . tracing . report_hostname
335- hostname = ( hostname && !hostname . empty? ) ? hostname : nil
365+ hostname = hostname && !hostname . empty? ? hostname : nil
336366
337367 if digest
338368 sampling_priority = if propagate_sampling_priority? ( upstream_tags : digest . trace_distributed_tags )
339- digest . trace_sampling_priority
340- end
369+ digest . trace_sampling_priority
370+ end
341371 TraceOperation . new (
342372 logger : logger ,
343373 hostname : hostname ,
@@ -353,7 +383,8 @@ def build_trace(digest = nil)
353383 trace_state_unknown_fields : digest . trace_state_unknown_fields ,
354384 remote_parent : digest . span_remote ,
355385 tracer : self ,
356- baggage : digest . baggage
386+ baggage : digest . baggage ,
387+ auto_finish : auto_finish
357388 )
358389 else
359390 TraceOperation . new (
@@ -362,13 +393,13 @@ def build_trace(digest = nil)
362393 profiling_enabled : profiling_enabled ,
363394 apm_tracing_enabled : apm_tracing_enabled ,
364395 remote_parent : false ,
365- tracer : self
396+ tracer : self ,
397+ auto_finish : auto_finish
366398 )
367399 end
368400 end
369401 # rubocop:enable Metrics/MethodLength
370402
371- # rubocop:disable Metrics/MethodLength
372403 def bind_trace_events! ( trace_op )
373404 events = trace_op . send ( :events )
374405
@@ -387,13 +418,12 @@ def bind_trace_events!(trace_op)
387418 flush_trace ( event_trace_op )
388419 end
389420 end
390- # rubocop:enable Metrics/MethodLength
391421
392422 # Creates a new TraceOperation, with events bounds to this Tracer instance.
393423 # @return [TraceOperation]
394- def start_trace ( continue_from : nil )
424+ def start_trace ( continue_from : nil , auto_finish : true )
395425 # Build a new trace using digest if provided.
396- trace = build_trace ( continue_from )
426+ trace = build_trace ( continue_from , auto_finish )
397427
398428 # Bind trace events: sample trace, set default service, flush spans.
399429 bind_trace_events! ( trace )
@@ -402,7 +432,6 @@ def start_trace(continue_from: nil)
402432 end
403433
404434 # rubocop:disable Lint/UnderscorePrefixedVariableName
405- # rubocop:disable Metrics/MethodLength
406435 def start_span (
407436 name ,
408437 continue_from : nil ,
@@ -454,18 +483,17 @@ def start_span(
454483 span
455484 end
456485 end
457- # rubocop:enable Lint/UnderscorePrefixedVariableName
458- # rubocop:enable Metrics/MethodLength
459486
487+ # rubocop:enable Lint/UnderscorePrefixedVariableName
460488 def resolve_tags ( tags , service )
461489 merged_tags = if @tags . any? && tags
462- # Combine default tags with provided tags,
463- # preferring provided tags.
464- @tags . merge ( tags )
465- else
466- # Use provided tags or default tags if none.
467- tags || @tags . dup
468- end
490+ # Combine default tags with provided tags,
491+ # preferring provided tags.
492+ @tags . merge ( tags )
493+ else
494+ # Use provided tags or default tags if none.
495+ tags || @tags . dup
496+ end
469497 # Remove version tag if service is not the default service
470498 if merged_tags . key? ( Core ::Environment ::Ext ::TAG_VERSION ) && service && service != @default_service
471499 merged_tags . delete ( Core ::Environment ::Ext ::TAG_VERSION )
0 commit comments