diff --git a/lib/datadog/opentracer/tracer.rb b/lib/datadog/opentracer/tracer.rb index a0c58319a4..478f70befa 100644 --- a/lib/datadog/opentracer/tracer.rb +++ b/lib/datadog/opentracer/tracer.rb @@ -151,12 +151,10 @@ def start_span( tags: tags || {} ) - # Build or extend the OpenTracer::SpanContext - span_context = if parent_span_context - SpanContextFactory.clone(span_context: parent_span_context) - else - SpanContextFactory.build(datadog_context: datadog_context) - end + span_context = SpanContextFactory.build( + datadog_context: datadog_context || datadog_tracer.send(:call_context), + baggage: parent_span_context ? parent_span_context.baggage.dup : {} + ) # Wrap the Datadog span and OpenTracer::Span context in a OpenTracer::Span Span.new(datadog_span: datadog_span, span_context: span_context) diff --git a/spec/datadog/opentracer/propagation_integration_spec.rb b/spec/datadog/opentracer/propagation_integration_spec.rb index a4eff6a593..0135b96502 100644 --- a/spec/datadog/opentracer/propagation_integration_spec.rb +++ b/spec/datadog/opentracer/propagation_integration_spec.rb @@ -17,14 +17,6 @@ datadog_tracer.shutdown! end - def sampling_priority_metric(span) - span.get_metric(Datadog::OpenTracer::TextMapPropagator::TAG_SAMPLING_PRIORITY) - end - - def origin_tag(span) - span.get_tag(Datadog::OpenTracer::TextMapPropagator::TAG_ORIGIN) - end - describe 'via OpenTracing::FORMAT_TEXT_MAP' do def baggage_to_carrier_format(baggage) baggage.map { |k, v| [Datadog::OpenTracer::TextMapPropagator::BAGGAGE_PREFIX + k, v] }.to_h @@ -120,69 +112,91 @@ def baggage_to_carrier_format(baggage) end context 'in a round-trip' do - let(:sender_span_name) { 'operation.sender' } - let(:sender_datadog_span) { datadog_spans.last } - let(:receiver_datadog_span) { datadog_spans.first } - let(:receiver_span_name) { 'operation.receiver' } - let(:baggage) { { 'account_name' => 'acme' } } - let(:carrier) { {} } - let(:another_carrier) { {} } - let(:datadog_sender_trace) { datadog_traces.last } - let(:datadog_receiver_trace) { datadog_traces.first } + let(:origin_span_name) { 'operation.origin' } + let(:origin_datadog_trace) { datadog_traces.find { |x| x.name == origin_span_name } } + let(:origin_datadog_span) { datadog_spans.find { |x| x.name == origin_span_name } } - before do - tracer.start_active_span(sender_span_name) do |sender_scope| - sender_scope.span.context.datadog_context.active_trace.sampling_priority = 1 - sender_scope.span.context.datadog_context.active_trace.origin = 'synthetics' - baggage.each { |k, v| sender_scope.span.set_baggage_item(k, v) } - tracer.inject( - sender_scope.span.context, - OpenTracing::FORMAT_TEXT_MAP, - carrier - ) + let(:intermediate_span_name) { 'operation.intermediate' } + let(:intermediate_datadog_trace) { datadog_traces.find { |x| x.name == intermediate_span_name } } + let(:intermediate_datadog_span) { datadog_spans.find { |x| x.name == intermediate_span_name } } - span_context = tracer.extract(OpenTracing::FORMAT_TEXT_MAP, carrier) - tracer.start_active_span(receiver_span_name, child_of: span_context) do |receiver_scope| - @receiver_scope = receiver_scope - # Do some work. + let(:destination_span_name) { 'operation.destination' } + let(:destination_datadog_trace) { datadog_traces.find { |x| x.name == destination_span_name } } + let(:destination_datadog_span) { datadog_spans.find { |x| x.name == destination_span_name } } - tracer.inject(receiver_scope.span.context, OpenTracing::FORMAT_TEXT_MAP, another_carrier) + let(:baggage) { { 'account_name' => 'acme' } } + + before do + tracer.start_active_span(origin_span_name) do |origin_scope| + origin_datadog_context = origin_scope.span.context.datadog_context + origin_datadog_context.active_trace.sampling_priority = 1 + origin_datadog_context.active_trace.origin = 'synthetics' + baggage.each { |k, v| origin_scope.span.set_baggage_item(k, v) } + + @origin_carrier = {}.tap do |c| + tracer.inject(origin_scope.span.context, OpenTracing::FORMAT_TEXT_MAP, c) + end + origin_datadog_context.activate!(nil) do + tracer.start_active_span( + intermediate_span_name, + child_of: tracer.extract(OpenTracing::FORMAT_TEXT_MAP, @origin_carrier) + ) do |intermediate_scope| + @intermediate_scope = intermediate_scope + + @intermediate_carrier = {}.tap do |c| + tracer.inject(intermediate_scope.span.context, OpenTracing::FORMAT_TEXT_MAP, c) + end + + tracer.start_active_span( + destination_span_name, + child_of: tracer.extract(OpenTracing::FORMAT_TEXT_MAP, @intermediate_carrier) + ) do |destination_scope| + @destination_scope = destination_scope + # Do something + end + end end end end - it { expect(datadog_spans).to have(2).items } + it { expect(datadog_traces).to have(3).items } + it { expect(datadog_spans).to have(3).items } - it { expect(datadog_sender_trace.sampling_priority).to eq(1) } - it { expect(datadog_sender_trace.origin).to eq('synthetics') } - it { expect(sender_datadog_span.name).to eq(sender_span_name) } - it { expect(sender_datadog_span.finished?).to be(true) } - it { expect(sender_datadog_span.parent_id).to eq(0) } + it { expect(origin_datadog_trace.sampling_priority).to eq(1) } + it { expect(origin_datadog_trace.origin).to eq('synthetics') } + it { expect(origin_datadog_span.finished?).to be(true) } + it { expect(origin_datadog_span.parent_id).to eq(0) } - it { expect(datadog_receiver_trace.sampling_priority).to eq(1) } - it { expect(datadog_receiver_trace.origin).to eq('synthetics') } - it { expect(receiver_datadog_span.name).to eq(receiver_span_name) } - it { expect(receiver_datadog_span.finished?).to be(true) } - it { expect(receiver_datadog_span.trace_id).to eq(sender_datadog_span.trace_id) } - it { expect(receiver_datadog_span.parent_id).to eq(sender_datadog_span.span_id) } - it { expect(@receiver_scope.span.context.baggage).to include(baggage) } + it { expect(intermediate_datadog_trace.sampling_priority).to eq(1) } + it { expect(intermediate_datadog_trace.origin).to eq('synthetics') } + it { expect(intermediate_datadog_span.finished?).to be(true) } + it { expect(intermediate_datadog_span.trace_id).to eq(origin_datadog_span.trace_id) } + it { expect(intermediate_datadog_span.parent_id).to eq(origin_datadog_span.span_id) } + it { expect(@intermediate_scope.span.context.baggage).to include(baggage) } + + it { expect(destination_datadog_trace.sampling_priority).to eq(1) } + it { expect(destination_datadog_trace.origin).to eq('synthetics') } + it { expect(destination_datadog_span.finished?).to be(true) } + it { expect(destination_datadog_span.trace_id).to eq(intermediate_datadog_span.trace_id) } + it { expect(destination_datadog_span.parent_id).to eq(intermediate_datadog_span.span_id) } + it { expect(@destination_scope.span.context.baggage).to include(baggage) } it do - expect(carrier).to include( - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_TRACE_ID => a_kind_of(Integer), - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_PARENT_ID => a_kind_of(Integer), - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_SAMPLING_PRIORITY => a_kind_of(Integer), - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_ORIGIN => a_kind_of(String), + expect(@origin_carrier).to include( + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_TRACE_ID => origin_datadog_span.trace_id, + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_PARENT_ID => origin_datadog_span.span_id, + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_SAMPLING_PRIORITY => 1, + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_ORIGIN => 'synthetics', 'ot-baggage-account_name' => 'acme' ) end it do - expect(another_carrier).to include( - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_TRACE_ID => a_kind_of(Integer), - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_PARENT_ID => a_kind_of(Integer), - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_SAMPLING_PRIORITY => a_kind_of(Integer), - Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_ORIGIN => a_kind_of(String), + expect(@intermediate_carrier).to include( + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_TRACE_ID => intermediate_datadog_span.trace_id, + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_PARENT_ID => intermediate_datadog_span.span_id, + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_SAMPLING_PRIORITY => 1, + Datadog::OpenTracer::TextMapPropagator::HTTP_HEADER_ORIGIN => 'synthetics', 'ot-baggage-account_name' => 'acme' ) end @@ -290,12 +304,17 @@ def baggage_to_carrier_format(baggage) end context 'in a round-trip' do - let(:sender_span_name) { 'operation.sender' } - let(:sender_datadog_span) { datadog_spans.last } - let(:receiver_datadog_span) { datadog_spans.first } - let(:receiver_span_name) { 'operation.receiver' } - let(:datadog_sender_trace) { datadog_traces.last } - let(:datadog_receiver_trace) { datadog_traces.first } + let(:origin_span_name) { 'operation.origin' } + let(:origin_datadog_trace) { datadog_traces.find { |x| x.name == origin_span_name } } + let(:origin_datadog_span) { datadog_spans.find { |x| x.name == origin_span_name } } + + let(:intermediate_span_name) { 'operation.intermediate' } + let(:intermediate_datadog_trace) { datadog_traces.find { |x| x.name == intermediate_span_name } } + let(:intermediate_datadog_span) { datadog_spans.find { |x| x.name == intermediate_span_name } } + + let(:destination_span_name) { 'operation.destination' } + let(:destination_datadog_trace) { datadog_traces.find { |x| x.name == destination_span_name } } + let(:destination_datadog_span) { datadog_spans.find { |x| x.name == destination_span_name } } # NOTE: If these baggage names include either dashes or uppercase characters # they will not make a round-trip with the same key format. They will @@ -305,57 +324,75 @@ def baggage_to_carrier_format(baggage) let(:baggage) { { 'account_name' => 'acme' } } before do - tracer.start_active_span(sender_span_name) do |sender_scope| - sender_scope.span.context.datadog_context.active_trace.sampling_priority = 1 - sender_scope.span.context.datadog_context.active_trace.origin = 'synthetics' - baggage.each { |k, v| sender_scope.span.set_baggage_item(k, v) } + tracer.start_active_span(origin_span_name) do |origin_scope| + origin_datadog_context = origin_scope.span.context.datadog_context + origin_datadog_context.active_trace.sampling_priority = 1 + origin_datadog_context.active_trace.origin = 'synthetics' - @carrier = {}.tap do |c| - tracer.inject(sender_scope.span.context, OpenTracing::FORMAT_RACK, c) - end + baggage.each { |k, v| origin_scope.span.set_baggage_item(k, v) } - span_context = tracer.extract(OpenTracing::FORMAT_RACK, carrier_to_rack_format(@carrier)) - tracer.start_active_span(receiver_span_name, child_of: span_context) do |receiver_scope| - @receiver_scope = receiver_scope - # Do some work. + @origin_carrier = {}.tap do |c| + tracer.inject(origin_scope.span.context, OpenTracing::FORMAT_RACK, c) + end - @another_carrier = {}.tap do |c| - tracer.inject(receiver_scope.span.context, OpenTracing::FORMAT_RACK, c) + origin_datadog_context.activate!(nil) do + tracer.start_active_span( + intermediate_span_name, + child_of: tracer.extract(OpenTracing::FORMAT_RACK, carrier_to_rack_format(@origin_carrier)) + ) do |intermediate_scope| + @intermediate_scope = intermediate_scope + + @intermediate_carrier = {}.tap do |c| + tracer.inject(intermediate_scope.span.context, OpenTracing::FORMAT_RACK, c) + end + + tracer.start_active_span( + destination_span_name, + child_of: tracer.extract(OpenTracing::FORMAT_RACK, carrier_to_rack_format(@intermediate_carrier)) + ) do |destination_scope| + @destination_scope = destination_scope + # Do something + end end end end end - it { expect(datadog_spans).to have(2).items } + it { expect(datadog_traces).to have(3).items } + it { expect(datadog_spans).to have(3).items } + + it { expect(origin_datadog_trace.sampling_priority).to eq(1) } + it { expect(origin_datadog_span.finished?).to be(true) } + it { expect(origin_datadog_span.parent_id).to eq(0) } - it { expect(datadog_sender_trace.sampling_priority).to eq(1) } - it { expect(sender_datadog_span.name).to eq(sender_span_name) } - it { expect(sender_datadog_span.finished?).to be(true) } - it { expect(sender_datadog_span.parent_id).to eq(0) } + it { expect(intermediate_datadog_trace.sampling_priority).to eq(1) } + it { expect(intermediate_datadog_span.finished?).to be(true) } + it { expect(intermediate_datadog_span.trace_id).to eq(origin_datadog_span.trace_id) } + it { expect(intermediate_datadog_span.parent_id).to eq(origin_datadog_span.span_id) } + it { expect(@intermediate_scope.span.context.baggage).to include(baggage) } - it { expect(datadog_receiver_trace.sampling_priority).to eq(1) } - it { expect(receiver_datadog_span.name).to eq(receiver_span_name) } - it { expect(receiver_datadog_span.finished?).to be(true) } - it { expect(receiver_datadog_span.trace_id).to eq(sender_datadog_span.trace_id) } - it { expect(receiver_datadog_span.parent_id).to eq(sender_datadog_span.span_id) } - it { expect(@receiver_scope.span.context.baggage).to include(baggage) } + it { expect(destination_datadog_trace.sampling_priority).to eq(1) } + it { expect(destination_datadog_span.finished?).to be(true) } + it { expect(destination_datadog_span.trace_id).to eq(intermediate_datadog_span.trace_id) } + it { expect(destination_datadog_span.parent_id).to eq(intermediate_datadog_span.span_id) } + it { expect(@destination_scope.span.context.baggage).to include(baggage) } it do - expect(@carrier).to include( - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_TRACE_ID => a_kind_of(String), - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_PARENT_ID => a_kind_of(String), - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_SAMPLING_PRIORITY => a_kind_of(String), - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_ORIGIN => a_kind_of(String), + expect(@origin_carrier).to include( + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_TRACE_ID => origin_datadog_span.trace_id.to_s, + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_PARENT_ID => origin_datadog_span.span_id.to_s, + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_SAMPLING_PRIORITY => '1', + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_ORIGIN => 'synthetics', 'ot-baggage-account_name' => 'acme' ) end it do - expect(@another_carrier).to include( - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_TRACE_ID => a_kind_of(String), - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_PARENT_ID => a_kind_of(String), - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_SAMPLING_PRIORITY => a_kind_of(String), - Datadog::OpenTracer::RackPropagator::HTTP_HEADER_ORIGIN => a_kind_of(String), + expect(@intermediate_carrier).to include( + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_TRACE_ID => intermediate_datadog_span.trace_id.to_s, + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_PARENT_ID => intermediate_datadog_span.span_id.to_s, + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_SAMPLING_PRIORITY => '1', + Datadog::OpenTracer::RackPropagator::HTTP_HEADER_ORIGIN => 'synthetics', 'ot-baggage-account_name' => 'acme' ) end