Skip to content

Commit a95d05b

Browse files
committed
fix(instrumentation-redis): correctly mark MULTI/PIPELINE in operation name
1 parent 53a6c94 commit a95d05b

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed

packages/instrumentation-ioredis/README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,14 @@ See [the HTTP migration guide](https://opentelemetry.io/docs/specs/semconv/non-n
113113

114114
Attributes collected:
115115

116-
| Old semconv | Stable semconv | Description |
117-
| ---------------------- | ---------------- | ----------- |
118-
| `db.connection_string` | Removed | |
119-
| `db.system` | `db.system.name` | 'redis' |
120-
| `db.statement` | `db.query.text` | The database query being executed. |
121-
| `net.peer.port` | `server.port` | Remote port number. |
122-
| `net.peer.name` | `server.address` | Remote hostname or similar. |
116+
| Old semconv | Stable semconv | Description |
117+
| ---------------------- | ------------------- | ---------------------------------- |
118+
| `db.connection_string` | Removed | |
119+
| `db.system` | `db.system.name`. | 'redis' |
120+
| `db.statement` | `db.query.text` | The database query being executed. |
121+
| `net.peer.port` | `server.port` | Remote port number. |
122+
| `net.peer.name` | `server.address` | Remote hostname or similar. |
123+
| Not included | `db.operation.name` | The database operation name. |
123124

124125

125126
## Useful links

packages/instrumentation-ioredis/src/instrumentation.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
import { IORedisInstrumentationConfig } from './types';
3232
import { IORedisCommand, RedisInterface } from './internal-types';
3333
import {
34+
ATTR_DB_OPERATION_NAME,
3435
ATTR_DB_QUERY_TEXT,
3536
ATTR_DB_SYSTEM_NAME,
3637
ATTR_SERVER_ADDRESS,
@@ -152,7 +153,38 @@ export class IORedisInstrumentation extends InstrumentationBase<IORedisInstrumen
152153
}
153154

154155
const attributes: Attributes = {};
156+
157+
let operationName = cmd.name;
158+
const command = cmd as any;
159+
160+
/**
161+
* ioredis sets metadata differently for MULTI/EXEC vs pipelines:
162+
* - MULTI/EXEC: queued commands have inTransaction = true; pipelineIndex tracks order in the transaction.
163+
* - Pipeline: commands have inTransaction = false; pipelineIndex increments per command (0, 1, 2…).
164+
*
165+
* Control commands ('multi'/'exec') are not prefixed.
166+
* These flags are used to prefix operation names so spans reflect transactional or pipelined commands.
167+
*/
168+
if (
169+
command.inTransaction &&
170+
cmd.name !== 'multi' &&
171+
cmd.name !== 'exec'
172+
) {
173+
operationName = `MULTI ${cmd.name}`;
174+
} else if (
175+
command.pipelineIndex != null &&
176+
cmd.name !== 'multi' &&
177+
cmd.name !== 'exec'
178+
) {
179+
operationName = `PIPELINE ${cmd.name}`;
180+
}
181+
182+
if (instrumentation._dbSemconvStability & SemconvStability.STABLE) {
183+
attributes[ATTR_DB_OPERATION_NAME] = operationName;
184+
}
185+
155186
const { host, port } = this.options;
187+
156188
const dbQueryText = dbStatementSerializer(cmd.name, cmd.args);
157189
if (instrumentation._dbSemconvStability & SemconvStability.OLD) {
158190
attributes[ATTR_DB_SYSTEM] = DB_SYSTEM_VALUE_REDIS;

packages/instrumentation-ioredis/test/ioredis.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
IORedisRequestHookInformation,
4141
} from '../src/types';
4242
import {
43+
ATTR_DB_OPERATION_NAME,
4344
ATTR_DB_QUERY_TEXT,
4445
ATTR_DB_SYSTEM_NAME,
4546
ATTR_EXCEPTION_MESSAGE,
@@ -266,6 +267,7 @@ describe('ioredis', () => {
266267
...DEFAULT_STABLE_ATTRIBUTES,
267268
[ATTR_DB_STATEMENT]: `${command.name} ${command.expectedDbStatement}`,
268269
[ATTR_DB_QUERY_TEXT]: `${command.name} ${command.expectedDbStatement}`,
270+
[ATTR_DB_OPERATION_NAME]: `${command.name}`,
269271
};
270272
const span = provider
271273
.getTracer('ioredis-test')
@@ -298,6 +300,7 @@ describe('ioredis', () => {
298300
...DEFAULT_STABLE_ATTRIBUTES,
299301
[ATTR_DB_STATEMENT]: `hset ${hashKeyName} random [1 other arguments]`,
300302
[ATTR_DB_QUERY_TEXT]: `hset ${hashKeyName} random [1 other arguments]`,
303+
[ATTR_DB_OPERATION_NAME]: 'hset',
301304
};
302305
const span = provider.getTracer('ioredis-test').startSpan('test span');
303306
await context.with(trace.setSpan(context.active(), span), async () => {
@@ -360,6 +363,7 @@ describe('ioredis', () => {
360363
...DEFAULT_STABLE_ATTRIBUTES,
361364
[ATTR_DB_STATEMENT]: 'scan 0 MATCH test-* COUNT 1000',
362365
[ATTR_DB_QUERY_TEXT]: 'scan 0 MATCH test-* COUNT 1000',
366+
[ATTR_DB_OPERATION_NAME]: 'scan',
363367
};
364368
const span = provider.getTracer('ioredis-test').startSpan('test span');
365369
context.with(trace.setSpan(context.active(), span), () => {
@@ -459,6 +463,7 @@ describe('ioredis', () => {
459463
...DEFAULT_STABLE_ATTRIBUTES,
460464
[ATTR_DB_STATEMENT]: 'multi',
461465
[ATTR_DB_QUERY_TEXT]: 'multi',
466+
[ATTR_DB_OPERATION_NAME]: 'multi',
462467
};
463468

464469
const span = provider.getTracer('ioredis-test').startSpan('test span');
@@ -478,6 +483,14 @@ describe('ioredis', () => {
478483
assert.strictEqual(endedSpans[1].name, 'set');
479484
assert.strictEqual(endedSpans[2].name, 'get');
480485
assert.strictEqual(endedSpans[3].name, 'exec');
486+
assert.strictEqual(
487+
endedSpans[1].attributes[ATTR_DB_OPERATION_NAME],
488+
'MULTI set'
489+
);
490+
assert.strictEqual(
491+
endedSpans[2].attributes[ATTR_DB_OPERATION_NAME],
492+
'MULTI get'
493+
);
481494
testUtils.assertSpan(
482495
endedSpans[0],
483496
SpanKind.CLIENT,
@@ -497,6 +510,7 @@ describe('ioredis', () => {
497510
...DEFAULT_STABLE_ATTRIBUTES,
498511
[ATTR_DB_STATEMENT]: 'set foo [1 other arguments]',
499512
[ATTR_DB_QUERY_TEXT]: 'set foo [1 other arguments]',
513+
[ATTR_DB_OPERATION_NAME]: 'PIPELINE set',
500514
};
501515

502516
const span = provider.getTracer('ioredis-test').startSpan('test span');
@@ -514,6 +528,14 @@ describe('ioredis', () => {
514528
assert.strictEqual(endedSpans[0].name, 'set');
515529
assert.strictEqual(endedSpans[1].name, 'del');
516530
assert.strictEqual(endedSpans[2].name, 'test span');
531+
assert.strictEqual(
532+
endedSpans[0].attributes[ATTR_DB_OPERATION_NAME],
533+
'PIPELINE set'
534+
);
535+
assert.strictEqual(
536+
endedSpans[1].attributes[ATTR_DB_OPERATION_NAME],
537+
'PIPELINE del'
538+
);
517539
testUtils.assertSpan(
518540
endedSpans[0],
519541
SpanKind.CLIENT,
@@ -533,6 +555,7 @@ describe('ioredis', () => {
533555
...DEFAULT_STABLE_ATTRIBUTES,
534556
[ATTR_DB_STATEMENT]: `get ${testKeyName}`,
535557
[ATTR_DB_QUERY_TEXT]: `get ${testKeyName}`,
558+
[ATTR_DB_OPERATION_NAME]: 'get',
536559
};
537560
const span = provider.getTracer('ioredis-test').startSpan('test span');
538561
await context.with(trace.setSpan(context.active(), span), async () => {
@@ -564,6 +587,7 @@ describe('ioredis', () => {
564587
...DEFAULT_STABLE_ATTRIBUTES,
565588
[ATTR_DB_STATEMENT]: `del ${testKeyName}`,
566589
[ATTR_DB_QUERY_TEXT]: `del ${testKeyName}`,
590+
[ATTR_DB_OPERATION_NAME]: 'del',
567591
};
568592
const span = provider.getTracer('ioredis-test').startSpan('test span');
569593
await context.with(trace.setSpan(context.active(), span), async () => {
@@ -600,6 +624,7 @@ describe('ioredis', () => {
600624
...DEFAULT_STABLE_ATTRIBUTES,
601625
[ATTR_DB_STATEMENT]: `evalsha bfbf458525d6a0b19200bfd6db3af481156b367b 1 ${testKeyName}`,
602626
[ATTR_DB_QUERY_TEXT]: `evalsha bfbf458525d6a0b19200bfd6db3af481156b367b 1 ${testKeyName}`,
627+
[ATTR_DB_OPERATION_NAME]: 'evalsha',
603628
};
604629

605630
const span = provider.getTracer('ioredis-test').startSpan('test span');
@@ -709,6 +734,7 @@ describe('ioredis', () => {
709734
...DEFAULT_STABLE_ATTRIBUTES,
710735
[ATTR_DB_STATEMENT]: `set ${testKeyName} [1 other arguments]`,
711736
[ATTR_DB_QUERY_TEXT]: `set ${testKeyName} [1 other arguments]`,
737+
[ATTR_DB_OPERATION_NAME]: 'set',
712738
},
713739
[],
714740
unsetStatus
@@ -789,6 +815,7 @@ describe('ioredis', () => {
789815
...DEFAULT_STABLE_ATTRIBUTES,
790816
[ATTR_DB_STATEMENT]: dbQueryText,
791817
[ATTR_DB_QUERY_TEXT]: dbQueryText,
818+
[ATTR_DB_OPERATION_NAME]: `${command.name}`,
792819
};
793820
const span = provider
794821
.getTracer('ioredis-test')
@@ -1110,6 +1137,7 @@ describe('ioredis', () => {
11101137
{
11111138
...DEFAULT_STABLE_ATTRIBUTES,
11121139
[ATTR_DB_QUERY_TEXT]: `set ${testKeyName} [1 other arguments]`,
1140+
[ATTR_DB_OPERATION_NAME]: 'set',
11131141
},
11141142
[],
11151143
unsetStatus

0 commit comments

Comments
 (0)