Skip to content

Commit

Permalink
Merge pull request #2879 from DataDog/tonycthsu/fix-distributed-traci…
Browse files Browse the repository at this point in the history
…ng-extraction

Use first valid extracted style for distributed tracing
  • Loading branch information
TonyCTHsu authored Sep 1, 2023
2 parents 737db7b + 38de428 commit 0318c77
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 83 deletions.
46 changes: 13 additions & 33 deletions lib/datadog/tracing/distributed/propagation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ class Propagation
# @param propagation_styles [Hash<String,Object>]
def initialize(propagation_styles:)
@propagation_styles = propagation_styles
# We need to make sure propagation_style option is evaluated.
# Our options are lazy evaluated and it happens that propagation_style has the on_set callback
# that affect Datadog.configuration.tracing.distributed_tracing.propagation_inject_style and
# Datadog.configuration.tracing.distributed_tracing.propagation_extract_style
# By calling it here, we make sure if the customers has set any value either via code or ENV variable is applied.
::Datadog.configuration.tracing.distributed_tracing.propagation_style
end

# inject! populates the env with span ID, trace ID and sampling priority
Expand Down Expand Up @@ -72,8 +78,10 @@ def inject!(digest, data)
#
# @param data [Hash]
def extract(data)
trace_digest = nil
dd_trace_digest = nil
return unless data
return if data.empty?

extracted_trace_digest = nil

::Datadog.configuration.tracing.distributed_tracing.propagation_extract_style.each do |style|
propagator = @propagation_styles[style]
Expand All @@ -83,42 +91,14 @@ def extract(data)
extracted_trace_digest = propagator.extract(data)
rescue => e
::Datadog.logger.error(
'Error extracting distributed trace data. ' \
"Cause: #{e} Location: #{Array(e.backtrace).first}"
"Error extracting distributed trace data. Cause: #{e} Location: #{Array(e.backtrace).first}"
)
end

# Skip if no valid data was found
next if extracted_trace_digest.nil?

# Keep track of the Datadog extracted digest, we want to return it if we have it.
if extracted_trace_digest && style == Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG
dd_trace_digest = extracted_trace_digest
end

# No previously extracted trace data, use the one we just extracted
if trace_digest.nil?
trace_digest = extracted_trace_digest
else
unless trace_digest.trace_id == extracted_trace_digest.trace_id \
&& trace_digest.span_id == extracted_trace_digest.span_id
# We have two mismatched propagation contexts
::Datadog.logger.debug do
'Cannot extract distributed trace data: extracted styles differ, ' \
"#{trace_digest.trace_id} != #{extracted_trace_digest.trace_id} && " \
"#{trace_digest.span_id} != #{extracted_trace_digest.span_id}"
end

# It's safer to create a new context than to attach ourselves to the wrong context
return TraceDigest.new # Early return from the whole method
end
end
break if extracted_trace_digest
end

# Return the extracted trace digest if we found one or else a new empty digest.
# Always return the Datadog trace digest if one exists since it has more
# information than the B3 digest, e.g. origin, priority sampling values.
dd_trace_digest || trace_digest || nil
extracted_trace_digest
end
end
end
Expand Down
124 changes: 74 additions & 50 deletions spec/datadog/tracing/distributed/propagation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,16 @@
subject(:extract) { propagator.extract(data) }
let(:trace_digest) { extract }

context 'given empty data' do
context 'given `nil`' do
let(:data) { nil }
it { is_expected.to be nil }
end

context 'given empty hash' do
let(:data) { {} }
it { is_expected.to be nil }
end

context 'given an data containing' do
context 'datadog trace id and parent id' do
let(:data) do
Expand Down Expand Up @@ -323,24 +328,6 @@
end
end
end

context 'with mismatched values' do
let(:data) do
{
prepare_key['x-datadog-trace-id'] => '7',
prepare_key['x-datadog-parent-id'] => '8',
prepare_key['x-b3-traceid'] => '00ef01',
prepare_key['x-b3-spanid'] => '011ef0'
}
end

it do
expect(trace_digest).to be_a_kind_of(Datadog::Tracing::TraceDigest)
expect(trace_digest.span_id).to be_nil
expect(trace_digest.trace_id).to be_nil
expect(trace_digest.trace_sampling_priority).to be nil
end
end
end

context 'datadog, b3, and b3 single header' do
Expand Down Expand Up @@ -381,26 +368,6 @@
expect(trace_digest.trace_sampling_priority).to eq(1)
end
end

context 'with mismatched values' do
let(:data) do
# DEV: We only need 1 to be mismatched
{
prepare_key['x-datadog-trace-id'] => '7',
prepare_key['x-datadog-parent-id'] => '8',
prepare_key['x-b3-traceid'] => '00ef01',
prepare_key['x-b3-spanid'] => '011ef0',
prepare_key['b3'] => '00ef01-011ef0'
}
end

it do
expect(trace_digest).to be_a_kind_of(Datadog::Tracing::TraceDigest)
expect(trace_digest.span_id).to be_nil
expect(trace_digest.trace_id).to be_nil
expect(trace_digest.trace_sampling_priority).to be nil
end
end
end

context 'datadog, and b3 single header' do
Expand Down Expand Up @@ -436,21 +403,78 @@
expect(trace_digest.trace_sampling_priority).to eq(1)
end
end
end

context 'with mismatched values' do
let(:data) do
{
prepare_key['x-datadog-trace-id'] => '7',
prepare_key['x-datadog-parent-id'] => '8',
prepare_key['b3'] => '00ef01-011ef0'
}
context 'when conflict across different extractions' do
let(:datadog_trace_id) { 0xabcdef }
let(:b3_multi_trace_id) { 0x123456 }
let(:b3_trace_id) { 0xfedcba }
let(:span_id) { 0xfffffff }
let(:data) do
{
prepare_key['x-datadog-trace-id'] => datadog_trace_id.to_s(10),
prepare_key['x-datadog-parent-id'] => span_id.to_s(10),
prepare_key['x-b3-traceid'] => b3_multi_trace_id.to_s(16),
prepare_key['x-b3-spanid'] => span_id.to_s(16),
prepare_key['b3'] => "#{b3_trace_id.to_s(16)}-#{span_id.to_s(16)}"
}
end

after do
Datadog.configuration.reset!
end

context "when extraction styles ['Datadog', 'b3multi', 'b3']" do
before do
Datadog.configure do |c|
c.tracing.distributed_tracing.propagation_extract_style = [
'Datadog',
'b3multi',
'b3',
]
end
end

it do
it 'returns trace digest from `Datadog` extraction' do
expect(trace_digest).to be_a_kind_of(Datadog::Tracing::TraceDigest)
expect(trace_digest.span_id).to be nil
expect(trace_digest.trace_id).to be nil
expect(trace_digest.trace_sampling_priority).to be nil
expect(trace_digest.trace_id).to eq(datadog_trace_id)
expect(trace_digest.span_id).to eq(0xfffffff)
end
end

context "when extraction styles ['b3multi', 'b3', 'Datadog']" do
before do
Datadog.configure do |c|
c.tracing.distributed_tracing.propagation_extract_style = [
'b3multi',
'b3',
'Datadog',
]
end
end

it 'returns trace digest from `b3multi` extraction' do
expect(trace_digest).to be_a_kind_of(Datadog::Tracing::TraceDigest)
expect(trace_digest.trace_id).to eq(b3_multi_trace_id)
expect(trace_digest.span_id).to eq(0xfffffff)
end
end

context "when extraction styles ['b3', 'Datadog', 'b3multi']" do
before do
Datadog.configure do |c|
c.tracing.distributed_tracing.propagation_extract_style = [
'b3',
'Datadog',
'b3multi',
]
end
end

it 'returns trace digest from `b3` extraction' do
expect(trace_digest).to be_a_kind_of(Datadog::Tracing::TraceDigest)
expect(trace_digest.trace_id).to eq(b3_trace_id)
expect(trace_digest.span_id).to eq(0xfffffff)
end
end
end
Expand Down

0 comments on commit 0318c77

Please sign in to comment.