Skip to content

Commit bc714cf

Browse files
authored
fix: Fixed undici/fetch instrumentation to properly assign the parent-id portion of the traceparent header on outgoing requests to the active http external span id (#2951)
1 parent 8dd557b commit bc714cf

File tree

6 files changed

+83
-7
lines changed

6 files changed

+83
-7
lines changed

lib/instrumentation/undici.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ function requestCreateHook(shim, { request }) {
136136
}
137137

138138
try {
139-
addDTHeaders({ transaction, config, request })
140139
createExternalSegment({ shim, request, segment })
140+
addDTHeaders({ transaction, config, request })
141141
} catch (err) {
142142
logger.warn(err, 'Unable to create external segment')
143143
}

test/integration/instrumentation/fetch.test.js

+22
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ function createServer() {
2727
const status = parts[parts.length - 1]
2828
res.writeHead(status)
2929
res.end()
30+
} else if (req.url.includes('/headers')) {
31+
const data = JSON.stringify(req.headers)
32+
res.writeHead(200, {
33+
'Content-Length': data.length,
34+
'Content-Type': 'application/json'
35+
})
36+
res.end(data)
3037
} else {
3138
res.writeHead(200)
3239
res.end('ok')
@@ -102,6 +109,21 @@ test('fetch', async function (t) {
102109
})
103110
})
104111

112+
await t.test('should add proper traceparent to outgoing headers', async () => {
113+
await helper.runInTransaction(agent, async (tx) => {
114+
const body = await fetch(`${REQUEST_URL}/headers`)
115+
assert.equal(body.status, 200)
116+
const segment = metrics.findSegment(tx.trace, tx.trace.root, `External/${HOST}/headers`)
117+
const { traceparent } = await body.json()
118+
const [version, traceId, parentSpan, sampledFlag] = traceparent.split('-')
119+
assert.equal(version, '00')
120+
assert.equal(traceId, tx.traceId)
121+
assert.equal(parentSpan, segment.id)
122+
assert.equal(sampledFlag, '01')
123+
tx.end()
124+
})
125+
})
126+
105127
await t.test('should add unscoped metrics for an external request', async () => {
106128
await helper.runInTransaction(agent, async (tx) => {
107129
const { status } = await fetch(`${REQUEST_URL}/get?a=b&c=d`)

test/unit/instrumentation/http/outbound.test.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -565,9 +565,15 @@ test('when working with http.request', async (t) => {
565565
nock(host)
566566
.get(path)
567567
.reply(200, function () {
568+
const { transaction, segment } = agent.tracer.getContext()
569+
assert.equal(segment.name, 'External/www.google.com')
568570
headers = this.req.headers
569571
assert.ok(headers.traceparent, 'traceparent header')
570-
assert.equal(headers.traceparent.split('-').length, 4)
572+
const [version, traceId, parentSpanId, sampledFlag] = headers.traceparent.split('-')
573+
assert.equal(version, '00')
574+
assert.equal(traceId, transaction.traceId)
575+
assert.equal(parentSpanId, segment.id)
576+
assert.equal(sampledFlag, '01')
571577
assert.ok(headers.tracestate, 'tracestate header')
572578
assert.ok(!headers.tracestate.includes('null'))
573579
assert.ok(!headers.tracestate.includes('true'))

test/unit/shim/message-shim.test.js

+27-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const API = require('../../../api')
1111
const DESTINATIONS = require('../../../lib/config/attribute-filter').DESTINATIONS
1212
const hashes = require('../../../lib/util/hashes')
1313
const helper = require('../../lib/agent_helper')
14+
const { findSegment } = require('#testlib/metrics_helper.js')
1415
const MessageShim = require('../../../lib/shim/message-shim')
1516
const { MessageSpec, MessageSubscribeSpec } = require('../../../lib/shim/specs')
1617
const {
@@ -369,6 +370,27 @@ test('MessageShim', async function (t) {
369370
})
370371
})
371372

373+
await t.test('should insert DT request headers', function (t, end) {
374+
const { agent, shim, wrappable } = t.nr
375+
agent.config.cross_application_tracer.enabled = false
376+
agent.config.distributed_tracing.enabled = true
377+
const headers = {}
378+
shim.recordProduce(wrappable, 'getActiveSegment', function () {
379+
return new MessageSpec({ headers })
380+
})
381+
382+
helper.runInTransaction(agent, function (tx) {
383+
wrappable.getActiveSegment()
384+
const segment = findSegment(tx.trace, tx.trace.root, 'MessageBroker/RabbitMQ/Exchange/Produce/Temp')
385+
const [version, traceId, parentSpanId, sampledFlag] = headers.traceparent.split('-')
386+
assert.equal(version, '00')
387+
assert.equal(traceId, tx.traceId)
388+
assert.equal(parentSpanId, segment.id)
389+
assert.equal(sampledFlag, '01')
390+
end()
391+
})
392+
})
393+
372394
await t.test('should insert distributed trace headers in all messages', async function (t) {
373395
const plan = tspl(t, { plan: 1 })
374396
const { agent, shim, wrappable } = t.nr
@@ -393,26 +415,27 @@ test('MessageShim', async function (t) {
393415
)
394416

395417
let called = 0
396-
agent.on('transactionFinished', () => {
418+
agent.on('transactionFinished', (tx) => {
397419
called++
420+
const segment = findSegment(tx.trace, tx.trace.root, 'MessageBroker/RabbitMQ/Exchange/Produce/Temp')
398421
match(messages, [
399422
{
400423
headers: {
401424
newrelic: '',
402-
traceparent: /^00-/
425+
traceparent: `00-${tx.traceId}-${segment.id}-01`
403426
}
404427
},
405428
{
406429
headers: {
407430
newrelic: '',
408-
traceparent: /^00-/,
431+
traceparent: `00-${tx.traceId}-${segment.id}-01`,
409432
foo: 'foo'
410433
}
411434
},
412435
{
413436
headers: {
414437
newrelic: '',
415-
traceparent: /^00-/
438+
traceparent: `00-${tx.traceId}-${segment.id}-01`
416439
}
417440
}
418441
])

test/unit/shim/transaction-shim.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ test('TransactionShim', async function (t) {
662662
const outboundHeaders = {}
663663
tx.insertDistributedTraceHeaders(outboundHeaders)
664664

665-
assert.ok(outboundHeaders.traceparent.startsWith('00-4bf92f3577b3'))
665+
assert.equal(outboundHeaders.traceparent, `00-${tx.traceId}-${segment.id}-01`)
666666
assert.ok(outboundHeaders.tracestate.endsWith(tracestate))
667667
end()
668668
})

test/versioned/undici/requests.test.js

+25
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ function createServer() {
3333
const statusCode = parts[parts.length - 1]
3434
res.writeHead(statusCode)
3535
res.end()
36+
} else if (req.url.includes('/headers')) {
37+
const data = JSON.stringify(req.headers)
38+
res.writeHead(200, {
39+
'Content-Length': data.length,
40+
'Content-Type': 'application/json'
41+
})
42+
res.end(data)
3643
} else {
3744
res.writeHead(200)
3845
res.end('ok')
@@ -145,6 +152,24 @@ test('Undici request tests', async (t) => {
145152
})
146153
})
147154

155+
await t.test('should add proper traceparent to outgoing headers', async () => {
156+
await helper.runInTransaction(agent, async (tx) => {
157+
const { statusCode, body } = await undici.request(REQUEST_URL, {
158+
path: '/headers',
159+
method: 'GET'
160+
})
161+
assert.equal(statusCode, 200)
162+
const segment = metrics.findSegment(tx.trace, tx.trace.root, `External/${HOST}/headers`)
163+
const { traceparent } = await body.json()
164+
const [version, traceId, parentSpan, sampledFlag] = traceparent.split('-')
165+
assert.equal(version, '00')
166+
assert.equal(traceId, tx.traceId)
167+
assert.equal(parentSpan, segment.id)
168+
assert.equal(sampledFlag, '01')
169+
tx.end()
170+
})
171+
})
172+
148173
await t.test('should add unscoped metrics for an external request', async () => {
149174
// make sure metric aggregator is empty before asserting metrics
150175
agent.metrics.clear()

0 commit comments

Comments
 (0)