Skip to content

Commit acfe953

Browse files
authored
feat: Added timeslice metrics for synthesized consumer segments (#2938)
1 parent 8e32ed7 commit acfe953

File tree

5 files changed

+67
-8
lines changed

5 files changed

+67
-8
lines changed

lib/metrics/recorders/message-transaction.js

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77

88
const NAMES = require('../../metrics/names.js')
99

10+
/**
11+
* @param {TraceSegment} segment
12+
* @param {object} scope
13+
* @param {Transaction} tx
14+
*/
1015
function recordMessageTransaction(segment, scope, tx) {
1116
if (tx.type !== 'message' || tx.baseSegment !== segment) {
1217
return

lib/otel/constants.js

+16
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,22 @@ module.exports = {
141141
*/
142142
ATTR_MESSAGING_DESTINATION_NAME: 'messaging.destination.name',
143143

144+
/**
145+
* Identifies the type of messaging consumer operation.
146+
*
147+
* {@link ATTR_MESSAGING_OPERATION_NAME} is newer and should be used.
148+
*/
149+
ATTR_MESSAGING_OPERATION: 'messaging.operation',
150+
151+
/**
152+
* Name of the operation being performed. Value is specific to the
153+
* target messaging system.
154+
*
155+
* @example ack
156+
* @example send
157+
*/
158+
ATTR_MESSAGING_OPERATION_NAME: 'messaging.operation.name',
159+
144160
/**
145161
* Target messaging system name.
146162
*

lib/otel/segments/consumer.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module.exports = createConsumerSegment
1313
// attributes according to our own internal specs.
1414

1515
const Transaction = require('../../transaction/')
16+
const recorder = require('../../metrics/recorders/message-transaction')
1617
const { DESTINATIONS, TYPES } = Transaction
1718

1819
const {
@@ -23,12 +24,12 @@ const {
2324

2425
function createConsumerSegment(agent, otelSpan) {
2526
const transaction = new Transaction(agent)
26-
transaction.type = TYPES.BG
27+
transaction.type = TYPES.MESSAGE
2728

2829
const system = otelSpan.attributes[ATTR_MESSAGING_SYSTEM] ?? 'unknown'
2930
const destination = otelSpan.attributes[ATTR_MESSAGING_DESTINATION] ?? 'unknown'
3031
const destKind = otelSpan.attributes[ATTR_MESSAGING_DESTINATION_KIND] ?? 'unknown'
31-
const segmentName = `OtherTransaction/Message/${system}/${destKind}/Named/${destination}`
32+
const segmentName = `${system}/${destKind}/Named/${destination}`
3233

3334
const txAttrs = transaction.trace.attributes
3435
txAttrs.addAttribute(DESTINATIONS.TRANS_SCOPE, 'message.queueName', destination)
@@ -37,10 +38,11 @@ function createConsumerSegment(agent, otelSpan) {
3738
// 'host',
3839
//
3940
// )
40-
transaction.name = segmentName
41+
transaction.setPartialName(segmentName)
4142

4243
const segment = agent.tracer.createSegment({
43-
name: segmentName,
44+
recorder,
45+
name: transaction.getFullName(),
4446
parent: transaction.trace.root,
4547
transaction
4648
})

test/unit/lib/otel/consumer.test.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,14 @@ test('should create consumer segment from otel span', (t) => {
5757

5858
const expectedName = 'OtherTransaction/Message/msgqueuer/topic1/Named/dest1'
5959
const { segment, transaction } = synth.synthesize(span)
60+
transaction.end()
6061
assert.equal(segment.name, expectedName)
6162
assert.equal(segment.parentId, segment.root.id)
6263
assert.equal(transaction.name, expectedName)
63-
assert.equal(transaction.type, 'bg')
64+
assert.equal(transaction.type, 'message')
6465
assert.equal(transaction.baseSegment, segment)
6566
assert.equal(
6667
transaction.trace.attributes.get(DESTINATIONS.TRANS_SCOPE)['message.queueName'],
6768
'dest1'
6869
)
69-
70-
transaction.end()
7170
})

test/versioned/otel-bridge/span.test.js

+38-1
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ const {
2020
ATTR_GRPC_STATUS_CODE,
2121
ATTR_HTTP_HOST,
2222
ATTR_HTTP_METHOD,
23-
ATTR_HTTP_URL,
2423
ATTR_HTTP_ROUTE,
2524
ATTR_HTTP_STATUS_CODE,
2625
ATTR_HTTP_STATUS_TEXT,
26+
ATTR_HTTP_URL,
2727
ATTR_MESSAGING_DESTINATION,
2828
ATTR_MESSAGING_DESTINATION_KIND,
29+
ATTR_MESSAGING_OPERATION,
2930
ATTR_MESSAGING_SYSTEM,
3031
ATTR_NET_PEER_NAME,
3132
ATTR_NET_PEER_PORT,
@@ -394,3 +395,39 @@ test('Otel producer span test', (t, end) => {
394395
})
395396
})
396397
})
398+
399+
test('messaging consumer metrics are bridged correctly', (t, end) => {
400+
const { agent, tracer } = t.nr
401+
const attributes = {
402+
[ATTR_MESSAGING_SYSTEM]: 'kafka',
403+
[ATTR_MESSAGING_OPERATION]: 'getMessage',
404+
[ATTR_SERVER_ADDRESS]: '127.0.0.1',
405+
[ATTR_MESSAGING_DESTINATION]: 'work-queue',
406+
[ATTR_MESSAGING_DESTINATION_KIND]: 'queue'
407+
}
408+
409+
tracer.startActiveSpan('consumer-test', { kind: otel.SpanKind.CONSUMER, attributes }, (span) => {
410+
const tx = agent.getTransaction()
411+
const segment = agent.tracer.getSegment()
412+
span.end()
413+
const duration = hrTimeToMilliseconds(span.duration)
414+
assert.equal(duration, segment.getDurationInMillis())
415+
tx.end()
416+
417+
assert.equal(segment.name, 'OtherTransaction/Message/kafka/queue/Named/work-queue')
418+
assert.equal(tx.type, 'message')
419+
420+
const unscopedMetrics = tx.metrics.unscoped
421+
const expectedMetrics = [
422+
'OtherTransaction/all',
423+
'OtherTransaction/Message/all',
424+
'OtherTransaction/Message/kafka/queue/Named/work-queue',
425+
'OtherTransactionTotalTime'
426+
]
427+
for (const expectedMetric of expectedMetrics) {
428+
assert.equal(unscopedMetrics[expectedMetric].callCount, 1, `${expectedMetric}.callCount`)
429+
}
430+
431+
end()
432+
})
433+
})

0 commit comments

Comments
 (0)