Skip to content

Commit caa9e05

Browse files
add essential mode and tests
1 parent 122bbe4 commit caa9e05

File tree

2 files changed

+191
-78
lines changed

2 files changed

+191
-78
lines changed

lib/spans/span-event.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,17 @@ class SpanEvent {
190190
if (entityRelationshipAttrs.length > 0) {
191191
return { attributes, customAttributes, dropSpan: false }
192192
}
193+
} else if (partialGranularityMode === 'essential') {
194+
const attributesToKeep = {}
195+
for (const item in attributes) {
196+
if (entityRelationshipAttrs.includes(item) || item.startsWith('error.')) {
197+
attributesToKeep[item] = attributes[item]
198+
}
199+
}
200+
201+
if (Object.keys(attributesToKeep).length > 0) {
202+
return { attributes: attributesToKeep, customAttributes: {}, dropSpan: false }
203+
}
193204
}
194205

195206
return { dropSpan: true }

test/unit/spans/partial-granularity-spans.test.js

Lines changed: 180 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -9,98 +9,200 @@ const test = require('node:test')
99
const helper = require('#testlib/agent_helper.js')
1010
const SpanEvent = require('#agentlib/spans/span-event.js')
1111

12-
test.beforeEach((ctx) => {
13-
const agent = helper.instrumentMockedAgent({
14-
distributed_tracing: {
15-
enabled: true,
16-
partial_granularity: {
12+
test('Partial Granularity Spans - reduced mode', async (t) => {
13+
t.beforeEach((ctx) => {
14+
const agent = helper.instrumentMockedAgent({
15+
distributed_tracing: {
1716
enabled: true,
18-
type: 'reduced'
17+
partial_granularity: {
18+
enabled: true,
19+
type: 'reduced'
20+
}
1921
}
20-
}
22+
})
23+
ctx.nr = { agent }
2124
})
22-
ctx.nr = { agent }
23-
})
2425

25-
test.afterEach((ctx) => {
26-
helper.unloadAgent(ctx.nr.agent)
27-
})
26+
t.afterEach((ctx) => {
27+
helper.unloadAgent(ctx.nr.agent)
28+
})
2829

29-
test('should include entry span', (t, end) => {
30-
const { agent } = t.nr
31-
helper.runInTransaction(agent, (transaction) => {
32-
transaction.isPartialTrace = true
33-
const segment = transaction.trace.add('entrySpan')
34-
transaction.baseSegment = segment
35-
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
36-
assert.ok(span)
37-
assert.equal(span.intrinsics['nr.entryPoint'], true)
38-
assert.equal(span.intrinsics['nr.pg'], true)
39-
assert.equal(span.intrinsics.parentId, null)
40-
end()
30+
await t.test('should include entry span', (t, end) => {
31+
const { agent } = t.nr
32+
helper.runInTransaction(agent, (transaction) => {
33+
transaction.isPartialTrace = true
34+
const segment = transaction.trace.add('entrySpan')
35+
transaction.baseSegment = segment
36+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
37+
assert.ok(span)
38+
assert.equal(span.intrinsics['nr.entryPoint'], true)
39+
assert.equal(span.intrinsics['nr.pg'], true)
40+
assert.equal(span.intrinsics.parentId, null)
41+
end()
42+
})
4143
})
42-
})
4344

44-
test('should include Llm span', (t, end) => {
45-
const { agent } = t.nr
46-
helper.runInTransaction(agent, (transaction) => {
47-
transaction.isPartialTrace = true
48-
const segment = transaction.trace.add('Llm/foobar')
49-
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
50-
assert.ok(span)
51-
end()
45+
await t.test('should include Llm span', (t, end) => {
46+
const { agent } = t.nr
47+
helper.runInTransaction(agent, (transaction) => {
48+
transaction.isPartialTrace = true
49+
const segment = transaction.trace.add('Llm/foobar')
50+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
51+
assert.ok(span)
52+
end()
53+
})
5254
})
53-
})
5455

55-
test('should include exit span that has entity relationship attrs', (t, end) => {
56-
const { agent } = t.nr
57-
helper.runInTransaction(agent, (transaction) => {
58-
transaction.isPartialTrace = true
59-
const segment = transaction.trace.add('Datastore/operation/Redis/SET')
60-
segment.addAttribute('host', 'redis-service')
61-
segment.addAttribute('port_path_or_id', 6379)
62-
segment.addAttribute('foo', 'bar')
63-
const spanContext = segment.getSpanContext()
64-
spanContext.addCustomAttribute('custom', 'test')
65-
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
66-
assert.ok(span)
67-
const [instrinsics, customAttrs, agentAttrs] = span.toJSON()
68-
assert.equal(instrinsics['name'], 'Datastore/operation/Redis/SET')
69-
assert.equal(instrinsics['span.kind'], 'client')
70-
assert.deepEqual(customAttrs, {
71-
custom: 'test'
56+
await t.test('should include exit span that has entity relationship attrs', (t, end) => {
57+
const { agent } = t.nr
58+
helper.runInTransaction(agent, (transaction) => {
59+
transaction.isPartialTrace = true
60+
const segment = transaction.trace.add('Datastore/operation/Redis/SET')
61+
segment.addAttribute('host', 'redis-service')
62+
segment.addAttribute('port_path_or_id', 6379)
63+
segment.addAttribute('foo', 'bar')
64+
const spanContext = segment.getSpanContext()
65+
spanContext.addCustomAttribute('custom', 'test')
66+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
67+
assert.ok(span)
68+
const [instrinsics, customAttrs, agentAttrs] = span.toJSON()
69+
assert.equal(instrinsics['name'], 'Datastore/operation/Redis/SET')
70+
assert.equal(instrinsics['span.kind'], 'client')
71+
assert.deepEqual(customAttrs, {
72+
custom: 'test'
73+
})
74+
assert.equal(span.intrinsics['nr.entryPoint'], null)
75+
assert.equal(span.intrinsics['nr.pg'], null)
76+
assert.equal(agentAttrs['peer.address'], 'redis-service:6379')
77+
assert.equal(agentAttrs['peer.hostname'], 'redis-service')
78+
assert.equal(agentAttrs['server.address'], 'redis-service')
79+
assert.equal(agentAttrs['server.port'], '6379')
80+
assert.equal(agentAttrs.foo, 'bar')
81+
end()
7282
})
73-
assert.equal(span.intrinsics['nr.entryPoint'], null)
74-
assert.equal(span.intrinsics['nr.pg'], null)
75-
assert.equal(agentAttrs['peer.address'], 'redis-service:6379')
76-
assert.equal(agentAttrs['peer.hostname'], 'redis-service')
77-
assert.equal(agentAttrs['server.address'], 'redis-service')
78-
assert.equal(agentAttrs['server.port'], '6379')
79-
assert.equal(agentAttrs.foo, 'bar')
80-
end()
8183
})
82-
})
8384

84-
test('should not include exit span that does not have entity relationship attrs', (t, end) => {
85-
const { agent } = t.nr
86-
helper.runInTransaction(agent, (transaction) => {
87-
transaction.isPartialTrace = true
88-
const segment = transaction.trace.add('Datastore/operation/Redis/SET')
89-
segment.addAttribute('foo', 'bar')
90-
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
91-
assert.ok(!span)
92-
end()
85+
await t.test('should not include exit span that does not have entity relationship attrs', (t, end) => {
86+
const { agent } = t.nr
87+
helper.runInTransaction(agent, (transaction) => {
88+
transaction.isPartialTrace = true
89+
const segment = transaction.trace.add('Datastore/operation/Redis/SET')
90+
segment.addAttribute('foo', 'bar')
91+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
92+
assert.ok(!span)
93+
end()
94+
})
95+
})
96+
97+
await t.test('should not include in process span', (t, end) => {
98+
const { agent } = t.nr
99+
helper.runInTransaction(agent, (transaction) => {
100+
transaction.isPartialTrace = true
101+
const segment = transaction.trace.add('test-segment')
102+
segment.addAttribute('foo', 'bar')
103+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
104+
assert.ok(!span)
105+
end()
106+
})
93107
})
94108
})
95109

96-
test('should not include in process span', (t, end) => {
97-
const { agent } = t.nr
98-
helper.runInTransaction(agent, (transaction) => {
99-
transaction.isPartialTrace = true
100-
const segment = transaction.trace.add('test-segment')
101-
segment.addAttribute('foo', 'bar')
102-
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'reduced' })
103-
assert.ok(!span)
104-
end()
110+
test('Partial Granularity Spans - essential mode', async (t) => {
111+
t.beforeEach((ctx) => {
112+
const agent = helper.instrumentMockedAgent({
113+
distributed_tracing: {
114+
enabled: true,
115+
partial_granularity: {
116+
enabled: true,
117+
type: 'essential'
118+
}
119+
}
120+
})
121+
ctx.nr = { agent }
122+
})
123+
124+
t.afterEach((ctx) => {
125+
helper.unloadAgent(ctx.nr.agent)
126+
})
127+
128+
await t.test('should include entry span', (t, end) => {
129+
const { agent } = t.nr
130+
helper.runInTransaction(agent, (transaction) => {
131+
transaction.isPartialTrace = true
132+
const segment = transaction.trace.add('entrySpan')
133+
transaction.baseSegment = segment
134+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'essential' })
135+
assert.ok(span)
136+
assert.equal(span.intrinsics['nr.entryPoint'], true)
137+
assert.equal(span.intrinsics['nr.pg'], true)
138+
assert.equal(span.intrinsics.parentId, null)
139+
end()
140+
})
141+
})
142+
143+
await t.test('should include Llm span', (t, end) => {
144+
const { agent } = t.nr
145+
helper.runInTransaction(agent, (transaction) => {
146+
transaction.isPartialTrace = true
147+
const segment = transaction.trace.add('Llm/foobar')
148+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'essential' })
149+
assert.ok(span)
150+
end()
151+
})
152+
})
153+
154+
await t.test('should include exit span with entity relationship and error attrs but no custom attrs', (t, end) => {
155+
const { agent } = t.nr
156+
helper.runInTransaction(agent, (transaction) => {
157+
transaction.isPartialTrace = true
158+
const segment = transaction.trace.add('Datastore/operation/Redis/SET')
159+
segment.addAttribute('host', 'redis-service')
160+
segment.addAttribute('port_path_or_id', 6379)
161+
segment.addAttribute('foo', 'bar')
162+
segment.addAttribute('error.message', 'something went wrong')
163+
segment.addAttribute('error.class', 'Error')
164+
const spanContext = segment.getSpanContext()
165+
spanContext.addCustomAttribute('custom', 'test')
166+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'essential' })
167+
assert.ok(span)
168+
const [instrinsics, customAttrs, agentAttrs] = span.toJSON()
169+
assert.equal(instrinsics['name'], 'Datastore/operation/Redis/SET')
170+
assert.equal(instrinsics['span.kind'], 'client')
171+
assert.deepEqual(customAttrs, {}) // should drop custom attributes
172+
assert.equal(span.intrinsics['nr.entryPoint'], null)
173+
assert.equal(span.intrinsics['nr.pg'], null)
174+
assert.equal(agentAttrs['peer.address'], 'redis-service:6379')
175+
assert.equal(agentAttrs['peer.hostname'], 'redis-service')
176+
assert.equal(agentAttrs['server.address'], 'redis-service')
177+
assert.equal(agentAttrs['server.port'], '6379')
178+
assert.equal(agentAttrs.foo, undefined) // should drop non entity relationship agent attributes
179+
assert.equal(agentAttrs['error.message'], 'something went wrong') // keep error attributes if they exist
180+
assert.equal(agentAttrs['error.class'], 'Error') // keep error attributes if they exist
181+
end()
182+
})
183+
})
184+
185+
await t.test('should not include exit span that does not have entity relationship attrs', (t, end) => {
186+
const { agent } = t.nr
187+
helper.runInTransaction(agent, (transaction) => {
188+
transaction.isPartialTrace = true
189+
const segment = transaction.trace.add('Datastore/operation/Redis/SET')
190+
segment.addAttribute('foo', 'bar')
191+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'essential' })
192+
assert.ok(!span)
193+
end()
194+
})
195+
})
196+
197+
await t.test('should not include in process span', (t, end) => {
198+
const { agent } = t.nr
199+
helper.runInTransaction(agent, (transaction) => {
200+
transaction.isPartialTrace = true
201+
const segment = transaction.trace.add('test-segment')
202+
segment.addAttribute('foo', 'bar')
203+
const span = SpanEvent.fromSegment({ segment, transaction, inProcessSpans: true, partialGranularityMode: 'essential' })
204+
assert.ok(!span)
205+
end()
206+
})
105207
})
106208
})

0 commit comments

Comments
 (0)