Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions packages/instrumentation-ioredis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 33 additions & 0 deletions packages/instrumentation-ioredis/src/instrumentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -152,7 +153,39 @@ export class IORedisInstrumentation extends InstrumentationBase<IORedisInstrumen
}

const attributes: Attributes = {};

let operationName = cmd.name;
const command = cmd as any;

/**
* ioredis sets metadata differently for MULTI/EXEC vs pipelines:
* - MULTI/EXEC: queued commands have inTransaction = true; pipelineIndex tracks order in the transaction.
* - Pipeline: commands have inTransaction = false; pipelineIndex increments per command (0, 1, 2…).
*
* Control commands ('multi'/'exec') are not prefixed.
* These flags are used to prefix operation names so spans reflect transactional or pipelined commands.
* Older ioredis versions (<=4.12.x) do not support prefixed operation names for multi/pipeline commands.
*/
if (
command.inTransaction &&
cmd.name !== 'multi' &&
cmd.name !== 'exec'
) {
operationName = `MULTI ${cmd.name}`;
} else if (
command.pipelineIndex != null &&
cmd.name !== 'multi' &&
cmd.name !== 'exec'
) {
operationName = `PIPELINE ${cmd.name}`;
}

if (instrumentation._dbSemconvStability & SemconvStability.STABLE) {
attributes[ATTR_DB_OPERATION_NAME] = operationName;
}

const { host, port } = this.options;

const dbQueryText = dbStatementSerializer(cmd.name, cmd.args);
if (instrumentation._dbSemconvStability & SemconvStability.OLD) {
attributes[ATTR_DB_SYSTEM] = DB_SYSTEM_VALUE_REDIS;
Expand Down
37 changes: 37 additions & 0 deletions packages/instrumentation-ioredis/test/ioredis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
IORedisRequestHookInformation,
} from '../src/types';
import {
ATTR_DB_OPERATION_NAME,
ATTR_DB_QUERY_TEXT,
ATTR_DB_SYSTEM_NAME,
ATTR_EXCEPTION_MESSAGE,
Expand Down Expand Up @@ -266,6 +267,7 @@ describe('ioredis', () => {
...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')
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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), () => {
Expand Down Expand Up @@ -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');
Expand All @@ -478,6 +483,17 @@ describe('ioredis', () => {
assert.strictEqual(endedSpans[1].name, 'set');
assert.strictEqual(endedSpans[2].name, 'get');
assert.strictEqual(endedSpans[3].name, 'exec');
assert.ok(
endedSpans[1].attributes[ATTR_DB_OPERATION_NAME] ===
'MULTI set' ||
endedSpans[1].attributes[ATTR_DB_OPERATION_NAME] === 'set'
);

assert.ok(
endedSpans[2].attributes[ATTR_DB_OPERATION_NAME] ===
'MULTI get' ||
endedSpans[2].attributes[ATTR_DB_OPERATION_NAME] === 'get'
);
testUtils.assertSpan(
endedSpans[0],
SpanKind.CLIENT,
Expand All @@ -497,6 +513,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');
Expand All @@ -514,6 +531,20 @@ describe('ioredis', () => {
assert.strictEqual(endedSpans[0].name, 'set');
assert.strictEqual(endedSpans[1].name, 'del');
assert.strictEqual(endedSpans[2].name, 'test span');
assert.ok(
endedSpans[0].attributes[ATTR_DB_OPERATION_NAME] ===
'PIPELINE set' ||
endedSpans[0].attributes[ATTR_DB_OPERATION_NAME] === 'set'
);

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,
Expand All @@ -533,6 +564,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 () => {
Expand Down Expand Up @@ -564,6 +596,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 () => {
Expand Down Expand Up @@ -600,6 +633,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');
Expand Down Expand Up @@ -709,6 +743,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
Expand Down Expand Up @@ -789,6 +824,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')
Expand Down Expand Up @@ -1110,6 +1146,7 @@ describe('ioredis', () => {
{
...DEFAULT_STABLE_ATTRIBUTES,
[ATTR_DB_QUERY_TEXT]: `set ${testKeyName} [1 other arguments]`,
[ATTR_DB_OPERATION_NAME]: 'set',
},
[],
unsetStatus
Expand Down
Loading