Skip to content

Commit

Permalink
implement w3c phase 3 (#4325)
Browse files Browse the repository at this point in the history
* implent w3c phase 3
  • Loading branch information
khanayan123 authored and juan-fernandez committed Jun 5, 2024
1 parent 56121ca commit 05eeb70
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 12 deletions.
1 change: 1 addition & 0 deletions ext/tags.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ declare const tags: {
MANUAL_DROP: 'manual.drop'
MEASURED: '_dd.measured'
BASE_SERVICE: '_dd.base_service'
DD_PARENT_ID: '_dd.parent_id'
HTTP_URL: 'http.url'
HTTP_METHOD: 'http.method'
HTTP_STATUS_CODE: 'http.status_code'
Expand Down
1 change: 1 addition & 0 deletions ext/tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const tags = {
MANUAL_DROP: 'manual.drop',
MEASURED: '_dd.measured',
BASE_SERVICE: '_dd.base_service',
DD_PARENT_ID: '_dd.parent_id',

// HTTP
HTTP_URL: 'http.url',
Expand Down
69 changes: 57 additions & 12 deletions packages/dd-trace/src/opentracing/propagation/text_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const id = require('../../id')
const DatadogSpanContext = require('../span_context')
const log = require('../../log')
const TraceState = require('./tracestate')
const tags = require('../../../../../ext/tags')

const { AUTO_KEEP, AUTO_REJECT, USER_KEEP } = require('../../../../../ext/priority')

Expand Down Expand Up @@ -39,6 +40,7 @@ const tracestateTagKeyFilter = /[^\x21-\x2b\x2d-\x3c\x3e-\x7e]/g
// Tag values in tracestate replace ',', '~' and ';' with '_'
const tracestateTagValueFilter = /[^\x20-\x2b\x2d-\x3a\x3c-\x7d]/g
const invalidSegment = /^0+$/
const zeroTraceId = '0000000000000000'

class TextMapPropagator {
constructor (config) {
Expand Down Expand Up @@ -175,9 +177,9 @@ class TextMapPropagator {
// SpanContext was created by a ddtrace span.
// Last datadog span id should be set to the current span.
state.set('p', spanContext._spanId)
} else if (spanContext._trace.tags['_dd.parent_id']) {
} else if (spanContext._trace.tags[tags.DD_PARENT_ID]) {
// Propagate the last Datadog span id set on the remote span.
state.set('p', spanContext._trace.tags['_dd.parent_id'])
state.set('p', spanContext._trace.tags[tags.DD_PARENT_ID])
}
state.set('s', priority)
if (mechanism) {
Expand Down Expand Up @@ -214,9 +216,56 @@ class TextMapPropagator {
return this._config.tracePropagationStyle[mode].includes(name)
}

_hasTraceIdConflict (w3cSpanContext, firstSpanContext) {
return w3cSpanContext !== null &&
firstSpanContext.toTraceId(true) === w3cSpanContext.toTraceId(true) &&
firstSpanContext.toSpanId() !== w3cSpanContext.toSpanId()
}

_hasParentIdInTags (spanContext) {
return tags.DD_PARENT_ID in spanContext._trace.tags &&
spanContext._trace.tags[tags.DD_PARENT_ID] !== zeroTraceId
}

_updateParentIdFromDdHeaders (carrier, firstSpanContext) {
const ddCtx = this._extractDatadogContext(carrier)
if (ddCtx !== null) {
firstSpanContext._trace.tags[tags.DD_PARENT_ID] = ddCtx._spanId.toString().padStart(16, '0')
}
}

_resolveTraceContextConflicts (w3cSpanContext, firstSpanContext, carrier) {
if (!this._hasTraceIdConflict(w3cSpanContext, firstSpanContext)) {
return firstSpanContext
}
if (this._hasParentIdInTags(w3cSpanContext)) {
// tracecontext headers contain a p value, ensure this value is sent to backend
firstSpanContext._trace.tags[tags.DD_PARENT_ID] = w3cSpanContext._trace.tags[tags.DD_PARENT_ID]
} else {
// if p value is not present in tracestate, use the parent id from the datadog headers
this._updateParentIdFromDdHeaders(carrier, firstSpanContext)
}
// the span_id in tracecontext takes precedence over the first extracted propagation style
firstSpanContext._spanId = w3cSpanContext._spanId
return firstSpanContext
}

_extractSpanContext (carrier) {
let spanContext = null
for (const extractor of this._config.tracePropagationStyle.extract) {
let spanContext = null
// add logic to ensure tracecontext headers takes precedence over other extracted headers
if (spanContext !== null) {
if (this._config.tracePropagationExtractFirst) {
return spanContext
}
if (extractor !== 'tracecontext') {
continue
}
spanContext = this._resolveTraceContextConflicts(
this._extractTraceparentContext(carrier), spanContext, carrier)
break
}

switch (extractor) {
case 'datadog':
spanContext = this._extractDatadogContext(carrier)
Expand All @@ -238,13 +287,9 @@ class TextMapPropagator {
default:
log.warn(`Unknown propagation style: ${extractor}`)
}

if (spanContext !== null) {
return spanContext
}
}

return this._extractSqsdContext(carrier)
return spanContext || this._extractSqsdContext(carrier)
}

_extractDatadogContext (carrier) {
Expand Down Expand Up @@ -354,7 +399,7 @@ class TextMapPropagator {
for (const [key, value] of state.entries()) {
switch (key) {
case 'p': {
spanContext._trace.tags['_dd.parent_id'] = value
spanContext._trace.tags[tags.DD_PARENT_ID] = value
break
}
case 's': {
Expand Down Expand Up @@ -387,8 +432,8 @@ class TextMapPropagator {
}
})

if (!spanContext._trace.tags['_dd.parent_id']) {
spanContext._trace.tags['_dd.parent_id'] = '0000000000000000'
if (!spanContext._trace.tags[tags.DD_PARENT_ID]) {
spanContext._trace.tags[tags.DD_PARENT_ID] = zeroTraceId
}

this._extractBaggageItems(carrier, spanContext)
Expand Down Expand Up @@ -531,7 +576,7 @@ class TextMapPropagator {

const tid = traceId.substring(0, 16)

if (tid === '0000000000000000') return
if (tid === zeroTraceId) return

spanContext._trace.tags['_dd.p.tid'] = tid
}
Expand Down
28 changes: 28 additions & 0 deletions packages/dd-trace/test/opentracing/propagation/text_map.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,34 @@ describe('TextMapPropagator', () => {
expect(spanContext._tracestate).to.be.undefined
})

it('extracts span_id from tracecontext headers and stores datadog parent-id in trace_distributed_tags', () => {
textMap['x-datadog-trace-id'] = '61185'
textMap['x-datadog-parent-id'] = '15'
textMap.traceparent = '00-0000000000000000000000000000ef01-0000000000011ef0-01'
config.tracePropagationStyle.extract = ['datadog', 'tracecontext']

const carrier = textMap
const spanContext = propagator.extract(carrier)
expect(parseInt(spanContext._spanId.toString(), 16)).to.equal(73456)
expect(parseInt(spanContext._traceId.toString(), 16)).to.equal(61185)
expect(spanContext._trace.tags).to.have.property('_dd.parent_id', '000000000000000f')
})

it('extracts span_id from tracecontext headers and stores p value from tracestate in trace_distributed_tags',
() => {
textMap['x-datadog-trace-id'] = '61185'
textMap['x-datadog-parent-id'] = '15'
textMap.traceparent = '00-0000000000000000000000000000ef01-0000000000011ef0-01'
textMap.tracestate = 'other=bleh,dd=p:0000000000000001;s:2;o:foo;t.dm:-4'
config.tracePropagationStyle.extract = ['datadog', 'tracecontext']

const carrier = textMap
const spanContext = propagator.extract(carrier)
expect(parseInt(spanContext._spanId.toString(), 16)).to.equal(73456)
expect(parseInt(spanContext._traceId.toString(), 16)).to.equal(61185)
expect(spanContext._trace.tags).to.have.property('_dd.parent_id', '0000000000000001')
})

describe('with B3 propagation as multiple headers', () => {
beforeEach(() => {
config.tracePropagationStyle.extract = ['b3multi']
Expand Down

0 comments on commit 05eeb70

Please sign in to comment.