From 7979763a1a0029af8ea60bf37d7c278968181e1f Mon Sep 17 00:00:00 2001 From: Bob Evans Date: Wed, 18 Feb 2026 15:48:20 -0500 Subject: [PATCH] refactor: Updated the reparenting logic for compact mode of partial traces to assign parent id to entry span --- lib/transaction/trace/partial-trace.js | 15 ++++++----- .../core-tracing-assertions.js | 2 +- .../tracer_info_standard.json | 27 ++++++++++++------- .../transaction/trace/partial-trace.test.js | 12 +++++---- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/lib/transaction/trace/partial-trace.js b/lib/transaction/trace/partial-trace.js index b70e068d2f..6a11f39163 100644 --- a/lib/transaction/trace/partial-trace.js +++ b/lib/transaction/trace/partial-trace.js @@ -185,13 +185,19 @@ class PartialTrace { } /** - * Checks if span was the retained exit span for a given entity and it has other spans that talked to the same - * entity. It will then sort all timestamps for spans that got dropped and calculate the `nr.durations` and assign - * `nr.ids` for all dropped spans to same entity. It will also reparent the span links from dropped spans to the retained exit span. + * Checks if span had a parentId, if so it will reparent to entry span. + * If span was the retained exit span for a given entity and it has other spans that talked to the same entity, it will: + * sort all timestamps for spans that got dropped and calculate the `nr.durations` + * assign `nr.ids` for all dropped spans to same entity. + * reparent the span links from dropped spans to the retained exit span. * * @param {SpanEvent} span to check if it has to calculate `nr.durations` and `nr.ids` */ applyCompaction(span) { + if (span.parentId) { + logger.debug(`Partial trace is compact, reparenting span ${span.id} from parent ${span.parentId} to entry span ${this.transaction.baseSegment.name}${this.transaction.baseSegment.id}`) + span.addIntrinsicAttribute('parentId', this.transaction.baseSegment.id) + } const sameEntitySpans = this.compactSpanGroups[span.id] if (!sameEntitySpans) { @@ -199,9 +205,6 @@ class PartialTrace { return } - logger.trace('Partial trace is compact, and an exit span, updating parentId(%s) to span %s', this.transaction.baseSegment.id, span.intrinsics.name) - span.addIntrinsicAttribute('parentId', this.transaction.baseSegment.id) - if (sameEntitySpans?.length < 2) { logger.trace('Partial trace is compact, but no exit spans were dropped, not assigning `nr.ids` nor `nr.durations` to span %s', span.intrinsics.name) return diff --git a/test/integration/distributed-tracing/core-tracing-assertions.js b/test/integration/distributed-tracing/core-tracing-assertions.js index fa915e166e..b890325a38 100644 --- a/test/integration/distributed-tracing/core-tracing-assertions.js +++ b/test/integration/distributed-tracing/core-tracing-assertions.js @@ -80,7 +80,7 @@ function findSpan({ spans, name }) { function assertParentId({ parent, spans, span }) { if (parent) { const parentSpan = findSpan({ spans, name: parent }) - assert.equal(span.parentId, parentSpan.id, `span ${span.intrinsics.name} should have parent ${parent}, got ${parentSpan.intrinsics.name}`) + assert.equal(span.parentId, parentSpan.id, `span ${span.intrinsics.name} should have parent ${parent}(${span.parentId}), got ${parentSpan.intrinsics.name}(${parentSpan.id})`) } else { assert.equal(span.parentId, parent) } diff --git a/test/lib/cross_agent_tests/distributed_tracing/tracer_info_standard.json b/test/lib/cross_agent_tests/distributed_tracing/tracer_info_standard.json index e4bc63c2c3..cee67722e7 100644 --- a/test/lib/cross_agent_tests/distributed_tracing/tracer_info_standard.json +++ b/test/lib/cross_agent_tests/distributed_tracing/tracer_info_standard.json @@ -65,20 +65,27 @@ } }, { - "name": "Llm/SOMETHING/function", - "timestamp": 1766435411000, + "name": "inprocess-2", + "timestamp": 1766435410020, "duration_millis": 200, - "agent_attrs": { - "http.url": "myllm" - }, "children": [ { - "name": "External/D", - "timestamp": 1766435411100, - "duration_millis": 250, + "name": "Llm/SOMETHING/function", + "timestamp": 1766435411000, + "duration_millis": 200, "agent_attrs": { - "http.url": "serviceD" - } + "http.url": "myllm" + }, + "children": [ + { + "name": "External/D", + "timestamp": 1766435411100, + "duration_millis": 250, + "agent_attrs": { + "http.url": "serviceD" + } + } + ] } ] } diff --git a/test/unit/transaction/trace/partial-trace.test.js b/test/unit/transaction/trace/partial-trace.test.js index 8d4323eb8f..a6b353e473 100644 --- a/test/unit/transaction/trace/partial-trace.test.js +++ b/test/unit/transaction/trace/partial-trace.test.js @@ -161,14 +161,15 @@ describe('applyCompaction', () => { transaction.baseSegment = { id: 100 } const now = Date.now() const span1 = { + parentId: 99, id: 1, intrinsics: { timestamp: now, duration: 5 }, addIntrinsicAttribute: sinon.spy() } - const span2 = { id: 2, intrinsics: { timestamp: now, duration: 5 } } // duration is 5 - const span3 = { id: 3, intrinsics: { timestamp: now, duration: 7 } } // duration is 7 - const span4 = { id: 4, intrinsics: { timestamp: now + 5000, duration: 3 } } // duration is 8 - const span5 = { id: 5, intrinsics: { timestamp: now + 10000, duration: 10 } } // duration is 18 + const span2 = { parentId: 1, id: 2, intrinsics: { timestamp: now, duration: 5 } } // duration is 5 + const span3 = { parentId: 1, id: 3, intrinsics: { timestamp: now, duration: 7 } } // duration is 7 + const span4 = { parentId: 1, id: 4, intrinsics: { timestamp: now + 5000, duration: 3 } } // duration is 8 + const span5 = { parentId: 1, id: 5, intrinsics: { timestamp: now + 10000, duration: 10 } } // duration is 18 partialTrace.compactSpanGroups[1] = [span1, span5, span3, span4, span2] partialTrace.applyCompaction(span1) assert.ok(!transaction.metrics.unscoped['Supportability/Nodejs/PartialGranularity/NrIds/Dropped']) @@ -184,7 +185,7 @@ describe('applyCompaction', () => { const { partialTrace, transaction } = t.nr transaction.baseSegment = { id: 100 } const now = Date.now() - const span1 = { id: 0, intrinsics: { timestamp: now, duration: 5 }, addIntrinsicAttribute: sinon.spy() } + const span1 = { parentId: 99, id: 0, intrinsics: { timestamp: now, duration: 5 }, addIntrinsicAttribute: sinon.spy() } partialTrace.compactSpanGroups[0] = [] const nrIds = [] for (let i = 1; i <= 100; i++) { @@ -211,6 +212,7 @@ describe('applyCompaction', () => { transaction.baseSegment = { id: 100 } const now = Date.now() const span1 = { + parentId: 99, id: 1, intrinsics: { timestamp: now, duration: 5 }, addIntrinsicAttribute: sinon.spy()