Skip to content

Commit a247d31

Browse files
authored
chore: Added supportability metrics Supportability/Nodejs/SpanEvent/<Links|Events>/Dropped when limit of 100 is exceeded (newrelic#3688)
1 parent f4dd09e commit a247d31

File tree

5 files changed

+90
-11
lines changed

5 files changed

+90
-11
lines changed

lib/metrics/names.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,9 @@ const SPAN_EVENTS = {
325325
SEEN: SUPPORTABILITY.PREFIX + SPAN_EVENT_PREFIX + 'TotalEventsSeen',
326326
SENT: SUPPORTABILITY.PREFIX + SPAN_EVENT_PREFIX + 'TotalEventsSent',
327327
DROPPED: SUPPORTABILITY.PREFIX + SPAN_EVENT_PREFIX + 'Discarded',
328-
LIMIT: SUPPORTABILITY.PREFIX + SPAN_EVENT_PREFIX + 'Limit'
328+
LIMIT: SUPPORTABILITY.PREFIX + SPAN_EVENT_PREFIX + 'Limit',
329+
LINKS_DROPPED: SUPPORTABILITY.NODEJS + '/' + SPAN_EVENT_PREFIX + 'Links/Dropped',
330+
EVENTS_DROPPED: SUPPORTABILITY.NODEJS + '/' + SPAN_EVENT_PREFIX + 'Events/Dropped'
329331
}
330332

331333
const INFINITE_TRACING = {

lib/otel/traces/span-processor.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const {
2323
transformTemplate
2424
} = require('./utils.js')
2525
const defaultLogger = require('#agentlib/logger.js').child({ component: 'span-processor' })
26+
const { SPAN_EVENTS } = require('#agentlib/metrics/names.js')
2627

2728
const {
2829
SPAN_STATUS_CODE
@@ -155,7 +156,10 @@ module.exports = class NrSpanProcessor {
155156
event: span.events[i],
156157
spanContext
157158
})
158-
segment.addTimedEvent(event)
159+
const added = segment.addTimedEvent(event)
160+
if (!added) {
161+
this.agent.metrics.getOrCreateMetric(SPAN_EVENTS.EVENTS_DROPPED).incrementCallCount()
162+
}
159163
}
160164
}
161165

@@ -181,7 +185,10 @@ module.exports = class NrSpanProcessor {
181185
spanContext,
182186
timestamp
183187
})
184-
segment.addSpanLink(link)
188+
const added = segment.addSpanLink(link)
189+
if (!added) {
190+
this.agent.metrics.getOrCreateMetric(SPAN_EVENTS.LINKS_DROPPED).incrementCallCount()
191+
}
185192
}
186193
}
187194

lib/transaction/trace/segment.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,20 +296,34 @@ TraceSegment.prototype.captureExternalAttributes = function captureExternalAttri
296296
this.addAttribute('procedure', method)
297297
}
298298

299+
/**
300+
* Adds SpanLink event to TraceSegment unless the size limit has been reached
301+
*
302+
* @param {SpanLink} spanLink to add to TraceSegment
303+
* @returns {boolean} if span link was added or not
304+
*/
299305
TraceSegment.prototype.addSpanLink = function addSpanLink(spanLink) {
300306
if (this.spanLinks.length === 100) {
301307
this.logger.trace({ spanLink }, 'Span links limit reached. Not adding new link.')
302-
return
308+
return false
303309
}
304310
this.spanLinks.push(spanLink)
311+
return true
305312
}
306313

314+
/**
315+
* Adds TimedEvent event to TraceSegment unless the size limit has been reached
316+
*
317+
* @param {TimedEvent} timedEvent to add to TraceSegment
318+
* @returns {boolean} if timed event was added or not
319+
*/
307320
TraceSegment.prototype.addTimedEvent = function addTimedEvent(timedEvent) {
308321
if (this.timedEvents.length === 100) {
309322
this.logger.trace({ timedEvent }, 'Timed event limit reached. Not adding new event.')
310-
return
323+
return false
311324
}
312325
this.timedEvents.push(timedEvent)
326+
return true
313327
}
314328

315329
module.exports = TraceSegment

test/unit/lib/otel/traces/span-procesor.test.js

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ test('reconcileEvents skips work if no events', (t) => {
271271
})
272272

273273
test('reconcileEvents adds remapped events to the segment', (t) => {
274-
t.plan(2)
274+
t.plan(3)
275275
const { agent, processor, tracer } = t.nr
276276

277277
helper.runInTransaction(agent, (tx) => {
@@ -296,7 +296,32 @@ test('reconcileEvents adds remapped events to the segment', (t) => {
296296
return spanContext.call(span)
297297
}
298298
processor.reconcileEvents({ segment, span })
299+
t.assert.ok(!agent.metrics._metrics.unscoped['Supportability/Nodejs/SpanEvent/Events/Dropped'])
300+
301+
tx.end()
302+
})
303+
})
304+
305+
test('reconcileEvents logs `Supportability/Nodejs/SpanEvent/Links/Dropped` when events exceed 100', (t) => {
306+
t.plan(2)
307+
const { agent, processor, tracer } = t.nr
299308

309+
helper.runInTransaction(agent, (tx) => {
310+
const span = createHttpClientSpan({ tracer })
311+
processor.onStart(span)
312+
313+
for (let i = 0; i < 105; i++) {
314+
span.events.push({
315+
name: `test-event-${i}`,
316+
attributes: { test: 'attr' },
317+
time: [1, 0]
318+
})
319+
}
320+
321+
const { segment } = span[otelSynthesis]
322+
processor.reconcileEvents({ segment, span })
323+
t.assert.equal(agent.metrics._metrics.unscoped['Supportability/Nodejs/SpanEvent/Events/Dropped'].callCount, 5)
324+
t.assert.equal(segment.timedEvents.length, 100)
300325
tx.end()
301326
})
302327
})
@@ -320,7 +345,7 @@ test('reconcileLinks skips work if no links', (t) => {
320345
})
321346

322347
test('reconcileLinks adds remapped links to the segment', (t) => {
323-
t.plan(2)
348+
t.plan(3)
324349
const { agent, processor, tracer } = t.nr
325350

326351
helper.runInTransaction(agent, (tx) => {
@@ -347,7 +372,34 @@ test('reconcileLinks adds remapped links to the segment', (t) => {
347372
return spanContext.call(span)
348373
}
349374
processor.reconcileLinks({ segment, otelSpan: span })
375+
t.assert.ok(!agent.metrics._metrics.unscoped['Supportability/Nodejs/SpanEvent/Links/Dropped'])
376+
377+
tx.end()
378+
})
379+
})
350380

381+
test('reconcileLinks logs `Supportability/Nodejs/SpanEvent/Links/Dropped` when links exceed 100', (t) => {
382+
t.plan(2)
383+
const { agent, processor, tracer } = t.nr
384+
385+
helper.runInTransaction(agent, (tx) => {
386+
const span = createHttpClientSpan({ tracer })
387+
processor.onStart(span)
388+
389+
for (let i = 0; i < 105; i++) {
390+
span.links.push({
391+
attributes: { test: `attr-${i}` },
392+
context: {
393+
spanId: 'linked-span',
394+
traceId: 'linked-trace'
395+
}
396+
})
397+
}
398+
399+
const { segment } = span[otelSynthesis]
400+
processor.reconcileLinks({ segment, otelSpan: span })
401+
t.assert.equal(agent.metrics._metrics.unscoped['Supportability/Nodejs/SpanEvent/Links/Dropped'].callCount, 5)
402+
t.assert.equal(segment.spanLinks.length, 100)
351403
tx.end()
352404
})
353405
})

test/unit/transaction/trace/segment.test.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,8 @@ test('addSpanLink', async (t) => {
705705
await test('adds link to the internal array', (t) => {
706706
const { segment } = t.nr
707707
assert.equal(segment.spanLinks.length, 0)
708-
segment.addSpanLink({ fake: 'link' })
708+
const added = segment.addSpanLink({ fake: 'link' })
709+
assert.equal(added, true)
709710
assert.equal(segment.spanLinks.length, 1)
710711
assert.deepStrictEqual(segment.spanLinks[0], { fake: 'link' })
711712
})
@@ -718,7 +719,8 @@ test('addSpanLink', async (t) => {
718719
}
719720
assert.equal(segment.spanLinks.length, 100)
720721

721-
segment.addSpanLink({ to: 'drop' })
722+
const added = segment.addSpanLink({ to: 'drop' })
723+
assert.equal(added, false)
722724
assert.equal(segment.spanLinks.length, 100)
723725
for (const link of segment.spanLinks) {
724726
assert.deepStrictEqual(link, { fake: 'link' })
@@ -770,7 +772,8 @@ test('addTimedEvent', async (t) => {
770772
await test('adds event to the internal array', (t) => {
771773
const { segment } = t.nr
772774
assert.equal(segment.timedEvents.length, 0)
773-
segment.addTimedEvent({ fake: 'event' })
775+
const added = segment.addTimedEvent({ fake: 'event' })
776+
assert.equal(added, true)
774777
assert.equal(segment.timedEvents.length, 1)
775778
assert.deepStrictEqual(segment.timedEvents[0], { fake: 'event' })
776779
})
@@ -783,7 +786,8 @@ test('addTimedEvent', async (t) => {
783786
}
784787
assert.equal(segment.timedEvents.length, 100)
785788

786-
segment.addTimedEvent({ to: 'drop' })
789+
const added = segment.addTimedEvent({ to: 'drop' })
790+
assert.equal(added, false)
787791
assert.equal(segment.timedEvents.length, 100)
788792
for (const event of segment.timedEvents) {
789793
assert.deepStrictEqual(event, { fake: 'event' })

0 commit comments

Comments
 (0)