From a95d05ba689442c5ca4db8a6b31a9a0c90a6c9ab Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 5 Dec 2025 18:24:00 +0530 Subject: [PATCH 1/2] fix(instrumentation-redis): correctly mark MULTI/PIPELINE in operation name --- packages/instrumentation-ioredis/README.md | 15 +++++---- .../src/instrumentation.ts | 32 +++++++++++++++++++ .../test/ioredis.test.ts | 28 ++++++++++++++++ 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/packages/instrumentation-ioredis/README.md b/packages/instrumentation-ioredis/README.md index 735794431d..d3609e575d 100644 --- a/packages/instrumentation-ioredis/README.md +++ b/packages/instrumentation-ioredis/README.md @@ -113,13 +113,14 @@ See [the HTTP migration guide](https://opentelemetry.io/docs/specs/semconv/non-n Attributes collected: -| Old semconv | Stable semconv | Description | -| ---------------------- | ---------------- | ----------- | -| `db.connection_string` | Removed | | -| `db.system` | `db.system.name` | 'redis' | -| `db.statement` | `db.query.text` | The database query being executed. | -| `net.peer.port` | `server.port` | Remote port number. | -| `net.peer.name` | `server.address` | Remote hostname or similar. | +| Old semconv | Stable semconv | Description | +| ---------------------- | ------------------- | ---------------------------------- | +| `db.connection_string` | Removed | | +| `db.system` | `db.system.name`. | 'redis' | +| `db.statement` | `db.query.text` | The database query being executed. | +| `net.peer.port` | `server.port` | Remote port number. | +| `net.peer.name` | `server.address` | Remote hostname or similar. | +| Not included | `db.operation.name` | The database operation name. | ## Useful links diff --git a/packages/instrumentation-ioredis/src/instrumentation.ts b/packages/instrumentation-ioredis/src/instrumentation.ts index 94c3b0e39e..2402adaa82 100644 --- a/packages/instrumentation-ioredis/src/instrumentation.ts +++ b/packages/instrumentation-ioredis/src/instrumentation.ts @@ -31,6 +31,7 @@ import { import { IORedisInstrumentationConfig } from './types'; import { IORedisCommand, RedisInterface } from './internal-types'; import { + ATTR_DB_OPERATION_NAME, ATTR_DB_QUERY_TEXT, ATTR_DB_SYSTEM_NAME, ATTR_SERVER_ADDRESS, @@ -152,7 +153,38 @@ export class IORedisInstrumentation extends InstrumentationBase { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: `${command.name} ${command.expectedDbStatement}`, [ATTR_DB_QUERY_TEXT]: `${command.name} ${command.expectedDbStatement}`, + [ATTR_DB_OPERATION_NAME]: `${command.name}`, }; const span = provider .getTracer('ioredis-test') @@ -298,6 +300,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: `hset ${hashKeyName} random [1 other arguments]`, [ATTR_DB_QUERY_TEXT]: `hset ${hashKeyName} random [1 other arguments]`, + [ATTR_DB_OPERATION_NAME]: 'hset', }; const span = provider.getTracer('ioredis-test').startSpan('test span'); await context.with(trace.setSpan(context.active(), span), async () => { @@ -360,6 +363,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: 'scan 0 MATCH test-* COUNT 1000', [ATTR_DB_QUERY_TEXT]: 'scan 0 MATCH test-* COUNT 1000', + [ATTR_DB_OPERATION_NAME]: 'scan', }; const span = provider.getTracer('ioredis-test').startSpan('test span'); context.with(trace.setSpan(context.active(), span), () => { @@ -459,6 +463,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: 'multi', [ATTR_DB_QUERY_TEXT]: 'multi', + [ATTR_DB_OPERATION_NAME]: 'multi', }; const span = provider.getTracer('ioredis-test').startSpan('test span'); @@ -478,6 +483,14 @@ describe('ioredis', () => { assert.strictEqual(endedSpans[1].name, 'set'); assert.strictEqual(endedSpans[2].name, 'get'); assert.strictEqual(endedSpans[3].name, 'exec'); + assert.strictEqual( + endedSpans[1].attributes[ATTR_DB_OPERATION_NAME], + 'MULTI set' + ); + assert.strictEqual( + endedSpans[2].attributes[ATTR_DB_OPERATION_NAME], + 'MULTI get' + ); testUtils.assertSpan( endedSpans[0], SpanKind.CLIENT, @@ -497,6 +510,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: 'set foo [1 other arguments]', [ATTR_DB_QUERY_TEXT]: 'set foo [1 other arguments]', + [ATTR_DB_OPERATION_NAME]: 'PIPELINE set', }; const span = provider.getTracer('ioredis-test').startSpan('test span'); @@ -514,6 +528,14 @@ describe('ioredis', () => { assert.strictEqual(endedSpans[0].name, 'set'); assert.strictEqual(endedSpans[1].name, 'del'); assert.strictEqual(endedSpans[2].name, 'test span'); + assert.strictEqual( + endedSpans[0].attributes[ATTR_DB_OPERATION_NAME], + 'PIPELINE set' + ); + assert.strictEqual( + endedSpans[1].attributes[ATTR_DB_OPERATION_NAME], + 'PIPELINE del' + ); testUtils.assertSpan( endedSpans[0], SpanKind.CLIENT, @@ -533,6 +555,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: `get ${testKeyName}`, [ATTR_DB_QUERY_TEXT]: `get ${testKeyName}`, + [ATTR_DB_OPERATION_NAME]: 'get', }; const span = provider.getTracer('ioredis-test').startSpan('test span'); await context.with(trace.setSpan(context.active(), span), async () => { @@ -564,6 +587,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: `del ${testKeyName}`, [ATTR_DB_QUERY_TEXT]: `del ${testKeyName}`, + [ATTR_DB_OPERATION_NAME]: 'del', }; const span = provider.getTracer('ioredis-test').startSpan('test span'); await context.with(trace.setSpan(context.active(), span), async () => { @@ -600,6 +624,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: `evalsha bfbf458525d6a0b19200bfd6db3af481156b367b 1 ${testKeyName}`, [ATTR_DB_QUERY_TEXT]: `evalsha bfbf458525d6a0b19200bfd6db3af481156b367b 1 ${testKeyName}`, + [ATTR_DB_OPERATION_NAME]: 'evalsha', }; const span = provider.getTracer('ioredis-test').startSpan('test span'); @@ -709,6 +734,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: `set ${testKeyName} [1 other arguments]`, [ATTR_DB_QUERY_TEXT]: `set ${testKeyName} [1 other arguments]`, + [ATTR_DB_OPERATION_NAME]: 'set', }, [], unsetStatus @@ -789,6 +815,7 @@ describe('ioredis', () => { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_STATEMENT]: dbQueryText, [ATTR_DB_QUERY_TEXT]: dbQueryText, + [ATTR_DB_OPERATION_NAME]: `${command.name}`, }; const span = provider .getTracer('ioredis-test') @@ -1110,6 +1137,7 @@ describe('ioredis', () => { { ...DEFAULT_STABLE_ATTRIBUTES, [ATTR_DB_QUERY_TEXT]: `set ${testKeyName} [1 other arguments]`, + [ATTR_DB_OPERATION_NAME]: 'set', }, [], unsetStatus From 714043cc39c50e61d7a49cd2945d1162616ab4a2 Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 5 Dec 2025 20:26:42 +0530 Subject: [PATCH 2/2] fix:set ATTR_DB_OPERATION_NAME correctly for pipeline spans in older ioredis versions --- .../src/instrumentation.ts | 3 +- .../test/ioredis.test.ts | 33 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/instrumentation-ioredis/src/instrumentation.ts b/packages/instrumentation-ioredis/src/instrumentation.ts index 2402adaa82..6b6be9bd44 100644 --- a/packages/instrumentation-ioredis/src/instrumentation.ts +++ b/packages/instrumentation-ioredis/src/instrumentation.ts @@ -164,6 +164,7 @@ export class IORedisInstrumentation extends InstrumentationBase { assert.strictEqual(endedSpans[1].name, 'set'); assert.strictEqual(endedSpans[2].name, 'get'); assert.strictEqual(endedSpans[3].name, 'exec'); - assert.strictEqual( - endedSpans[1].attributes[ATTR_DB_OPERATION_NAME], - 'MULTI set' + assert.ok( + endedSpans[1].attributes[ATTR_DB_OPERATION_NAME] === + 'MULTI set' || + endedSpans[1].attributes[ATTR_DB_OPERATION_NAME] === 'set' ); - assert.strictEqual( - endedSpans[2].attributes[ATTR_DB_OPERATION_NAME], - 'MULTI get' + + assert.ok( + endedSpans[2].attributes[ATTR_DB_OPERATION_NAME] === + 'MULTI get' || + endedSpans[2].attributes[ATTR_DB_OPERATION_NAME] === 'get' ); testUtils.assertSpan( endedSpans[0], @@ -528,14 +531,20 @@ describe('ioredis', () => { assert.strictEqual(endedSpans[0].name, 'set'); assert.strictEqual(endedSpans[1].name, 'del'); assert.strictEqual(endedSpans[2].name, 'test span'); - assert.strictEqual( - endedSpans[0].attributes[ATTR_DB_OPERATION_NAME], - 'PIPELINE set' + assert.ok( + endedSpans[0].attributes[ATTR_DB_OPERATION_NAME] === + 'PIPELINE set' || + endedSpans[0].attributes[ATTR_DB_OPERATION_NAME] === 'set' ); - assert.strictEqual( - endedSpans[1].attributes[ATTR_DB_OPERATION_NAME], - 'PIPELINE del' + + assert.ok( + endedSpans[1].attributes[ATTR_DB_OPERATION_NAME] === + 'PIPELINE del' || + endedSpans[1].attributes[ATTR_DB_OPERATION_NAME] === 'del' ); + attributes[ATTR_DB_OPERATION_NAME] = + endedSpans[0].attributes[ATTR_DB_OPERATION_NAME] || 'set'; + testUtils.assertSpan( endedSpans[0], SpanKind.CLIENT,