Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

w3c(phase 3): ensure last datadog parent id is always recorded #3631

Merged
merged 12 commits into from
Jun 7, 2024
32 changes: 30 additions & 2 deletions lib/datadog/tracing/distributed/propagation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,22 @@ def extract(data)
# Only parse if it represent the same trace as the successfully extracted one
next unless tracecontext_digest.trace_id == extracted_trace_digest.trace_id

# Preserve the `tracestate`
parent_id = extracted_trace_digest.span_id
distributed_tags = extracted_trace_digest.trace_distributed_tags
unless extracted_trace_digest.span_id == tracecontext_digest.span_id
# span_id in the tracecontext header takes precedence over the value in all conflicting headers
parent_id = tracecontext_digest.span_id
if (lp_id = last_datadog_parent_id(data, tracecontext_digest.trace_distributed_tags))
distributed_tags = extracted_trace_digest.trace_distributed_tags&.dup || {}
distributed_tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID] = lp_id
end
end
# Preserve the trace state and last datadog span id
extracted_trace_digest = extracted_trace_digest.merge(
mabdinur marked this conversation as resolved.
Show resolved Hide resolved
span_id: parent_id,
trace_state: tracecontext_digest.trace_state,
trace_state_unknown_fields: tracecontext_digest.trace_state_unknown_fields
trace_state_unknown_fields: tracecontext_digest.trace_state_unknown_fields,
trace_distributed_tags: distributed_tags
)
end
rescue => e
Expand All @@ -115,6 +127,22 @@ def extract(data)

extracted_trace_digest
end

private

def last_datadog_parent_id(headers, tracecontext_tags)
dd_propagator = @propagation_style_extract.find { |propagator| propagator.is_a?(Datadog) }
if tracecontext_tags&.fetch(
mabdinur marked this conversation as resolved.
Show resolved Hide resolved
Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID,
Tracing::Metadata::Ext::Distributed::DD_PARENT_ID_DEFAULT
) != Tracing::Metadata::Ext::Distributed::DD_PARENT_ID_DEFAULT
# tracecontext headers contain a p value, ensure this value is sent to backend
tracecontext_tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID]
elsif dd_propagator && (dd_digest = dd_propagator.extract(headers))
# if p value is not present in tracestate, use the parent id from the datadog headers
format('%016x', dd_digest.span_id)
end
end
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/tracing/distributed/trace_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def extract(data)
end

tags ||= {}
tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID] = ts_parent_id || '0000000000000000'
tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID] =
ts_parent_id || Tracing::Metadata::Ext::Distributed::DD_PARENT_ID_DEFAULT

TraceDigest.new(
span_id: parent_id,
Expand Down
1 change: 1 addition & 0 deletions lib/datadog/tracing/metadata/ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ module Distributed
TAG_SAMPLING_PRIORITY = '_sampling_priority_v1'

TAG_DD_PARENT_ID = '_dd.parent_id'
DD_PARENT_ID_DEFAULT = '0000000000000000'

# Trace tags with this prefix will propagate from a trace through distributed tracing.
# Distributed headers tags with this prefix will be injected into the active trace.
Expand Down
24 changes: 24 additions & 0 deletions spec/datadog/tracing/distributed/propagation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,30 @@
end
end
end

context 'and span_id is not matching' do
let(:data) { super().merge(prepare_key['x-datadog-parent-id'] => '15') }

context 'without tracestate' do
it 'extracts span_id from traceparent and stores x-datadog-parent-id in trace_distributed_tags' do
expect(trace_digest).to be_a_kind_of(Datadog::Tracing::TraceDigest)
expect(trace_digest.span_id).to eq(73456)
expect(trace_digest.trace_id).to eq(61185)
expect(trace_digest.trace_distributed_tags).to include('_dd.parent_id' => '000000000000000f')
end
end

context 'with tracestate' do
let(:data) { super().merge(prepare_key['tracestate'] => 'other=gg,dd=s:1;p:000000000000000a') }

it 'extracts span_id from traceparent and stores tracestate p value in trace_distributed_tags' do
expect(trace_digest).to be_a_kind_of(Datadog::Tracing::TraceDigest)
expect(trace_digest.span_id).to eq(73456)
expect(trace_digest.trace_id).to eq(61185)
expect(trace_digest.trace_distributed_tags).to eq({ '_dd.parent_id' => '000000000000000a' })
end
end
end
end
end

Expand Down
Loading