From f44b587228fa33b07fccb0a694648ab9e173ee49 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Wed, 28 May 2025 07:39:24 +0700 Subject: [PATCH 01/28] refactor(instrumentation-redis): support multi versions as seprate inst objects --- .../src/instrumentation.ts | 148 ++++-------------- .../src/v1-2-3/instrumentation.ts | 118 ++++++++++++++ .../src/{ => v1-2-3}/internal-types.ts | 0 .../src/{ => v1-2-3}/utils.ts | 5 +- 4 files changed, 151 insertions(+), 120 deletions(-) create mode 100644 plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/instrumentation.ts rename plugins/node/opentelemetry-instrumentation-redis/src/{ => v1-2-3}/internal-types.ts (100%) rename plugins/node/opentelemetry-instrumentation-redis/src/{ => v1-2-3}/utils.ts (96%) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts index dd0960d533..fd24cb55fc 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts @@ -1,123 +1,37 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - isWrapped, - InstrumentationBase, - InstrumentationNodeModuleDefinition, -} from '@opentelemetry/instrumentation'; -import { - getTracedCreateClient, - getTracedCreateStreamTrace, - getTracedInternalSendCommand, -} from './utils'; -import { RedisInstrumentationConfig } from './types'; -/** @knipignore */ -import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; +import { InstrumentationBase } from "@opentelemetry/instrumentation"; +import { RedisInstrumentationConfig } from "./types"; +import { PACKAGE_NAME, PACKAGE_VERSION } from "./version"; +import { RedisInstrumentationV1_2_3 } from "./v1-2-3/instrumentation"; const DEFAULT_CONFIG: RedisInstrumentationConfig = { - requireParentSpan: false, + requireParentSpan: false, }; +// Wrapper RedisInstrumentation that address all supported versions export class RedisInstrumentation extends InstrumentationBase { - static readonly COMPONENT = 'redis'; - - constructor(config: RedisInstrumentationConfig = {}) { - super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); - } - - override setConfig(config: RedisInstrumentationConfig = {}) { - super.setConfig({ ...DEFAULT_CONFIG, ...config }); - } - - protected init() { - return [ - new InstrumentationNodeModuleDefinition( - 'redis', - ['>=2.6.0 <4'], - moduleExports => { - if ( - isWrapped( - moduleExports.RedisClient.prototype['internal_send_command'] - ) - ) { - this._unwrap( - moduleExports.RedisClient.prototype, - 'internal_send_command' - ); - } - this._wrap( - moduleExports.RedisClient.prototype, - 'internal_send_command', - this._getPatchInternalSendCommand() - ); - - if (isWrapped(moduleExports.RedisClient.prototype['create_stream'])) { - this._unwrap(moduleExports.RedisClient.prototype, 'create_stream'); - } - this._wrap( - moduleExports.RedisClient.prototype, - 'create_stream', - this._getPatchCreateStream() - ); - - if (isWrapped(moduleExports.createClient)) { - this._unwrap(moduleExports, 'createClient'); - } - this._wrap( - moduleExports, - 'createClient', - this._getPatchCreateClient() - ); - return moduleExports; - }, - moduleExports => { - if (moduleExports === undefined) return; - this._unwrap( - moduleExports.RedisClient.prototype, - 'internal_send_command' - ); - this._unwrap(moduleExports.RedisClient.prototype, 'create_stream'); - this._unwrap(moduleExports, 'createClient'); - } - ), - ]; - } - /** - * Patch internal_send_command(...) to trace requests - */ - private _getPatchInternalSendCommand() { - const tracer = this.tracer; - const config = this.getConfig(); - return function internal_send_command(original: Function) { - return getTracedInternalSendCommand(tracer, original, config); - }; - } - - private _getPatchCreateClient() { - const tracer = this.tracer; - return function createClient(original: Function) { - return getTracedCreateClient(tracer, original); - }; - } - private _getPatchCreateStream() { - const tracer = this.tracer; - return function createReadStream(original: Function) { - return getTracedCreateStreamTrace(tracer, original); - }; - } -} + private instrumentationV1_2_3?: RedisInstrumentationV1_2_3; + + constructor(config: RedisInstrumentationConfig = {}) { + super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); + } + + override setConfig(config: RedisInstrumentationConfig = {}) { + const newConfig = { ...DEFAULT_CONFIG, ...config }; + super.setConfig(newConfig); + + // set the configs on all specific version instrumentations + // this function is also called in constructor, before the specific version instrumentations are initialized + // which we need to avoid. + this.instrumentationV1_2_3?.setConfig(newConfig); + } + + override init() { + this.instrumentationV1_2_3 = new RedisInstrumentationV1_2_3(this.getConfig()); + const v1_2_3_patches = this.instrumentationV1_2_3.init(); + + return [ + ...v1_2_3_patches, + ]; + } +} \ No newline at end of file diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/instrumentation.ts new file mode 100644 index 0000000000..caab0af781 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/instrumentation.ts @@ -0,0 +1,118 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + isWrapped, + InstrumentationBase, + InstrumentationNodeModuleDefinition, +} from '@opentelemetry/instrumentation'; +import { + getTracedCreateClient, + getTracedCreateStreamTrace, + getTracedInternalSendCommand, +} from './utils'; +import { RedisInstrumentationConfig } from '../types'; +/** @knipignore */ +import { PACKAGE_NAME, PACKAGE_VERSION } from '../version'; + +export class RedisInstrumentationV1_2_3 extends InstrumentationBase { + + constructor(config: RedisInstrumentationConfig = {}) { + super(PACKAGE_NAME, PACKAGE_VERSION, config); + } + + override setConfig(config: RedisInstrumentationConfig = {}) { + super.setConfig(config); + } + + public init() { + return [ + new InstrumentationNodeModuleDefinition( + 'redis', + ['>=2.6.0 <4'], + moduleExports => { + if ( + isWrapped( + moduleExports.RedisClient.prototype['internal_send_command'] + ) + ) { + this._unwrap( + moduleExports.RedisClient.prototype, + 'internal_send_command' + ); + } + this._wrap( + moduleExports.RedisClient.prototype, + 'internal_send_command', + this._getPatchInternalSendCommand() + ); + + if (isWrapped(moduleExports.RedisClient.prototype['create_stream'])) { + this._unwrap(moduleExports.RedisClient.prototype, 'create_stream'); + } + this._wrap( + moduleExports.RedisClient.prototype, + 'create_stream', + this._getPatchCreateStream() + ); + + if (isWrapped(moduleExports.createClient)) { + this._unwrap(moduleExports, 'createClient'); + } + this._wrap( + moduleExports, + 'createClient', + this._getPatchCreateClient() + ); + return moduleExports; + }, + moduleExports => { + if (moduleExports === undefined) return; + this._unwrap( + moduleExports.RedisClient.prototype, + 'internal_send_command' + ); + this._unwrap(moduleExports.RedisClient.prototype, 'create_stream'); + this._unwrap(moduleExports, 'createClient'); + } + ), + ]; + } + /** + * Patch internal_send_command(...) to trace requests + */ + private _getPatchInternalSendCommand() { + const tracer = this.tracer; + const config = this.getConfig(); + return function internal_send_command(original: Function) { + return getTracedInternalSendCommand(tracer, original, config); + }; + } + + private _getPatchCreateClient() { + const tracer = this.tracer; + return function createClient(original: Function) { + return getTracedCreateClient(tracer, original); + }; + } + + private _getPatchCreateStream() { + const tracer = this.tracer; + return function createReadStream(original: Function) { + return getTracedCreateStreamTrace(tracer, original); + }; + } +} diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/internal-types.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/internal-types.ts similarity index 100% rename from plugins/node/opentelemetry-instrumentation-redis/src/internal-types.ts rename to plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/internal-types.ts diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/utils.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/utils.ts similarity index 96% rename from plugins/node/opentelemetry-instrumentation-redis/src/utils.ts rename to plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/utils.ts index d863089f30..7b7196fc56 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/utils.ts @@ -24,9 +24,8 @@ import { trace, diag, } from '@opentelemetry/api'; -import { RedisCommand, RedisInstrumentationConfig } from './types'; +import { RedisCommand, RedisInstrumentationConfig } from '../types'; import { EventEmitter } from 'events'; -import { RedisInstrumentation } from './'; import { DBSYSTEMVALUES_REDIS, SEMATTRS_DB_CONNECTION_STRING, @@ -100,7 +99,7 @@ export const getTracedInternalSendCommand = ( const dbStatementSerializer = config?.dbStatementSerializer || defaultDbStatementSerializer; const span = tracer.startSpan( - `${RedisInstrumentation.COMPONENT}-${cmd.command}`, + `redis-${cmd.command}`, { kind: SpanKind.CLIENT, attributes: { From 2329836f367f95937bb67479aa84cd7b57363860 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sat, 7 Jun 2025 15:16:13 +0300 Subject: [PATCH 02/28] fix(redis): unit tests for new setup --- .../src/instrumentation.ts | 43 +++++++++++++++---- .../src/v1-2-3/instrumentation.ts | 10 +---- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts index fd24cb55fc..3270b79e6e 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts @@ -2,6 +2,7 @@ import { InstrumentationBase } from "@opentelemetry/instrumentation"; import { RedisInstrumentationConfig } from "./types"; import { PACKAGE_NAME, PACKAGE_VERSION } from "./version"; import { RedisInstrumentationV1_2_3 } from "./v1-2-3/instrumentation"; +import { TracerProvider } from "@opentelemetry/api"; const DEFAULT_CONFIG: RedisInstrumentationConfig = { requireParentSpan: false, @@ -10,10 +11,18 @@ const DEFAULT_CONFIG: RedisInstrumentationConfig = { // Wrapper RedisInstrumentation that address all supported versions export class RedisInstrumentation extends InstrumentationBase { - private instrumentationV1_2_3?: RedisInstrumentationV1_2_3; + private instrumentationV1_2_3: RedisInstrumentationV1_2_3; + + // this is used to bypass a flaw in the base class constructor, which is calling + // member functions before the constructor has a chance to fully initialize the member variables. + private initialized = false; constructor(config: RedisInstrumentationConfig = {}) { - super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); + const resolvedConfig = { ...DEFAULT_CONFIG, ...config }; + super(PACKAGE_NAME, PACKAGE_VERSION, resolvedConfig); + + this.instrumentationV1_2_3 = new RedisInstrumentationV1_2_3(this.getConfig()); + this.initialized = true; } override setConfig(config: RedisInstrumentationConfig = {}) { @@ -27,11 +36,29 @@ export class RedisInstrumentation extends InstrumentationBase { static readonly COMPONENT = 'redis'; constructor(config: RedisInstrumentationConfig = {}) { - super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); - } - - override setConfig(config: RedisInstrumentationConfig = {}) { - super.setConfig({ ...DEFAULT_CONFIG, ...config }); + super(PACKAGE_NAME, PACKAGE_VERSION, config); } protected init() { From 65b09d07257d91d140cd1867326626c9dccd2a81 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sat, 7 Jun 2025 15:45:46 +0300 Subject: [PATCH 03/28] chore: add redis-4 impl to redis inst --- .../src/index.ts | 1 - .../src/instrumentation.ts | 27 +- .../src/types.ts | 18 +- .../src/{v1-2-3 => v2-3}/instrumentation.ts | 8 +- .../src/{v1-2-3 => v2-3}/internal-types.ts | 10 + .../src/{v1-2-3 => v2-3}/utils.ts | 0 .../src/v4/instrumentation.ts | 490 ++++++++++++++++++ .../src/v4/internal-types.ts | 22 + .../src/v4/utils.ts | 63 +++ .../test/{ => v2-3}/redis.test.ts | 10 +- 10 files changed, 615 insertions(+), 34 deletions(-) rename plugins/node/opentelemetry-instrumentation-redis/src/{v1-2-3 => v2-3}/instrumentation.ts (95%) rename plugins/node/opentelemetry-instrumentation-redis/src/{v1-2-3 => v2-3}/internal-types.ts (73%) rename plugins/node/opentelemetry-instrumentation-redis/src/{v1-2-3 => v2-3}/utils.ts (100%) create mode 100644 plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts create mode 100644 plugins/node/opentelemetry-instrumentation-redis/src/v4/internal-types.ts create mode 100644 plugins/node/opentelemetry-instrumentation-redis/src/v4/utils.ts rename plugins/node/opentelemetry-instrumentation-redis/test/{ => v2-3}/redis.test.ts (97%) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/index.ts b/plugins/node/opentelemetry-instrumentation-redis/src/index.ts index 8aee6d3cd5..50c62a0ebc 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/index.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/index.ts @@ -17,7 +17,6 @@ export { RedisInstrumentation } from './instrumentation'; export type { DbStatementSerializer, - RedisCommand, RedisInstrumentationConfig, RedisResponseCustomAttributeFunction, } from './types'; diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts index 3270b79e6e..f4341f9e9a 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts @@ -1,8 +1,9 @@ import { InstrumentationBase } from "@opentelemetry/instrumentation"; import { RedisInstrumentationConfig } from "./types"; import { PACKAGE_NAME, PACKAGE_VERSION } from "./version"; -import { RedisInstrumentationV1_2_3 } from "./v1-2-3/instrumentation"; +import { RedisInstrumentationV2_3 } from "./v2-3/instrumentation"; import { TracerProvider } from "@opentelemetry/api"; +import { RedisInstrumentationV4 } from "./v4/instrumentation"; const DEFAULT_CONFIG: RedisInstrumentationConfig = { requireParentSpan: false, @@ -11,7 +12,8 @@ const DEFAULT_CONFIG: RedisInstrumentationConfig = { // Wrapper RedisInstrumentation that address all supported versions export class RedisInstrumentation extends InstrumentationBase { - private instrumentationV1_2_3: RedisInstrumentationV1_2_3; + private instrumentationV2_3: RedisInstrumentationV2_3; + private instrumentationV4: RedisInstrumentationV4; // this is used to bypass a flaw in the base class constructor, which is calling // member functions before the constructor has a chance to fully initialize the member variables. @@ -21,18 +23,20 @@ export class RedisInstrumentation extends InstrumentationBase void; - call_on_write: boolean; -} - /** * Function that can be used to serialize db.statement tag * @param cmdName - The name of the command (eg. set, get, mset) @@ -35,8 +25,8 @@ export interface RedisCommand { * @returns serialized string that will be used as the db.statement attribute. */ export type DbStatementSerializer = ( - cmdName: RedisCommand['command'], - cmdArgs: RedisCommand['args'] + cmdName: string, + cmdArgs: Array ) => string; /** @@ -51,8 +41,8 @@ export type DbStatementSerializer = ( export interface RedisResponseCustomAttributeFunction { ( span: Span, - cmdName: RedisCommand['command'], - cmdArgs: RedisCommand['args'], + cmdName: string, + cmdArgs: Array, response: unknown ): void; } diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v2-3/instrumentation.ts similarity index 95% rename from plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/instrumentation.ts rename to plugins/node/opentelemetry-instrumentation-redis/src/v2-3/instrumentation.ts index c33a2bd9bd..91f3e72f50 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v2-3/instrumentation.ts @@ -25,10 +25,10 @@ import { getTracedCreateClient, getTracedCreateStreamTrace, } from './utils'; -import { RedisCommand, RedisInstrumentationConfig } from '../types'; +import { RedisInstrumentationConfig } from '../types'; /** @knipignore */ import { PACKAGE_NAME, PACKAGE_VERSION } from '../version'; -import { RedisPluginClientTypes } from './internal-types'; +import { RedisCommand, RedisPluginClientTypes } from './internal-types'; import { SpanKind, context, trace } from '@opentelemetry/api'; import { DBSYSTEMVALUES_REDIS, @@ -40,7 +40,7 @@ import { } from '@opentelemetry/semantic-conventions'; import { defaultDbStatementSerializer } from '@opentelemetry/redis-common'; -export class RedisInstrumentationV1_2_3 extends InstrumentationBase { +export class RedisInstrumentationV2_3 extends InstrumentationBase { static readonly COMPONENT = 'redis'; constructor(config: RedisInstrumentationConfig = {}) { @@ -128,7 +128,7 @@ export class RedisInstrumentationV1_2_3 extends InstrumentationBase void; + call_on_write: boolean; +} diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/utils.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v2-3/utils.ts similarity index 100% rename from plugins/node/opentelemetry-instrumentation-redis/src/v1-2-3/utils.ts rename to plugins/node/opentelemetry-instrumentation-redis/src/v2-3/utils.ts diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts new file mode 100644 index 0000000000..5ef319dfa6 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts @@ -0,0 +1,490 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + trace, + context, + SpanKind, + Span, + SpanStatusCode, +} from '@opentelemetry/api'; +import { + isWrapped, + InstrumentationBase, + InstrumentationNodeModuleDefinition, + InstrumentationNodeModuleFile, +} from '@opentelemetry/instrumentation'; +import { getClientAttributes } from './utils'; +import { defaultDbStatementSerializer } from '@opentelemetry/redis-common'; +import { RedisInstrumentationConfig } from '../types'; +/** @knipignore */ +import { PACKAGE_NAME, PACKAGE_VERSION } from '../version'; +import { SEMATTRS_DB_STATEMENT } from '@opentelemetry/semantic-conventions'; +import type { MultiErrorReply } from './internal-types'; + +const OTEL_OPEN_SPANS = Symbol( + 'opentelemetry.instrumentation.redis.open_spans' +); +const MULTI_COMMAND_OPTIONS = Symbol( + 'opentelemetry.instrumentation.redis.multi_command_options' +); + +interface MutliCommandInfo { + span: Span; + commandName: string; + commandArgs: Array; +} + +const DEFAULT_CONFIG: RedisInstrumentationConfig = { + requireParentSpan: false, +}; + +export class RedisInstrumentationV4 extends InstrumentationBase { + static readonly COMPONENT = 'redis'; + + constructor(config: RedisInstrumentationConfig = {}) { + super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); + } + + override setConfig(config: RedisInstrumentationConfig = {}) { + super.setConfig({ ...DEFAULT_CONFIG, ...config }); + } + + protected init() { + // @node-redis/client is a new package introduced and consumed by 'redis 4.0.x' + // on redis@4.1.0 it was changed to @redis/client. + // we will instrument both packages + return [ + this._getInstrumentationNodeModuleDefinition('@redis/client'), + this._getInstrumentationNodeModuleDefinition('@node-redis/client'), + ]; + } + + private _getInstrumentationNodeModuleDefinition( + basePackageName: string + ): InstrumentationNodeModuleDefinition { + const commanderModuleFile = new InstrumentationNodeModuleFile( + `${basePackageName}/dist/lib/commander.js`, + ['^1.0.0'], + (moduleExports: any, moduleVersion?: string) => { + const transformCommandArguments = + moduleExports.transformCommandArguments; + if (!transformCommandArguments) { + this._diag.error( + 'internal instrumentation error, missing transformCommandArguments function' + ); + return moduleExports; + } + + // function name and signature changed in redis 4.1.0 from 'extendWithCommands' to 'attachCommands' + // the matching internal package names starts with 1.0.x (for redis 4.0.x) + const functionToPatch = moduleVersion?.startsWith('1.0.') + ? 'extendWithCommands' + : 'attachCommands'; + // this is the function that extend a redis client with a list of commands. + // the function patches the commandExecutor to record a span + if (isWrapped(moduleExports?.[functionToPatch])) { + this._unwrap(moduleExports, functionToPatch); + } + this._wrap( + moduleExports, + functionToPatch, + this._getPatchExtendWithCommands(transformCommandArguments) + ); + + return moduleExports; + }, + (moduleExports: any) => { + if (isWrapped(moduleExports?.extendWithCommands)) { + this._unwrap(moduleExports, 'extendWithCommands'); + } + if (isWrapped(moduleExports?.attachCommands)) { + this._unwrap(moduleExports, 'attachCommands'); + } + } + ); + + const multiCommanderModule = new InstrumentationNodeModuleFile( + `${basePackageName}/dist/lib/client/multi-command.js`, + ['^1.0.0'], + (moduleExports: any) => { + const redisClientMultiCommandPrototype = + moduleExports?.default?.prototype; + + if (isWrapped(redisClientMultiCommandPrototype?.exec)) { + this._unwrap(redisClientMultiCommandPrototype, 'exec'); + } + this._wrap( + redisClientMultiCommandPrototype, + 'exec', + this._getPatchMultiCommandsExec() + ); + + if (isWrapped(redisClientMultiCommandPrototype?.addCommand)) { + this._unwrap(redisClientMultiCommandPrototype, 'addCommand'); + } + this._wrap( + redisClientMultiCommandPrototype, + 'addCommand', + this._getPatchMultiCommandsAddCommand() + ); + + return moduleExports; + }, + (moduleExports: any) => { + const redisClientMultiCommandPrototype = + moduleExports?.default?.prototype; + if (isWrapped(redisClientMultiCommandPrototype?.exec)) { + this._unwrap(redisClientMultiCommandPrototype, 'exec'); + } + if (isWrapped(redisClientMultiCommandPrototype?.addCommand)) { + this._unwrap(redisClientMultiCommandPrototype, 'addCommand'); + } + } + ); + + const clientIndexModule = new InstrumentationNodeModuleFile( + `${basePackageName}/dist/lib/client/index.js`, + ['^1.0.0'], + (moduleExports: any) => { + const redisClientPrototype = moduleExports?.default?.prototype; + + // In some @redis/client versions 'multi' is a method. In later + // versions, as of https://github.com/redis/node-redis/pull/2324, + // 'MULTI' is a method and 'multi' is a property defined in the + // constructor that points to 'MULTI', and therefore it will not + // be defined on the prototype. + if (redisClientPrototype?.multi) { + if (isWrapped(redisClientPrototype?.multi)) { + this._unwrap(redisClientPrototype, 'multi'); + } + this._wrap( + redisClientPrototype, + 'multi', + this._getPatchRedisClientMulti() + ); + } + if (redisClientPrototype?.MULTI) { + if (isWrapped(redisClientPrototype?.MULTI)) { + this._unwrap(redisClientPrototype, 'MULTI'); + } + this._wrap( + redisClientPrototype, + 'MULTI', + this._getPatchRedisClientMulti() + ); + } + + if (isWrapped(redisClientPrototype?.sendCommand)) { + this._unwrap(redisClientPrototype, 'sendCommand'); + } + this._wrap( + redisClientPrototype, + 'sendCommand', + this._getPatchRedisClientSendCommand() + ); + + this._wrap( + redisClientPrototype, + 'connect', + this._getPatchedClientConnect() + ); + + return moduleExports; + }, + (moduleExports: any) => { + const redisClientPrototype = moduleExports?.default?.prototype; + if (isWrapped(redisClientPrototype?.multi)) { + this._unwrap(redisClientPrototype, 'multi'); + } + if (isWrapped(redisClientPrototype?.MULTI)) { + this._unwrap(redisClientPrototype, 'MULTI'); + } + if (isWrapped(redisClientPrototype?.sendCommand)) { + this._unwrap(redisClientPrototype, 'sendCommand'); + } + } + ); + + return new InstrumentationNodeModuleDefinition( + basePackageName, + ['^1.0.0'], + (moduleExports: any) => { + return moduleExports; + }, + () => {}, + [commanderModuleFile, multiCommanderModule, clientIndexModule] + ); + } + + // serves both for redis 4.0.x where function name is extendWithCommands + // and redis ^4.1.0 where function name is attachCommands + private _getPatchExtendWithCommands(transformCommandArguments: Function) { + const plugin = this; + return function extendWithCommandsPatchWrapper(original: Function) { + return function extendWithCommandsPatch(this: any, config: any) { + if (config?.BaseClass?.name !== 'RedisClient') { + return original.apply(this, arguments); + } + + const origExecutor = config.executor; + config.executor = function ( + this: any, + command: any, + args: Array + ) { + const redisCommandArguments = transformCommandArguments( + command, + args + ).args; + return plugin._traceClientCommand( + origExecutor, + this, + arguments, + redisCommandArguments + ); + }; + return original.apply(this, arguments); + }; + }; + } + + private _getPatchMultiCommandsExec() { + const plugin = this; + return function execPatchWrapper(original: Function) { + return function execPatch(this: any) { + const execRes = original.apply(this, arguments); + if (typeof execRes?.then !== 'function') { + plugin._diag.error( + 'got non promise result when patching RedisClientMultiCommand.exec' + ); + return execRes; + } + + return execRes + .then((redisRes: unknown[]) => { + const openSpans = this[OTEL_OPEN_SPANS]; + plugin._endSpansWithRedisReplies(openSpans, redisRes); + return redisRes; + }) + .catch((err: Error) => { + const openSpans = this[OTEL_OPEN_SPANS]; + if (!openSpans) { + plugin._diag.error( + 'cannot find open spans to end for redis multi command' + ); + } else { + const replies = + err.constructor.name === 'MultiErrorReply' + ? (err as MultiErrorReply).replies + : new Array(openSpans.length).fill(err); + plugin._endSpansWithRedisReplies(openSpans, replies); + } + return Promise.reject(err); + }); + }; + }; + } + + private _getPatchMultiCommandsAddCommand() { + const plugin = this; + return function addCommandWrapper(original: Function) { + return function addCommandPatch(this: any, args: Array) { + return plugin._traceClientCommand(original, this, arguments, args); + }; + }; + } + + private _getPatchRedisClientMulti() { + return function multiPatchWrapper(original: Function) { + return function multiPatch(this: any) { + const multiRes = original.apply(this, arguments); + multiRes[MULTI_COMMAND_OPTIONS] = this.options; + return multiRes; + }; + }; + } + + private _getPatchRedisClientSendCommand() { + const plugin = this; + return function sendCommandWrapper(original: Function) { + return function sendCommandPatch( + this: any, + args: Array + ) { + return plugin._traceClientCommand(original, this, arguments, args); + }; + }; + } + + private _getPatchedClientConnect() { + const plugin = this; + return function connectWrapper(original: Function) { + return function patchedConnect(this: any): Promise { + const options = this.options; + + const attributes = getClientAttributes(plugin._diag, options); + + const span = plugin.tracer.startSpan( + `${RedisInstrumentationV4.COMPONENT}-connect`, + { + kind: SpanKind.CLIENT, + attributes, + } + ); + + const res = context.with(trace.setSpan(context.active(), span), () => { + return original.apply(this); + }); + + return res + .then((result: unknown) => { + span.end(); + return result; + }) + .catch((error: Error) => { + span.recordException(error); + span.setStatus({ + code: SpanStatusCode.ERROR, + message: error.message, + }); + span.end(); + return Promise.reject(error); + }); + }; + }; + } + + private _traceClientCommand( + origFunction: Function, + origThis: any, + origArguments: IArguments, + redisCommandArguments: Array + ) { + const hasNoParentSpan = trace.getSpan(context.active()) === undefined; + if (hasNoParentSpan && this.getConfig().requireParentSpan) { + return origFunction.apply(origThis, origArguments); + } + + const clientOptions = origThis.options || origThis[MULTI_COMMAND_OPTIONS]; + + const commandName = redisCommandArguments[0] as string; // types also allows it to be a Buffer, but in practice it only string + const commandArgs = redisCommandArguments.slice(1); + + const dbStatementSerializer = + this.getConfig().dbStatementSerializer || defaultDbStatementSerializer; + + const attributes = getClientAttributes(this._diag, clientOptions); + + try { + const dbStatement = dbStatementSerializer(commandName, commandArgs); + if (dbStatement != null) { + attributes[SEMATTRS_DB_STATEMENT] = dbStatement; + } + } catch (e) { + this._diag.error('dbStatementSerializer throw an exception', e, { + commandName, + }); + } + + const span = this.tracer.startSpan( + `${RedisInstrumentationV4.COMPONENT}-${commandName}`, + { + kind: SpanKind.CLIENT, + attributes, + } + ); + + const res = context.with(trace.setSpan(context.active(), span), () => { + return origFunction.apply(origThis, origArguments); + }); + if (typeof res?.then === 'function') { + res.then( + (redisRes: unknown) => { + this._endSpanWithResponse( + span, + commandName, + commandArgs, + redisRes, + undefined + ); + }, + (err: any) => { + this._endSpanWithResponse(span, commandName, commandArgs, null, err); + } + ); + } else { + const redisClientMultiCommand = res as { + [OTEL_OPEN_SPANS]?: Array; + }; + redisClientMultiCommand[OTEL_OPEN_SPANS] = + redisClientMultiCommand[OTEL_OPEN_SPANS] || []; + redisClientMultiCommand[OTEL_OPEN_SPANS]!.push({ + span, + commandName, + commandArgs, + }); + } + return res; + } + + private _endSpansWithRedisReplies( + openSpans: Array, + replies: unknown[] + ) { + if (!openSpans) { + return this._diag.error( + 'cannot find open spans to end for redis multi command' + ); + } + if (replies.length !== openSpans.length) { + return this._diag.error( + 'number of multi command spans does not match response from redis' + ); + } + for (let i = 0; i < openSpans.length; i++) { + const { span, commandName, commandArgs } = openSpans[i]; + const currCommandRes = replies[i]; + const [res, err] = + currCommandRes instanceof Error + ? [null, currCommandRes] + : [currCommandRes, undefined]; + this._endSpanWithResponse(span, commandName, commandArgs, res, err); + } + } + + private _endSpanWithResponse( + span: Span, + commandName: string, + commandArgs: Array, + response: unknown, + error: Error | undefined + ) { + const { responseHook } = this.getConfig(); + if (!error && responseHook) { + try { + responseHook(span, commandName, commandArgs, response); + } catch (err) { + this._diag.error('responseHook throw an exception', err); + } + } + if (error) { + span.recordException(error); + span.setStatus({ code: SpanStatusCode.ERROR, message: error?.message }); + } + span.end(); + } +} diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v4/internal-types.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v4/internal-types.ts new file mode 100644 index 0000000000..cf03d290d1 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v4/internal-types.ts @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Error class introduced in redis@4.6.12. +// https://github.com/redis/node-redis/blob/redis@4.6.12/packages/client/lib/errors.ts#L69-L84 +export interface MultiErrorReply extends Error { + replies: unknown[]; + errorIndexes: Array; +} diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v4/utils.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v4/utils.ts new file mode 100644 index 0000000000..b7cc79628d --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v4/utils.ts @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Attributes, DiagLogger } from '@opentelemetry/api'; +import { + SEMATTRS_DB_SYSTEM, + SEMATTRS_DB_CONNECTION_STRING, + SEMATTRS_NET_PEER_NAME, + SEMATTRS_NET_PEER_PORT, + DBSYSTEMVALUES_REDIS, +} from '@opentelemetry/semantic-conventions'; + +export function getClientAttributes( + diag: DiagLogger, + options: any +): Attributes { + return { + [SEMATTRS_DB_SYSTEM]: DBSYSTEMVALUES_REDIS, + [SEMATTRS_NET_PEER_NAME]: options?.socket?.host, + [SEMATTRS_NET_PEER_PORT]: options?.socket?.port, + [SEMATTRS_DB_CONNECTION_STRING]: + removeCredentialsFromDBConnectionStringAttribute(diag, options?.url), + }; +} + +/** + * removeCredentialsFromDBConnectionStringAttribute removes basic auth from url and user_pwd from query string + * + * Examples: + * redis://user:pass@localhost:6379/mydb => redis://localhost:6379/mydb + * redis://localhost:6379?db=mydb&user_pwd=pass => redis://localhost:6379?db=mydb + */ +function removeCredentialsFromDBConnectionStringAttribute( + diag: DiagLogger, + url?: unknown +): string | undefined { + if (typeof url !== 'string' || !url) { + return; + } + + try { + const u = new URL(url); + u.searchParams.delete('user_pwd'); + u.username = ''; + u.password = ''; + return u.href; + } catch (err) { + diag.error('failed to sanitize redis connection url', err); + } + return; +} diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts similarity index 97% rename from plugins/node/opentelemetry-instrumentation-redis/test/redis.test.ts rename to plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts index 39973aadfe..581878c6d4 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts @@ -30,7 +30,7 @@ import { SimpleSpanProcessor, } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; -import { RedisInstrumentation } from '../src'; +import { RedisInstrumentation } from '../../src'; import { DBSYSTEMVALUES_REDIS, SEMATTRS_DB_CONNECTION_STRING, @@ -45,7 +45,7 @@ instrumentation.enable(); instrumentation.disable(); import * as redisTypes from 'redis'; -import { RedisResponseCustomAttributeFunction } from '../src/types'; +import { RedisResponseCustomAttributeFunction } from '../../src/types'; const memoryExporter = new InMemorySpanExporter(); @@ -263,7 +263,7 @@ describe('redis@2.x', () => { }); describe('dbStatementSerializer config', () => { - const dbStatementSerializer = (cmdName: string, cmdArgs: string[]) => { + const dbStatementSerializer = (cmdName: string, cmdArgs: Array) => { return Array.isArray(cmdArgs) && cmdArgs.length ? `${cmdName} ${cmdArgs.join(' ')}` : cmdName; @@ -306,7 +306,7 @@ describe('redis@2.x', () => { const responseHook: RedisResponseCustomAttributeFunction = ( span: Span, _cmdName: string, - _cmdArgs: string[], + _cmdArgs: Array, response: unknown ) => { span.setAttribute(dataFieldName, new String(response).toString()); @@ -337,7 +337,7 @@ describe('redis@2.x', () => { const badResponseHook: RedisResponseCustomAttributeFunction = ( _span: Span, _cmdName: string, - _cmdArgs: string[], + _cmdArgs: Array, _response: unknown ) => { throw 'Some kind of error'; From ca617a5fddd04b37ed30642915c8d9ab3d4f1045 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sat, 7 Jun 2025 18:52:09 +0300 Subject: [PATCH 04/28] test: fix redis tests with v4 --- .../.tav.yml | 4 +- .../package.json | 3 +- .../test/v2-3/redis.test.ts | 182 ++---- .../test/v4/redis.test.ts | 614 ++++++++++++++++++ .../test/v4/utils.ts | 24 + 5 files changed, 694 insertions(+), 133 deletions(-) create mode 100644 plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts create mode 100644 plugins/node/opentelemetry-instrumentation-redis/test/v4/utils.ts diff --git a/plugins/node/opentelemetry-instrumentation-redis/.tav.yml b/plugins/node/opentelemetry-instrumentation-redis/.tav.yml index 81020bc78f..f8b40362a8 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/.tav.yml +++ b/plugins/node/opentelemetry-instrumentation-redis/.tav.yml @@ -1,5 +1,7 @@ redis: versions: - include: '>=2.6.0 <4' + include: '>=2.6.0 <5' + # "4.6.9" was a bad release that accidentally broke node v14 support. + exclude: "4.6.9" mode: latest-minors commands: npm run test diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index f80c700681..48de7394be 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -6,7 +6,7 @@ "types": "build/src/index.d.ts", "repository": "open-telemetry/opentelemetry-js-contrib", "scripts": { - "test": "nyc mocha 'test/**/*.test.ts'", + "test": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/**/*.test.ts'", "test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true mocha --inspect-brk --no-timeouts 'test/**/*.test.ts'", "test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test", "test:docker:run": "docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine", @@ -59,6 +59,7 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", + "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts index 581878c6d4..d54fccd310 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts @@ -21,14 +21,14 @@ import { SpanStatus, trace, Span, + ROOT_CONTEXT, } from '@opentelemetry/api'; -import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import * as testUtils from '@opentelemetry/contrib-test-utils'; import { - InMemorySpanExporter, - SimpleSpanProcessor, -} from '@opentelemetry/sdk-trace-base'; + getTestSpans, + registerInstrumentationTesting, +} from '@opentelemetry/contrib-test-utils'; import * as assert from 'assert'; import { RedisInstrumentation } from '../../src'; import { @@ -40,15 +40,13 @@ import { SEMATTRS_NET_PEER_PORT, } from '@opentelemetry/semantic-conventions'; -const instrumentation = new RedisInstrumentation(); -instrumentation.enable(); -instrumentation.disable(); +const instrumentation = registerInstrumentationTesting( + new RedisInstrumentation() +); import * as redisTypes from 'redis'; import { RedisResponseCustomAttributeFunction } from '../../src/types'; -const memoryExporter = new InMemorySpanExporter(); - const CONFIG = { host: process.env.OPENTELEMETRY_REDIS_HOST || 'localhost', port: Number(process.env.OPENTELEMETRY_REDIS_PORT || 63790), @@ -68,26 +66,10 @@ const unsetStatus: SpanStatus = { }; describe('redis@2.x', () => { - const provider = new NodeTracerProvider({ - spanProcessors: [new SimpleSpanProcessor(memoryExporter)], - }); - const tracer = provider.getTracer('external'); let redis: typeof redisTypes; const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; - - let contextManager: AsyncLocalStorageContextManager; - beforeEach(() => { - contextManager = new AsyncLocalStorageContextManager().enable(); - context.setGlobalContextManager(contextManager); - // set the default tracer provider before each test - // specific ones can override it to assert certain things - instrumentation.setTracerProvider(provider); - }); - - afterEach(() => { - context.disable(); - }); + const tracer = trace.getTracer('external'); before(function () { // needs to be "function" to have MochaContext "this" context @@ -103,8 +85,6 @@ describe('redis@2.x', () => { } redis = require('redis'); - instrumentation.setTracerProvider(provider); - instrumentation.enable(); }); after(() => { @@ -144,30 +124,30 @@ describe('redis@2.x', () => { expectedDbStatement: string; method: (cb: redisTypes.Callback) => unknown; }> = [ - { - description: 'insert', - command: 'hset', - args: ['hash', 'random', 'random'], - expectedDbStatement: 'hash random [1 other arguments]', - method: (cb: redisTypes.Callback) => - client.hset('hash', 'random', 'random', cb), - }, - { - description: 'get', - command: 'get', - args: ['test'], - expectedDbStatement: 'test', - method: (cb: redisTypes.Callback) => - client.get('test', cb), - }, - { - description: 'delete', - command: 'del', - args: ['test'], - expectedDbStatement: 'test', - method: (cb: redisTypes.Callback) => client.del('test', cb), - }, - ]; + { + description: 'insert', + command: 'hset', + args: ['hash', 'random', 'random'], + expectedDbStatement: 'hash random [1 other arguments]', + method: (cb: redisTypes.Callback) => + client.hset('hash', 'random', 'random', cb), + }, + { + description: 'get', + command: 'get', + args: ['test'], + expectedDbStatement: 'test', + method: (cb: redisTypes.Callback) => + client.get('test', cb), + }, + { + description: 'delete', + command: 'del', + args: ['test'], + expectedDbStatement: 'test', + method: (cb: redisTypes.Callback) => client.del('test', cb), + }, + ]; before(done => { client = redis.createClient(URL); @@ -179,7 +159,7 @@ describe('redis@2.x', () => { beforeEach(done => { client.set('test', 'data', () => { - memoryExporter.reset(); + testUtils.resetMemoryExporter() done(); }); }); @@ -190,7 +170,7 @@ describe('redis@2.x', () => { afterEach(done => { client.del('hash', () => { - memoryExporter.reset(); + testUtils.resetMemoryExporter(); done(); }); }); @@ -206,9 +186,9 @@ describe('redis@2.x', () => { context.with(trace.setSpan(context.active(), span), () => { operation.method((err, _result) => { assert.ifError(err); - assert.strictEqual(memoryExporter.getFinishedSpans().length, 1); + assert.strictEqual(getTestSpans().length, 1); span.end(); - const endedSpans = memoryExporter.getFinishedSpans(); + const endedSpans = getTestSpans(); assert.strictEqual(endedSpans.length, 2); assert.strictEqual( endedSpans[0].name, @@ -239,29 +219,6 @@ describe('redis@2.x', () => { }); }); - describe('Removing instrumentation', () => { - before(() => { - instrumentation.disable(); - }); - - REDIS_OPERATIONS.forEach(operation => { - it(`should not create a child span for ${operation.description}`, done => { - const span = tracer.startSpan('test span'); - context.with(trace.setSpan(context.active(), span), () => { - operation.method((err, _) => { - assert.ifError(err); - assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); - span.end(); - const endedSpans = memoryExporter.getFinishedSpans(); - assert.strictEqual(endedSpans.length, 1); - assert.strictEqual(endedSpans[0], span); - done(); - }); - }); - }); - }); - }); - describe('dbStatementSerializer config', () => { const dbStatementSerializer = (cmdName: string, cmdArgs: Array) => { return Array.isArray(cmdArgs) && cmdArgs.length @@ -269,10 +226,8 @@ describe('redis@2.x', () => { : cmdName; }; - before(() => { - instrumentation.disable(); + beforeEach(() => { instrumentation.setConfig({ dbStatementSerializer }); - instrumentation.enable(); }); REDIS_OPERATIONS.forEach(operation => { @@ -282,7 +237,7 @@ describe('redis@2.x', () => { operation.method((err, _) => { assert.ifError(err); span.end(); - const endedSpans = memoryExporter.getFinishedSpans(); + const endedSpans = getTestSpans(); assert.strictEqual(endedSpans.length, 2); const expectedStatement = dbStatementSerializer( operation.command, @@ -312,17 +267,15 @@ describe('redis@2.x', () => { span.setAttribute(dataFieldName, new String(response).toString()); }; - before(() => { - instrumentation.disable(); + beforeEach(() => { instrumentation.setConfig({ responseHook }); - instrumentation.enable(); }); REDIS_OPERATIONS.forEach(operation => { it(`should apply responseHook for operation ${operation.description}`, done => { operation.method((err, reply) => { assert.ifError(err); - const endedSpans = memoryExporter.getFinishedSpans(); + const endedSpans = getTestSpans(); assert.strictEqual( endedSpans[0].attributes[dataFieldName], new String(reply).toString() @@ -343,17 +296,15 @@ describe('redis@2.x', () => { throw 'Some kind of error'; }; - before(() => { - instrumentation.disable(); + beforeEach(() => { instrumentation.setConfig({ responseHook: badResponseHook }); - instrumentation.enable(); }); REDIS_OPERATIONS.forEach(operation => { it(`should not fail because of responseHook error for operation ${operation.description}`, done => { operation.method((err, _reply) => { assert.ifError(err); - const endedSpans = memoryExporter.getFinishedSpans(); + const endedSpans = getTestSpans(); assert.strictEqual(endedSpans.length, 1); done(); }); @@ -363,19 +314,19 @@ describe('redis@2.x', () => { }); describe('requireParentSpan config', () => { - before(() => { - instrumentation.disable(); + beforeEach(() => { instrumentation.setConfig({ requireParentSpan: true }); - instrumentation.enable(); }); REDIS_OPERATIONS.forEach(operation => { it(`should not create span without parent span for operation ${operation.description}`, done => { - operation.method((err, _) => { - assert.ifError(err); - const endedSpans = memoryExporter.getFinishedSpans(); - assert.strictEqual(endedSpans.length, 0); - done(); + context.with(ROOT_CONTEXT, () => { + operation.method((err, _) => { + assert.ifError(err); + const endedSpans = getTestSpans(); + assert.strictEqual(endedSpans.length, 0); + done(); + }); }); }); @@ -384,7 +335,7 @@ describe('redis@2.x', () => { context.with(trace.setSpan(context.active(), span), () => { operation.method((err, _) => { assert.ifError(err); - const endedSpans = memoryExporter.getFinishedSpans(); + const endedSpans = getTestSpans(); assert.strictEqual(endedSpans.length, 1); done(); }); @@ -392,36 +343,5 @@ describe('redis@2.x', () => { }); }); }); - - describe('setTracerProvider', () => { - before(() => { - instrumentation.disable(); - instrumentation.setConfig({}); - instrumentation.enable(); - }); - - it('should use new tracer provider after setTracerProvider is called', done => { - const testSpecificMemoryExporter = new InMemorySpanExporter(); - const spanProcessor = new SimpleSpanProcessor( - testSpecificMemoryExporter - ); - const tracerProvider = new NodeTracerProvider({ - spanProcessors: [spanProcessor], - }); - - // key point of this test, setting new tracer provider and making sure - // new spans use it. - instrumentation.setTracerProvider(tracerProvider); - - client.set('test', 'value-with-new-tracer-provider', err => { - assert.ifError(err); - // assert that the span was exported by the new tracer provider - // which is using the test specific span processor - const spans = testSpecificMemoryExporter.getFinishedSpans(); - assert.strictEqual(spans.length, 1); - done(); - }); - }); - }); }); }); diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts new file mode 100644 index 0000000000..a00dc16a98 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts @@ -0,0 +1,614 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { diag, DiagLogLevel, ROOT_CONTEXT } from '@opentelemetry/api'; +import { + getTestSpans, + registerInstrumentationTesting, +} from '@opentelemetry/contrib-test-utils'; +import { RedisInstrumentation } from '../../src'; +import type { MultiErrorReply } from '../../src/v4/internal-types'; +import * as assert from 'assert'; + +import { + redisTestConfig, + redisTestUrl, + shouldTest, + shouldTestLocal, +} from './utils'; +import * as testUtils from '@opentelemetry/contrib-test-utils'; + +const instrumentation = registerInstrumentationTesting( + new RedisInstrumentation() +); + +import { createClient, WatchError } from 'redis-v4'; +import { + Span, + SpanKind, + SpanStatusCode, + trace, + context, +} from '@opentelemetry/api'; +import { + SEMATTRS_DB_CONNECTION_STRING, + SEMATTRS_DB_STATEMENT, + SEMATTRS_DB_SYSTEM, + SEMATTRS_EXCEPTION_MESSAGE, + SEMATTRS_NET_PEER_NAME, + SEMATTRS_NET_PEER_PORT, +} from '@opentelemetry/semantic-conventions'; +import { RedisResponseCustomAttributeFunction } from '../../src/types'; +import { hrTimeToMilliseconds, suppressTracing } from '@opentelemetry/core'; + +describe('redis@^4.0.0', () => { + before(function () { + // needs to be "function" to have MochaContext "this" context + if (!shouldTest) { + // this.skip() workaround + // https://github.com/mochajs/mocha/issues/2683#issuecomment-375629901 + this.test!.parent!.pending = true; + this.skip(); + } + + if (shouldTestLocal) { + testUtils.startDocker('redis'); + } + }); + + after(() => { + if (shouldTestLocal) { + testUtils.cleanUpDocker('redis'); + } + }); + + let client: any; + + beforeEach(async () => { + client = createClient({ + url: redisTestUrl, + }); + await context.with(suppressTracing(context.active()), async () => { + await client.connect(); + }); + }); + + afterEach(async () => { + await client?.disconnect(); + }); + + describe('redis commands', () => { + it('simple set and get', async () => { + await client.set('key', 'value'); + const value = await client.get('key'); + assert.strictEqual(value, 'value'); // verify we did not screw up the normal functionality + + const spans = getTestSpans(); + assert.strictEqual(spans.length, 2); + + const setSpan = spans.find(s => s.name.includes('SET')); + assert.ok(setSpan); + assert.strictEqual(setSpan?.kind, SpanKind.CLIENT); + assert.strictEqual(setSpan?.name, 'redis-SET'); + assert.strictEqual(setSpan?.attributes[SEMATTRS_DB_SYSTEM], 'redis'); + assert.strictEqual( + setSpan?.attributes[SEMATTRS_DB_STATEMENT], + 'SET key [1 other arguments]' + ); + assert.strictEqual( + setSpan?.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + setSpan?.attributes[SEMATTRS_NET_PEER_PORT], + redisTestConfig.port + ); + assert.strictEqual( + setSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], + redisTestUrl + ); + + const getSpan = spans.find(s => s.name.includes('GET')); + assert.ok(getSpan); + assert.strictEqual(getSpan?.kind, SpanKind.CLIENT); + assert.strictEqual(getSpan?.name, 'redis-GET'); + assert.strictEqual(getSpan?.attributes[SEMATTRS_DB_SYSTEM], 'redis'); + assert.strictEqual(getSpan?.attributes[SEMATTRS_DB_STATEMENT], 'GET key'); + assert.strictEqual( + getSpan?.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + getSpan?.attributes[SEMATTRS_NET_PEER_PORT], + redisTestConfig.port + ); + assert.strictEqual( + getSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], + redisTestUrl + ); + }); + + it('send general command', async () => { + const res = await client.sendCommand(['SET', 'key', 'value']); + assert.strictEqual(res, 'OK'); // verify we did not screw up the normal functionality + + const [setSpan] = getTestSpans(); + + assert.ok(setSpan); + assert.strictEqual( + setSpan?.attributes[SEMATTRS_DB_STATEMENT], + 'SET key [1 other arguments]' + ); + assert.strictEqual( + setSpan?.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + setSpan?.attributes[SEMATTRS_NET_PEER_PORT], + redisTestConfig.port + ); + }); + + it('command with error', async () => { + await client.set('string-key', 'string-value'); + await assert.rejects(async () => await client.incr('string-key')); + + const [_setSpan, incrSpan] = getTestSpans(); + + assert.ok(incrSpan); + assert.strictEqual(incrSpan?.status.code, SpanStatusCode.ERROR); + assert.strictEqual( + incrSpan?.status.message, + 'ERR value is not an integer or out of range' + ); + + const exceptions = incrSpan.events.filter( + event => event.name === 'exception' + ); + assert.strictEqual(exceptions.length, 1); + assert.strictEqual( + exceptions?.[0].attributes?.[SEMATTRS_EXCEPTION_MESSAGE], + 'ERR value is not an integer or out of range' + ); + }); + }); + + describe('client connect', () => { + it('produces a span', async () => { + const newClient = createClient({ + url: redisTestUrl, + }); + + after(async () => { + await newClient.disconnect(); + }); + + await newClient.connect(); + + const [span] = getTestSpans(); + + assert.strictEqual(span.name, 'redis-connect'); + + assert.strictEqual(span.attributes[SEMATTRS_DB_SYSTEM], 'redis'); + assert.strictEqual( + span.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + span.attributes[SEMATTRS_NET_PEER_PORT], + redisTestConfig.port + ); + assert.strictEqual( + span.attributes[SEMATTRS_DB_CONNECTION_STRING], + redisTestUrl + ); + }); + + it('sets error status on connection failure', async () => { + const redisURL = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 + }`; + const newClient = createClient({ + url: redisURL, + }); + + await assert.rejects(newClient.connect()); + + const [span] = getTestSpans(); + + assert.strictEqual(span.name, 'redis-connect'); + assert.strictEqual(span.status.code, SpanStatusCode.ERROR); + assert.strictEqual( + span.attributes[SEMATTRS_DB_CONNECTION_STRING], + redisURL + ); + }); + + it('omits basic auth from DB_CONNECTION_STRING span attribute', async () => { + const redisURL = `redis://myuser:mypassword@${redisTestConfig.host}:${redisTestConfig.port + 1 + }`; + const expectAttributeConnString = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 + }`; + const newClient = createClient({ + url: redisURL, + }); + + await assert.rejects(newClient.connect()); + + const [span] = getTestSpans(); + + assert.strictEqual(span.name, 'redis-connect'); + assert.strictEqual(span.status.code, SpanStatusCode.ERROR); + assert.strictEqual( + span.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + span.attributes[SEMATTRS_DB_CONNECTION_STRING], + expectAttributeConnString + ); + }); + + it('omits user_pwd query parameter from DB_CONNECTION_STRING span attribute', async () => { + const redisURL = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 + }?db=mydb&user_pwd=mypassword`; + const expectAttributeConnString = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 + }?db=mydb`; + const newClient = createClient({ + url: redisURL, + }); + + await assert.rejects(newClient.connect()); + + const [span] = getTestSpans(); + + assert.strictEqual(span.name, 'redis-connect'); + assert.strictEqual(span.status.code, SpanStatusCode.ERROR); + assert.strictEqual( + span.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + span.attributes[SEMATTRS_DB_CONNECTION_STRING], + expectAttributeConnString + ); + }); + + it('with empty string for client URL, there is no crash and no diag.error', async () => { + // Note: This messily leaves the diag logger set for other tests. + const diagErrors = [] as any; + diag.setLogger( + { + verbose() { }, + debug() { }, + info() { }, + warn() { }, + error(...args) { + diagErrors.push(args); + }, + }, + DiagLogLevel.WARN + ); + + const newClient = createClient({ url: '' }); + try { + await newClient.connect(); + } catch (_err) { + // Ignore. If the test Redis is not at the default port we expect this + // to error. + } + await newClient.disconnect(); + + const [span] = getTestSpans(); + assert.strictEqual(span.name, 'redis-connect'); + assert.strictEqual(diagErrors.length, 0, "no diag.error's"); + }); + }); + + describe('multi (transactions) commands', () => { + it('multi commands', async () => { + await client.set('another-key', 'another-value'); + const [setKeyReply, otherKeyValue] = await client + .multi() + .set('key', 'value') + .get('another-key') + .exec(); // ['OK', 'another-value'] + + assert.strictEqual(setKeyReply, 'OK'); // verify we did not screw up the normal functionality + assert.strictEqual(otherKeyValue, 'another-value'); // verify we did not screw up the normal functionality + + const [setSpan, multiSetSpan, multiGetSpan] = getTestSpans(); + + assert.ok(setSpan); + + assert.ok(multiSetSpan); + assert.strictEqual(multiSetSpan.name, 'redis-SET'); + assert.strictEqual( + multiSetSpan.attributes[SEMATTRS_DB_STATEMENT], + 'SET key [1 other arguments]' + ); + assert.strictEqual( + multiSetSpan?.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + multiSetSpan?.attributes[SEMATTRS_NET_PEER_PORT], + redisTestConfig.port + ); + assert.strictEqual( + multiSetSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], + redisTestUrl + ); + + assert.ok(multiGetSpan); + assert.strictEqual(multiGetSpan.name, 'redis-GET'); + assert.strictEqual( + multiGetSpan.attributes[SEMATTRS_DB_STATEMENT], + 'GET another-key' + ); + assert.strictEqual( + multiGetSpan?.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + multiGetSpan?.attributes[SEMATTRS_NET_PEER_PORT], + redisTestConfig.port + ); + assert.strictEqual( + multiGetSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], + redisTestUrl + ); + }); + + it('multi command with generic command', async () => { + const [setReply] = await client + .multi() + .addCommand(['SET', 'key', 'value']) + .exec(); + assert.strictEqual(setReply, 'OK'); // verify we did not screw up the normal functionality + + const [multiSetSpan] = getTestSpans(); + assert.ok(multiSetSpan); + assert.strictEqual( + multiSetSpan.attributes[SEMATTRS_DB_STATEMENT], + 'SET key [1 other arguments]' + ); + assert.strictEqual( + multiSetSpan?.attributes[SEMATTRS_NET_PEER_NAME], + redisTestConfig.host + ); + assert.strictEqual( + multiSetSpan?.attributes[SEMATTRS_NET_PEER_PORT], + redisTestConfig.port + ); + assert.strictEqual( + multiSetSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], + redisTestUrl + ); + }); + + it('multi command with error', async () => { + let replies; + try { + replies = await client.multi().set('key', 'value').incr('key').exec(); + } catch (err) { + // Starting in redis@4.6.12 `multi().exec()` will *throw* a + // MultiErrorReply, with `err.replies`, if any of the commands error. + replies = (err as MultiErrorReply).replies; + } + const [setReply, incrReply] = replies; + + assert.strictEqual(setReply, 'OK'); // verify we did not screw up the normal functionality + assert.ok(incrReply instanceof Error); // verify we did not screw up the normal functionality + + const [multiSetSpan, multiIncrSpan] = getTestSpans(); + + assert.ok(multiSetSpan); + assert.strictEqual(multiSetSpan.status.code, SpanStatusCode.UNSET); + + assert.ok(multiIncrSpan); + assert.strictEqual(multiIncrSpan.status.code, SpanStatusCode.ERROR); + assert.strictEqual( + multiIncrSpan.status.message, + 'ERR value is not an integer or out of range' + ); + }); + + it('multi command that rejects', async () => { + const watchedKey = 'watched-key'; + await client.watch(watchedKey); + await client.set(watchedKey, 'a different value'); + try { + await client.multi().get(watchedKey).exec(); + assert.fail('expected WatchError to be thrown and caught in try/catch'); + } catch (error) { + assert.ok(error instanceof WatchError); + } + + // All the multi spans' status are set to ERROR. + const [_watchSpan, _setSpan, multiGetSpan] = getTestSpans(); + assert.strictEqual(multiGetSpan?.status.code, SpanStatusCode.ERROR); + assert.strictEqual( + multiGetSpan?.status.message, + 'One (or more) of the watched keys has been changed' + ); + }); + + it('duration covers create until server response', async () => { + await client.set('another-key', 'another-value'); + const multiClient = client.multi(); + let commands = multiClient.set('key', 'value'); + // wait 10 ms before adding next command + // simulate long operation + await new Promise(resolve => setTimeout(resolve, 10)); + commands = commands.get('another-key'); + const [setKeyReply, otherKeyValue] = await commands.exec(); // ['OK', 'another-value'] + + assert.strictEqual(setKeyReply, 'OK'); // verify we did not screw up the normal functionality + assert.strictEqual(otherKeyValue, 'another-value'); // verify we did not screw up the normal functionality + + const [_setSpan, multiSetSpan, multiGetSpan] = getTestSpans(); + // verify that commands span started when it was added to multi and not when "sent". + // they were called with 10 ms gap between them, so it should be reflected in the span start time + // could be nice feature in the future to capture an event for when it is actually sent + const startTimeDiff = + hrTimeToMilliseconds(multiGetSpan.startTime) - + hrTimeToMilliseconds(multiSetSpan.startTime); + assert.ok( + startTimeDiff >= 9, + `diff of start time should be >= 10 and it's ${startTimeDiff}` + ); + + const endTimeDiff = + hrTimeToMilliseconds(multiGetSpan.endTime) - + hrTimeToMilliseconds(multiSetSpan.endTime); + assert.ok(endTimeDiff < 10); // spans should all end together when multi response arrives from redis server + }); + + it('response hook for multi commands', async () => { + const responseHook: RedisResponseCustomAttributeFunction = ( + span: Span, + cmdName: string, + cmdArgs: Array, + response: unknown + ) => { + span.setAttribute('test.cmd.name', cmdName); + span.setAttribute('test.cmd.args', cmdArgs as string[]); + span.setAttribute('test.db.response', response as string); + }; + instrumentation.setConfig({ responseHook }); + + await client.set('another-key', 'another-value'); + const [setKeyReply, otherKeyValue] = await client + .multi() + .set('key', 'value') + .get('another-key') + .exec(); // ['OK', 'another-value'] + assert.strictEqual(setKeyReply, 'OK'); // verify we did not screw up the normal functionality + assert.strictEqual(otherKeyValue, 'another-value'); // verify we did not screw up the normal functionality + + const [_setSpan, multiSetSpan, multiGetSpan] = getTestSpans(); + + assert.ok(multiSetSpan); + assert.strictEqual(multiSetSpan.attributes['test.cmd.name'], 'SET'); + assert.deepStrictEqual(multiSetSpan.attributes['test.cmd.args'], [ + 'key', + 'value', + ]); + assert.strictEqual(multiSetSpan.attributes['test.db.response'], 'OK'); + + assert.ok(multiGetSpan); + assert.strictEqual(multiGetSpan.attributes['test.cmd.name'], 'GET'); + assert.deepStrictEqual(multiGetSpan.attributes['test.cmd.args'], [ + 'another-key', + ]); + assert.strictEqual( + multiGetSpan.attributes['test.db.response'], + 'another-value' + ); + }); + }); + + describe('config', () => { + describe('dbStatementSerializer', () => { + it('custom dbStatementSerializer', async () => { + const dbStatementSerializer = ( + cmdName: string, + cmdArgs: Array + ) => { + return `${cmdName} ${cmdArgs.join(' ')}`; + }; + + instrumentation.setConfig({ dbStatementSerializer }); + await client.set('key', 'value'); + const [span] = getTestSpans(); + assert.strictEqual( + span.attributes[SEMATTRS_DB_STATEMENT], + 'SET key value' + ); + }); + + it('dbStatementSerializer throws', async () => { + const dbStatementSerializer = () => { + throw new Error('dbStatementSerializer error'); + }; + + instrumentation.setConfig({ dbStatementSerializer }); + await client.set('key', 'value'); + const [span] = getTestSpans(); + assert.ok(span); + assert.ok(!(SEMATTRS_DB_STATEMENT in span.attributes)); + }); + }); + + describe('responseHook', () => { + it('valid response hook', async () => { + const responseHook: RedisResponseCustomAttributeFunction = ( + span: Span, + cmdName: string, + cmdArgs: Array, + response: unknown + ) => { + span.setAttribute('test.cmd.name', cmdName); + span.setAttribute('test.cmd.args', cmdArgs as string[]); + span.setAttribute('test.db.response', response as string); + }; + instrumentation.setConfig({ responseHook }); + await client.set('key', 'value'); + const [span] = getTestSpans(); + assert.ok(span); + assert.strictEqual(span.attributes['test.cmd.name'], 'SET'); + assert.deepStrictEqual(span.attributes['test.cmd.args'], [ + 'key', + 'value', + ]); + assert.strictEqual(span.attributes['test.db.response'], 'OK'); + }); + + it('responseHook throws', async () => { + const responseHook = () => { + throw new Error('responseHook error'); + }; + instrumentation.setConfig({ responseHook }); + const res = await client.set('key', 'value'); + assert.strictEqual(res, 'OK'); // package is still functional + const [span] = getTestSpans(); + assert.ok(span); + }); + }); + + describe('requireParentSpan', () => { + it('set to true', async () => { + instrumentation.setConfig({ requireParentSpan: true }); + + // no parent span => no redis span + context.with(ROOT_CONTEXT, async () => { + const res = await client.set('key', 'value'); + assert.strictEqual(res, 'OK'); // verify we did not screw up the normal functionality + assert.ok(getTestSpans().length === 0); + }); + + // has ambient span => redis span + const span = trace.getTracer('test').startSpan('test span'); + await context.with(trace.setSpan(context.active(), span), async () => { + const res = await client.set('key', 'value'); + assert.strictEqual(res, 'OK'); // verify we did not screw up the normal functionality + assert.ok(getTestSpans().length === 1); + }); + span.end(); + }); + }); + }); +}); diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/utils.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/utils.ts new file mode 100644 index 0000000000..cc0e0a6609 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/utils.ts @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const redisTestConfig = { + host: process.env.OPENTELEMETRY_REDIS_HOST || 'localhost', + port: +(process.env.OPENTELEMETRY_REDIS_PORT || 63790), +}; + +export const redisTestUrl = `redis://${redisTestConfig.host}:${redisTestConfig.port}`; + +export const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; +export const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; From 4ecf3a8330ec9723714d0c13607e58ebe4efa15e Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sat, 7 Jun 2025 18:53:43 +0300 Subject: [PATCH 05/28] fix: redis docs to include consolidated version --- package-lock.json | 180 ++++++++++++++++++ .../README.md | 6 +- 2 files changed, 182 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47456dc892..56845cde2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26452,6 +26452,104 @@ "node": ">=4" } }, + "node_modules/redis-v4": { + "name": "redis", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", + "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", + "dev": true, + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.1", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", + "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", + "dev": true, + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/redis-v4/node_modules/@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/redis-v4/node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/redis-v4/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/redis/node_modules/denque": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", @@ -33527,6 +33625,7 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", + "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -40900,6 +40999,7 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", + "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -56009,6 +56109,86 @@ "redis-errors": "^1.0.0" } }, + "redis-v4": { + "version": "npm:redis@4.7.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", + "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", + "dev": true, + "requires": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.1", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" + }, + "dependencies": { + "@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "dev": true, + "requires": {} + }, + "@redis/client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", + "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", + "dev": true, + "requires": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + } + }, + "@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "dev": true, + "requires": {} + }, + "@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "dev": true, + "requires": {} + }, + "@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "dev": true, + "requires": {} + }, + "@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "dev": true, + "requires": {} + }, + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "dev": true + }, + "generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, "reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", diff --git a/plugins/node/opentelemetry-instrumentation-redis/README.md b/plugins/node/opentelemetry-instrumentation-redis/README.md index b5c9f1cdc1..b2827e72f4 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/README.md +++ b/plugins/node/opentelemetry-instrumentation-redis/README.md @@ -3,7 +3,7 @@ [![NPM Published Version][npm-img]][npm-url] [![Apache License][license-image]][license-image] -This module provides automatic instrumentation for the [`redis`](https://github.com/NodeRedis/node_redis) module versions `>=2.6.0 <4`, which may be loaded using the [`@opentelemetry/sdk-trace-node`](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node) package and is included in the [`@opentelemetry/auto-instrumentations-node`](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) bundle. +This module provides automatic instrumentation for the [`redis`](https://github.com/NodeRedis/node_redis) module versions `>=2.6.0 <5`, which may be loaded using the [`@opentelemetry/sdk-trace-node`](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node) package and is included in the [`@opentelemetry/auto-instrumentations-node`](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) bundle. If total installation size is not constrained, it is recommended to use the [`@opentelemetry/auto-instrumentations-node`](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) bundle with [@opentelemetry/sdk-node](`https://www.npmjs.com/package/@opentelemetry/sdk-node`) for the most seamless instrumentation experience. @@ -17,9 +17,7 @@ npm install --save @opentelemetry/instrumentation-redis ### Supported Versions -- [`redis`](https://www.npmjs.com/package/redis) versions `>=2.6.0 <4` - -For versions `redis@^4.0.0`, please use `@opentelemetry/instrumentation-redis-4` +- [`redis`](https://www.npmjs.com/package/redis) versions `>=2.6.0 <5` ## Usage From 537cd34bdd59bff73c9d57483690ee238580db98 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sat, 7 Jun 2025 18:56:54 +0300 Subject: [PATCH 06/28] chore: lint:fix --- .../src/instrumentation.ts | 117 ++++++++++-------- .../src/v2-3/instrumentation.ts | 2 +- .../src/v2-3/utils.ts | 2 +- .../test/v2-3/redis.test.ts | 55 ++++---- .../test/v4/redis.test.ts | 33 ++--- 5 files changed, 115 insertions(+), 94 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts index f4341f9e9a..58167eec9a 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts @@ -1,71 +1,84 @@ -import { InstrumentationBase } from "@opentelemetry/instrumentation"; -import { RedisInstrumentationConfig } from "./types"; -import { PACKAGE_NAME, PACKAGE_VERSION } from "./version"; -import { RedisInstrumentationV2_3 } from "./v2-3/instrumentation"; -import { TracerProvider } from "@opentelemetry/api"; -import { RedisInstrumentationV4 } from "./v4/instrumentation"; +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { InstrumentationBase } from '@opentelemetry/instrumentation'; +import { RedisInstrumentationConfig } from './types'; +import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; +import { RedisInstrumentationV2_3 } from './v2-3/instrumentation'; +import { TracerProvider } from '@opentelemetry/api'; +import { RedisInstrumentationV4 } from './v4/instrumentation'; const DEFAULT_CONFIG: RedisInstrumentationConfig = { - requireParentSpan: false, + requireParentSpan: false, }; // Wrapper RedisInstrumentation that address all supported versions export class RedisInstrumentation extends InstrumentationBase { + private instrumentationV2_3: RedisInstrumentationV2_3; + private instrumentationV4: RedisInstrumentationV4; - private instrumentationV2_3: RedisInstrumentationV2_3; - private instrumentationV4: RedisInstrumentationV4; + // this is used to bypass a flaw in the base class constructor, which is calling + // member functions before the constructor has a chance to fully initialize the member variables. + private initialized = false; - // this is used to bypass a flaw in the base class constructor, which is calling - // member functions before the constructor has a chance to fully initialize the member variables. - private initialized = false; + constructor(config: RedisInstrumentationConfig = {}) { + const resolvedConfig = { ...DEFAULT_CONFIG, ...config }; + super(PACKAGE_NAME, PACKAGE_VERSION, resolvedConfig); - constructor(config: RedisInstrumentationConfig = {}) { - const resolvedConfig = { ...DEFAULT_CONFIG, ...config }; - super(PACKAGE_NAME, PACKAGE_VERSION, resolvedConfig); + this.instrumentationV2_3 = new RedisInstrumentationV2_3(this.getConfig()); + this.instrumentationV4 = new RedisInstrumentationV4(this.getConfig()); + this.initialized = true; + } - this.instrumentationV2_3 = new RedisInstrumentationV2_3(this.getConfig()); - this.instrumentationV4 = new RedisInstrumentationV4(this.getConfig()); - this.initialized = true; + override setConfig(config: RedisInstrumentationConfig = {}) { + const newConfig = { ...DEFAULT_CONFIG, ...config }; + super.setConfig(newConfig); + if (!this.initialized) { + return; } - override setConfig(config: RedisInstrumentationConfig = {}) { - const newConfig = { ...DEFAULT_CONFIG, ...config }; - super.setConfig(newConfig); - if (!this.initialized) { - return - } + this.instrumentationV2_3.setConfig(newConfig); + this.instrumentationV4.setConfig(newConfig); + } - this.instrumentationV2_3.setConfig(newConfig); - this.instrumentationV4.setConfig(newConfig); - } - - override init() { - } + override init() {} - override setTracerProvider(tracerProvider: TracerProvider) { - super.setTracerProvider(tracerProvider); - if (!this.initialized) { - return - } - this.instrumentationV2_3.setTracerProvider(tracerProvider); - this.instrumentationV4.setTracerProvider(tracerProvider); + override setTracerProvider(tracerProvider: TracerProvider) { + super.setTracerProvider(tracerProvider); + if (!this.initialized) { + return; } + this.instrumentationV2_3.setTracerProvider(tracerProvider); + this.instrumentationV4.setTracerProvider(tracerProvider); + } - override enable() { - super.enable(); - if (!this.initialized) { - return - } - this.instrumentationV2_3.enable(); - this.instrumentationV4.enable(); + override enable() { + super.enable(); + if (!this.initialized) { + return; } + this.instrumentationV2_3.enable(); + this.instrumentationV4.enable(); + } - override disable() { - super.disable(); - if (!this.initialized) { - return - } - this.instrumentationV2_3.disable(); - this.instrumentationV4.disable(); + override disable() { + super.disable(); + if (!this.initialized) { + return; } -} \ No newline at end of file + this.instrumentationV2_3.disable(); + this.instrumentationV4.disable(); + } +} diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v2-3/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v2-3/instrumentation.ts index 91f3e72f50..b245e82800 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/v2-3/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v2-3/instrumentation.ts @@ -212,4 +212,4 @@ export class RedisInstrumentationV2_3 extends InstrumentationBase { } return original.apply(this, arguments); }; -}; \ No newline at end of file +}; diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts index d54fccd310..3339865bb9 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts @@ -124,30 +124,30 @@ describe('redis@2.x', () => { expectedDbStatement: string; method: (cb: redisTypes.Callback) => unknown; }> = [ - { - description: 'insert', - command: 'hset', - args: ['hash', 'random', 'random'], - expectedDbStatement: 'hash random [1 other arguments]', - method: (cb: redisTypes.Callback) => - client.hset('hash', 'random', 'random', cb), - }, - { - description: 'get', - command: 'get', - args: ['test'], - expectedDbStatement: 'test', - method: (cb: redisTypes.Callback) => - client.get('test', cb), - }, - { - description: 'delete', - command: 'del', - args: ['test'], - expectedDbStatement: 'test', - method: (cb: redisTypes.Callback) => client.del('test', cb), - }, - ]; + { + description: 'insert', + command: 'hset', + args: ['hash', 'random', 'random'], + expectedDbStatement: 'hash random [1 other arguments]', + method: (cb: redisTypes.Callback) => + client.hset('hash', 'random', 'random', cb), + }, + { + description: 'get', + command: 'get', + args: ['test'], + expectedDbStatement: 'test', + method: (cb: redisTypes.Callback) => + client.get('test', cb), + }, + { + description: 'delete', + command: 'del', + args: ['test'], + expectedDbStatement: 'test', + method: (cb: redisTypes.Callback) => client.del('test', cb), + }, + ]; before(done => { client = redis.createClient(URL); @@ -159,7 +159,7 @@ describe('redis@2.x', () => { beforeEach(done => { client.set('test', 'data', () => { - testUtils.resetMemoryExporter() + testUtils.resetMemoryExporter(); done(); }); }); @@ -220,7 +220,10 @@ describe('redis@2.x', () => { }); describe('dbStatementSerializer config', () => { - const dbStatementSerializer = (cmdName: string, cmdArgs: Array) => { + const dbStatementSerializer = ( + cmdName: string, + cmdArgs: Array + ) => { return Array.isArray(cmdArgs) && cmdArgs.length ? `${cmdName} ${cmdArgs.join(' ')}` : cmdName; diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts index a00dc16a98..fc42b7734b 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts @@ -218,8 +218,9 @@ describe('redis@^4.0.0', () => { }); it('sets error status on connection failure', async () => { - const redisURL = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 - }`; + const redisURL = `redis://${redisTestConfig.host}:${ + redisTestConfig.port + 1 + }`; const newClient = createClient({ url: redisURL, }); @@ -237,10 +238,12 @@ describe('redis@^4.0.0', () => { }); it('omits basic auth from DB_CONNECTION_STRING span attribute', async () => { - const redisURL = `redis://myuser:mypassword@${redisTestConfig.host}:${redisTestConfig.port + 1 - }`; - const expectAttributeConnString = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 - }`; + const redisURL = `redis://myuser:mypassword@${redisTestConfig.host}:${ + redisTestConfig.port + 1 + }`; + const expectAttributeConnString = `redis://${redisTestConfig.host}:${ + redisTestConfig.port + 1 + }`; const newClient = createClient({ url: redisURL, }); @@ -262,10 +265,12 @@ describe('redis@^4.0.0', () => { }); it('omits user_pwd query parameter from DB_CONNECTION_STRING span attribute', async () => { - const redisURL = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 - }?db=mydb&user_pwd=mypassword`; - const expectAttributeConnString = `redis://${redisTestConfig.host}:${redisTestConfig.port + 1 - }?db=mydb`; + const redisURL = `redis://${redisTestConfig.host}:${ + redisTestConfig.port + 1 + }?db=mydb&user_pwd=mypassword`; + const expectAttributeConnString = `redis://${redisTestConfig.host}:${ + redisTestConfig.port + 1 + }?db=mydb`; const newClient = createClient({ url: redisURL, }); @@ -291,10 +296,10 @@ describe('redis@^4.0.0', () => { const diagErrors = [] as any; diag.setLogger( { - verbose() { }, - debug() { }, - info() { }, - warn() { }, + verbose() {}, + debug() {}, + info() {}, + warn() {}, error(...args) { diagErrors.push(args); }, From de9f42ed629db86e85e495a0af4e37952504e789 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sat, 7 Jun 2025 19:09:31 +0300 Subject: [PATCH 07/28] chore: fix compile --- .../opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts index 3339865bb9..751f237858 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v2-3/redis.test.ts @@ -23,7 +23,6 @@ import { Span, ROOT_CONTEXT, } from '@opentelemetry/api'; -import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import * as testUtils from '@opentelemetry/contrib-test-utils'; import { getTestSpans, From b99ef55d389cb100d24ea02093cedc9f2c9410f9 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sat, 7 Jun 2025 19:10:07 +0300 Subject: [PATCH 08/28] chore: fix description in package.json --- plugins/node/opentelemetry-instrumentation-redis/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index 48de7394be..7bc0e05f71 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -1,7 +1,7 @@ { "name": "@opentelemetry/instrumentation-redis", "version": "0.49.0", - "description": "OpenTelemetry instrumentation for `redis` v2 and v3 database client for Redis", + "description": "OpenTelemetry instrumentation for `redis` database client for Redis", "main": "build/src/index.js", "types": "build/src/index.d.ts", "repository": "open-telemetry/opentelemetry-js-contrib", From 5279606adae967239d28cac17cf0ffbc86b8207e Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sun, 8 Jun 2025 14:10:19 +0300 Subject: [PATCH 09/28] fix: running tav --- package-lock.json | 180 ------------------ .../.tav.yml | 16 +- .../package.json | 7 +- .../test/v4/redis.test.ts | 2 +- 4 files changed, 16 insertions(+), 189 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56845cde2d..47456dc892 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26452,104 +26452,6 @@ "node": ">=4" } }, - "node_modules/redis-v4": { - "name": "redis", - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", - "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", - "dev": true, - "dependencies": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.6.1", - "@redis/graph": "1.1.1", - "@redis/json": "1.0.7", - "@redis/search": "1.2.0", - "@redis/time-series": "1.1.0" - } - }, - "node_modules/redis-v4/node_modules/@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/redis-v4/node_modules/@redis/client": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", - "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", - "dev": true, - "dependencies": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/redis-v4/node_modules/@redis/graph": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", - "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/redis-v4/node_modules/@redis/json": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", - "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/redis-v4/node_modules/@redis/search": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", - "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/redis-v4/node_modules/@redis/time-series": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", - "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/redis-v4/node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/redis-v4/node_modules/generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/redis-v4/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/redis/node_modules/denque": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", @@ -33625,7 +33527,6 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", - "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -40999,7 +40900,6 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", - "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -56109,86 +56009,6 @@ "redis-errors": "^1.0.0" } }, - "redis-v4": { - "version": "npm:redis@4.7.1", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", - "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", - "dev": true, - "requires": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.6.1", - "@redis/graph": "1.1.1", - "@redis/json": "1.0.7", - "@redis/search": "1.2.0", - "@redis/time-series": "1.1.0" - }, - "dependencies": { - "@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "dev": true, - "requires": {} - }, - "@redis/client": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", - "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", - "dev": true, - "requires": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - } - }, - "@redis/graph": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", - "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", - "dev": true, - "requires": {} - }, - "@redis/json": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", - "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", - "dev": true, - "requires": {} - }, - "@redis/search": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", - "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", - "dev": true, - "requires": {} - }, - "@redis/time-series": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", - "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", - "dev": true, - "requires": {} - }, - "cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "dev": true - }, - "generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, "reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", diff --git a/plugins/node/opentelemetry-instrumentation-redis/.tav.yml b/plugins/node/opentelemetry-instrumentation-redis/.tav.yml index f8b40362a8..cbe37cff10 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/.tav.yml +++ b/plugins/node/opentelemetry-instrumentation-redis/.tav.yml @@ -1,7 +1,11 @@ redis: - versions: - include: '>=2.6.0 <5' - # "4.6.9" was a bad release that accidentally broke node v14 support. - exclude: "4.6.9" - mode: latest-minors - commands: npm run test + - versions: + include: '>=2.6.0 <4' + mode: latest-minors + commands: npm run test-v2-v3-run + - versions: + include: '>=4 <5' + # "4.6.9" was a bad release that accidentally broke node v14 support. + exclude: "4.6.9" + mode: latest-minors + commands: npm run test-v4-run diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index 7bc0e05f71..6194901e3c 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -6,7 +6,11 @@ "types": "build/src/index.d.ts", "repository": "open-telemetry/opentelemetry-js-contrib", "scripts": { - "test": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/**/*.test.ts'", + "test": "npm run test-v2-v3 && npm run test-v4", + "test-v2-v3": "tav redis 3.1.2 npm run test-v2-v3-run", + "test-v4": "tav redis 4.7.1 npm run test-v4-run", + "test-v2-v3-run": "nyc mocha --no-clean --require '@opentelemetry/contrib-test-utils' 'test/v2-3/*.test.ts'", + "test-v4-run": "nyc mocha --no-clean --require '@opentelemetry/contrib-test-utils' 'test/v4/*.test.ts'", "test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true mocha --inspect-brk --no-timeouts 'test/**/*.test.ts'", "test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test", "test:docker:run": "docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine", @@ -59,7 +63,6 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", - "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts index fc42b7734b..8b7d8096ec 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts @@ -35,7 +35,7 @@ const instrumentation = registerInstrumentationTesting( new RedisInstrumentation() ); -import { createClient, WatchError } from 'redis-v4'; +import { createClient, WatchError } from 'redis'; import { Span, SpanKind, From 63638dac053dd4069403e8de1226bd2715baae77 Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sun, 8 Jun 2025 14:44:20 +0300 Subject: [PATCH 10/28] fix(redis): v4 test compile --- package-lock.json | 180 ++++++++++++++++++ .../package.json | 1 + .../test/v4/redis.test.ts | 19 +- 3 files changed, 191 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47456dc892..56845cde2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26452,6 +26452,104 @@ "node": ">=4" } }, + "node_modules/redis-v4": { + "name": "redis", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", + "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", + "dev": true, + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.1", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", + "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", + "dev": true, + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/redis-v4/node_modules/@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "dev": true, + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/redis-v4/node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/redis-v4/node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/redis-v4/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/redis/node_modules/denque": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", @@ -33527,6 +33625,7 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", + "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -40900,6 +40999,7 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", + "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -56009,6 +56109,86 @@ "redis-errors": "^1.0.0" } }, + "redis-v4": { + "version": "npm:redis@4.7.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", + "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", + "dev": true, + "requires": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.1", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" + }, + "dependencies": { + "@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "dev": true, + "requires": {} + }, + "@redis/client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", + "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", + "dev": true, + "requires": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + } + }, + "@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "dev": true, + "requires": {} + }, + "@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "dev": true, + "requires": {} + }, + "@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "dev": true, + "requires": {} + }, + "@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "dev": true, + "requires": {} + }, + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "dev": true + }, + "generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, "reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index 6194901e3c..be7290fe73 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -63,6 +63,7 @@ "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "3.1.2", + "redis-v4": "npm:redis@4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts index 8b7d8096ec..b45171cb2e 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts @@ -35,7 +35,8 @@ const instrumentation = registerInstrumentationTesting( new RedisInstrumentation() ); -import { createClient, WatchError } from 'redis'; +import { createClient } from 'redis'; +import type { RedisClientType } from '@redis/client'; import { Span, SpanKind, @@ -75,12 +76,12 @@ describe('redis@^4.0.0', () => { } }); - let client: any; + let client: RedisClientType; beforeEach(async () => { client = createClient({ url: redisTestUrl, - }); + }) as unknown as RedisClientType; await context.with(suppressTracing(context.active()), async () => { await client.connect(); }); @@ -190,7 +191,7 @@ describe('redis@^4.0.0', () => { it('produces a span', async () => { const newClient = createClient({ url: redisTestUrl, - }); + }) as unknown as RedisClientType; after(async () => { await newClient.disconnect(); @@ -223,7 +224,7 @@ describe('redis@^4.0.0', () => { }`; const newClient = createClient({ url: redisURL, - }); + }) as unknown as RedisClientType; await assert.rejects(newClient.connect()); @@ -246,7 +247,7 @@ describe('redis@^4.0.0', () => { }`; const newClient = createClient({ url: redisURL, - }); + }) as unknown as RedisClientType; await assert.rejects(newClient.connect()); @@ -273,7 +274,7 @@ describe('redis@^4.0.0', () => { }?db=mydb`; const newClient = createClient({ url: redisURL, - }); + }) as unknown as RedisClientType; await assert.rejects(newClient.connect()); @@ -307,7 +308,7 @@ describe('redis@^4.0.0', () => { DiagLogLevel.WARN ); - const newClient = createClient({ url: '' }); + const newClient = createClient({ url: '' }) as unknown as RedisClientType; try { await newClient.connect(); } catch (_err) { @@ -439,7 +440,7 @@ describe('redis@^4.0.0', () => { await client.multi().get(watchedKey).exec(); assert.fail('expected WatchError to be thrown and caught in try/catch'); } catch (error) { - assert.ok(error instanceof WatchError); + assert.ok(error instanceof Error); } // All the multi spans' status are set to ERROR. From 1ec39b4fd836bb8770f802fc19e0807aa7d8a54d Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sun, 8 Jun 2025 16:35:37 +0300 Subject: [PATCH 11/28] chore: resolve lint with knip ignore --- .../opentelemetry-instrumentation-redis/src/instrumentation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts index 58167eec9a..8ade8937d7 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts @@ -15,6 +15,7 @@ */ import { InstrumentationBase } from '@opentelemetry/instrumentation'; import { RedisInstrumentationConfig } from './types'; +/** @knipignore */ import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; import { RedisInstrumentationV2_3 } from './v2-3/instrumentation'; import { TracerProvider } from '@opentelemetry/api'; From 5b2c10ba5e044192ab5cdb9c4a1757e6fd98d17e Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Sun, 8 Jun 2025 17:10:23 +0300 Subject: [PATCH 12/28] chore: add v prefix when using multiple versions --- .../package.json | 2 +- .../src/instrumentation.ts | 14 +++++++------- .../src/{v2-3 => v2-v3}/instrumentation.ts | 4 ++-- .../src/{v2-3 => v2-v3}/internal-types.ts | 0 .../src/{v2-3 => v2-v3}/utils.ts | 0 .../test/{v2-3 => v2-v3}/redis.test.ts | 0 6 files changed, 10 insertions(+), 10 deletions(-) rename plugins/node/opentelemetry-instrumentation-redis/src/{v2-3 => v2-v3}/instrumentation.ts (97%) rename plugins/node/opentelemetry-instrumentation-redis/src/{v2-3 => v2-v3}/internal-types.ts (100%) rename plugins/node/opentelemetry-instrumentation-redis/src/{v2-3 => v2-v3}/utils.ts (100%) rename plugins/node/opentelemetry-instrumentation-redis/test/{v2-3 => v2-v3}/redis.test.ts (100%) diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index be7290fe73..cae401a47f 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -9,7 +9,7 @@ "test": "npm run test-v2-v3 && npm run test-v4", "test-v2-v3": "tav redis 3.1.2 npm run test-v2-v3-run", "test-v4": "tav redis 4.7.1 npm run test-v4-run", - "test-v2-v3-run": "nyc mocha --no-clean --require '@opentelemetry/contrib-test-utils' 'test/v2-3/*.test.ts'", + "test-v2-v3-run": "nyc mocha --no-clean --require '@opentelemetry/contrib-test-utils' 'test/v2-v3/*.test.ts'", "test-v4-run": "nyc mocha --no-clean --require '@opentelemetry/contrib-test-utils' 'test/v4/*.test.ts'", "test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true mocha --inspect-brk --no-timeouts 'test/**/*.test.ts'", "test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test", diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts index 8ade8937d7..14c2003dce 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts @@ -17,7 +17,7 @@ import { InstrumentationBase } from '@opentelemetry/instrumentation'; import { RedisInstrumentationConfig } from './types'; /** @knipignore */ import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; -import { RedisInstrumentationV2_3 } from './v2-3/instrumentation'; +import { RedisInstrumentationV2_V3 } from './v2-v3/instrumentation'; import { TracerProvider } from '@opentelemetry/api'; import { RedisInstrumentationV4 } from './v4/instrumentation'; @@ -27,7 +27,7 @@ const DEFAULT_CONFIG: RedisInstrumentationConfig = { // Wrapper RedisInstrumentation that address all supported versions export class RedisInstrumentation extends InstrumentationBase { - private instrumentationV2_3: RedisInstrumentationV2_3; + private instrumentationV2_V3: RedisInstrumentationV2_V3; private instrumentationV4: RedisInstrumentationV4; // this is used to bypass a flaw in the base class constructor, which is calling @@ -38,7 +38,7 @@ export class RedisInstrumentation extends InstrumentationBase { +export class RedisInstrumentationV2_V3 extends InstrumentationBase { static readonly COMPONENT = 'redis'; constructor(config: RedisInstrumentationConfig = {}) { @@ -128,7 +128,7 @@ export class RedisInstrumentationV2_3 extends InstrumentationBase Date: Sun, 8 Jun 2025 17:38:59 +0300 Subject: [PATCH 13/28] chore: add deprecation warning to redis-4 --- plugins/node/opentelemetry-instrumentation-redis-4/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/README.md b/plugins/node/opentelemetry-instrumentation-redis-4/README.md index a8e9449d4b..85b0516974 100644 --- a/plugins/node/opentelemetry-instrumentation-redis-4/README.md +++ b/plugins/node/opentelemetry-instrumentation-redis-4/README.md @@ -1,5 +1,7 @@ # OpenTelemetry redis Instrumentation for Node.js +> ⚠️ **DEPRECATED**: The support for `redis@4` instrumentation is now part of `@opentelemetry/instrumentation-redis`. please use it instead. + [![NPM Published Version][npm-img]][npm-url] [![Apache License][license-image]][license-image] From f46e1664c26b5ab9bd67bff29ac999d0438e064f Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 14:14:58 -0700 Subject: [PATCH 14/28] v4: drop DEFAULT_CONFIG handling, it is handled in the parent RedisInstrumentation now --- .../src/v4/instrumentation.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts index 5ef319dfa6..38f444ca17 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v4/instrumentation.ts @@ -48,19 +48,11 @@ interface MutliCommandInfo { commandArgs: Array; } -const DEFAULT_CONFIG: RedisInstrumentationConfig = { - requireParentSpan: false, -}; - export class RedisInstrumentationV4 extends InstrumentationBase { static readonly COMPONENT = 'redis'; constructor(config: RedisInstrumentationConfig = {}) { - super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); - } - - override setConfig(config: RedisInstrumentationConfig = {}) { - super.setConfig({ ...DEFAULT_CONFIG, ...config }); + super(PACKAGE_NAME, PACKAGE_VERSION, config); } protected init() { From 8a52338b1859a49b8e284ffe2bf7feebb025a01d Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 15:17:21 -0700 Subject: [PATCH 15/28] move testing of redis v2/v3 to 'npm run test-all-versions'; fix tests against earlier redis v4 versions Also drop unused secondary redis v4 install: "redis-v4": "npm:redis@4.7.1", --- package-lock.json | 148 ++++++------------ .../.tav.yml | 4 +- .../package.json | 10 +- .../test/v2-v3/redis.test.ts | 2 +- .../test/v4/redis.test.ts | 10 +- 5 files changed, 63 insertions(+), 111 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56845cde2d..92d32aaf4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26407,30 +26407,23 @@ } }, "node_modules/redis": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", - "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", + "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", "dev": true, + "license": "MIT", + "workspaces": [ + "./packages/*" + ], "dependencies": { - "denque": "^1.5.0", - "redis-commands": "^1.7.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-redis" + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.1", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" } }, - "node_modules/redis-commands": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", - "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==", - "dev": true - }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -26452,35 +26445,22 @@ "node": ">=4" } }, - "node_modules/redis-v4": { - "name": "redis", - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", - "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", - "dev": true, - "dependencies": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.6.1", - "@redis/graph": "1.1.1", - "@redis/json": "1.0.7", - "@redis/search": "1.2.0", - "@redis/time-series": "1.1.0" - } - }, - "node_modules/redis-v4/node_modules/@redis/bloom": { + "node_modules/redis/node_modules/@redis/bloom": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", "dev": true, + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, - "node_modules/redis-v4/node_modules/@redis/client": { + "node_modules/redis/node_modules/@redis/client": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", "dev": true, + "license": "MIT", "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -26490,74 +26470,72 @@ "node": ">=14" } }, - "node_modules/redis-v4/node_modules/@redis/graph": { + "node_modules/redis/node_modules/@redis/graph": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", "dev": true, + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, - "node_modules/redis-v4/node_modules/@redis/json": { + "node_modules/redis/node_modules/@redis/json": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", "dev": true, + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, - "node_modules/redis-v4/node_modules/@redis/search": { + "node_modules/redis/node_modules/@redis/search": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", "dev": true, + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, - "node_modules/redis-v4/node_modules/@redis/time-series": { + "node_modules/redis/node_modules/@redis/time-series": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", "dev": true, + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, - "node_modules/redis-v4/node_modules/cluster-key-slot": { + "node_modules/redis/node_modules/cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.10.0" } }, - "node_modules/redis-v4/node_modules/generic-pool": { + "node_modules/redis/node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, - "node_modules/redis-v4/node_modules/yallist": { + "node_modules/redis/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/redis/node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", "dev": true, - "engines": { - "node": ">=0.10" - } + "license": "ISC" }, "node_modules/reflect-metadata": { "version": "0.2.2", @@ -33624,8 +33602,7 @@ "@types/redis": "2.8.32", "cross-env": "7.0.3", "nyc": "17.1.0", - "redis": "3.1.2", - "redis-v4": "npm:redis@4.7.1", + "redis": "^4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -40998,8 +40975,7 @@ "@types/redis": "2.8.32", "cross-env": "7.0.3", "nyc": "17.1.0", - "redis": "3.1.2", - "redis-v4": "npm:redis@4.7.1", + "redis": "^4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" @@ -56069,48 +56045,7 @@ } }, "redis": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", - "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", - "dev": true, - "requires": { - "denque": "^1.5.0", - "redis-commands": "^1.7.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - }, - "dependencies": { - "denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "dev": true - } - } - }, - "redis-commands": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", - "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==", - "dev": true - }, - "redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "dev": true - }, - "redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "dev": true, - "requires": { - "redis-errors": "^1.0.0" - } - }, - "redis-v4": { - "version": "npm:redis@4.7.1", + "version": "4.7.1", "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", "dev": true, @@ -56189,6 +56124,21 @@ } } }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "dev": true + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dev": true, + "requires": { + "redis-errors": "^1.0.0" + } + }, "reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", diff --git a/plugins/node/opentelemetry-instrumentation-redis/.tav.yml b/plugins/node/opentelemetry-instrumentation-redis/.tav.yml index cbe37cff10..12aa469538 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/.tav.yml +++ b/plugins/node/opentelemetry-instrumentation-redis/.tav.yml @@ -2,10 +2,10 @@ redis: - versions: include: '>=2.6.0 <4' mode: latest-minors - commands: npm run test-v2-v3-run + commands: npm run test-v2-v3 - versions: include: '>=4 <5' # "4.6.9" was a bad release that accidentally broke node v14 support. exclude: "4.6.9" mode: latest-minors - commands: npm run test-v4-run + commands: npm test diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index cae401a47f..1cea2ed346 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -6,11 +6,8 @@ "types": "build/src/index.d.ts", "repository": "open-telemetry/opentelemetry-js-contrib", "scripts": { - "test": "npm run test-v2-v3 && npm run test-v4", - "test-v2-v3": "tav redis 3.1.2 npm run test-v2-v3-run", - "test-v4": "tav redis 4.7.1 npm run test-v4-run", - "test-v2-v3-run": "nyc mocha --no-clean --require '@opentelemetry/contrib-test-utils' 'test/v2-v3/*.test.ts'", - "test-v4-run": "nyc mocha --no-clean --require '@opentelemetry/contrib-test-utils' 'test/v4/*.test.ts'", + "test-v2-v3": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/v2-v3/*.test.ts'", + "test": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/v4/*.test.ts'", "test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true mocha --inspect-brk --no-timeouts 'test/**/*.test.ts'", "test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test", "test:docker:run": "docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine", @@ -62,8 +59,7 @@ "@types/redis": "2.8.32", "cross-env": "7.0.3", "nyc": "17.1.0", - "redis": "3.1.2", - "redis-v4": "npm:redis@4.7.1", + "redis": "^4.7.1", "rimraf": "5.0.10", "test-all-versions": "6.1.0", "typescript": "5.0.4" diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts index 751f237858..6cbf5e21f4 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts @@ -64,7 +64,7 @@ const unsetStatus: SpanStatus = { code: SpanStatusCode.UNSET, }; -describe('redis@2.x', () => { +describe('redis v2-v3', () => { let redis: typeof redisTypes; const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts index b45171cb2e..c21800bd71 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts @@ -55,7 +55,7 @@ import { import { RedisResponseCustomAttributeFunction } from '../../src/types'; import { hrTimeToMilliseconds, suppressTracing } from '@opentelemetry/core'; -describe('redis@^4.0.0', () => { +describe('redis v4', () => { before(function () { // needs to be "function" to have MochaContext "this" context if (!shouldTest) { @@ -315,7 +315,13 @@ describe('redis@^4.0.0', () => { // Ignore. If the test Redis is not at the default port we expect this // to error. } - await newClient.disconnect(); + // See https://github.com/open-telemetry/opentelemetry-js-contrib/pull/2914 + try { + await newClient.disconnect(); + } catch (_disconnectErr) { + // Ignore. In redis@4.4.0 and earlier this disconnect throws + // "The client is closed" if the connect failed. + } const [span] = getTestSpans(); assert.strictEqual(span.name, 'redis-connect'); From 9b0fc9e966f17fbdcd43eb43ba73b24942badc00 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 15:24:19 -0700 Subject: [PATCH 16/28] use a diff name here to see if git picks up on src/instrumentation.ts -> src/v2-v3/instrumentation.ts for a smaller PR diff --- plugins/node/opentelemetry-instrumentation-redis/src/index.ts | 2 +- .../src/{instrumentation.ts => redis.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename plugins/node/opentelemetry-instrumentation-redis/src/{instrumentation.ts => redis.ts} (100%) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/index.ts b/plugins/node/opentelemetry-instrumentation-redis/src/index.ts index 50c62a0ebc..1cce49e0f1 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/index.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export { RedisInstrumentation } from './instrumentation'; +export { RedisInstrumentation } from './redis'; export type { DbStatementSerializer, RedisInstrumentationConfig, diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/redis.ts similarity index 100% rename from plugins/node/opentelemetry-instrumentation-redis/src/instrumentation.ts rename to plugins/node/opentelemetry-instrumentation-redis/src/redis.ts From 79cd098219ba9471d0199e7943e5c99c31d71215 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 15:26:32 -0700 Subject: [PATCH 17/28] remove old instr-redis-4 sources, so git can pick up on the move of the isntr and test files for git --follow history --- .../.eslintignore | 1 - .../.eslintrc.js | 7 - .../.tav.yml | 7 - .../package.json | 72 -- .../src/index.ts | 22 - .../src/instrumentation.ts | 490 -------------- .../src/internal-types.ts | 22 - .../src/types.ts | 59 -- .../src/utils.ts | 63 -- .../test/redis.test.ts | 617 ------------------ .../test/utils.ts | 24 - .../tsconfig.json | 11 - 12 files changed, 1395 deletions(-) delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/.eslintignore delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/.eslintrc.js delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/.tav.yml delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/package.json delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/src/index.ts delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/src/instrumentation.ts delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/src/internal-types.ts delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/src/types.ts delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/src/utils.ts delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/test/redis.test.ts delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/test/utils.ts delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/tsconfig.json diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/.eslintignore b/plugins/node/opentelemetry-instrumentation-redis-4/.eslintignore deleted file mode 100644 index 378eac25d3..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/.eslintrc.js b/plugins/node/opentelemetry-instrumentation-redis-4/.eslintrc.js deleted file mode 100644 index f756f4488b..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - "env": { - "mocha": true, - "node": true - }, - ...require('../../../eslint.config.js') -} diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/.tav.yml b/plugins/node/opentelemetry-instrumentation-redis-4/.tav.yml deleted file mode 100644 index 8890082e4c..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/.tav.yml +++ /dev/null @@ -1,7 +0,0 @@ -redis: - versions: - include: "^4.0.0" - # "4.6.9" was a bad release that accidentally broke node v14 support. - exclude: "4.6.9" - mode: latest-minors - commands: npm run test diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/package.json b/plugins/node/opentelemetry-instrumentation-redis-4/package.json deleted file mode 100644 index 86afcfe46b..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/package.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "@opentelemetry/instrumentation-redis-4", - "version": "0.49.0", - "description": "OpenTelemetry instrumentation for `redis` v4 database client for Redis", - "main": "build/src/index.js", - "types": "build/src/index.d.ts", - "repository": "open-telemetry/opentelemetry-js-contrib", - "scripts": { - "test": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/redis.test.ts'", - "test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true mocha --inspect-brk --no-timeouts test/redis.test.ts", - "test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test", - "test:docker:run": "docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine", - "test:docker:stop": "docker stop otel-redis", - "test-all-versions": "tav", - "test-all-versions:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test-all-versions", - "tdd": "npm run test -- --watch-extensions ts --watch", - "clean": "rimraf build/*", - "lint": "eslint . --ext .ts", - "lint:fix": "eslint . --ext .ts --fix", - "lint:readme": "node ../../../scripts/lint-readme.js", - "version:update": "node ../../../scripts/version-update.js", - "setup:dev": "nx run-many -t compile -p @opentelemetry/instrumentation-redis-4", - "compile": "tsc -p .", - "prepublishOnly": "npm run compile" - }, - "keywords": [ - "instrumentation", - "nodejs", - "opentelemetry", - "profiling", - "redis", - "tracing" - ], - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "files": [ - "build/src/**/*.js", - "build/src/**/*.js.map", - "build/src/**/*.d.ts" - ], - "publishConfig": { - "access": "public" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "devDependencies": { - "@opentelemetry/api": "^1.3.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/contrib-test-utils": "^0.48.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/sdk-trace-node": "^2.0.0", - "@types/mocha": "10.0.10", - "@types/node": "18.18.14", - "cross-env": "7.0.3", - "nyc": "17.1.0", - "redis": "4.1.0", - "rimraf": "5.0.10", - "test-all-versions": "6.1.0", - "typescript": "5.0.4" - }, - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/redis-common": "^0.37.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-redis-4#readme" -} diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/src/index.ts b/plugins/node/opentelemetry-instrumentation-redis-4/src/index.ts deleted file mode 100644 index 50c62a0ebc..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/src/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { RedisInstrumentation } from './instrumentation'; -export type { - DbStatementSerializer, - RedisInstrumentationConfig, - RedisResponseCustomAttributeFunction, -} from './types'; diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis-4/src/instrumentation.ts deleted file mode 100644 index cbbbb0aab1..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/src/instrumentation.ts +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - trace, - context, - SpanKind, - Span, - SpanStatusCode, -} from '@opentelemetry/api'; -import { - isWrapped, - InstrumentationBase, - InstrumentationNodeModuleDefinition, - InstrumentationNodeModuleFile, -} from '@opentelemetry/instrumentation'; -import { getClientAttributes } from './utils'; -import { defaultDbStatementSerializer } from '@opentelemetry/redis-common'; -import { RedisInstrumentationConfig } from './types'; -/** @knipignore */ -import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; -import { SEMATTRS_DB_STATEMENT } from '@opentelemetry/semantic-conventions'; -import type { MultiErrorReply } from './internal-types'; - -const OTEL_OPEN_SPANS = Symbol( - 'opentelemetry.instrumentation.redis.open_spans' -); -const MULTI_COMMAND_OPTIONS = Symbol( - 'opentelemetry.instrumentation.redis.multi_command_options' -); - -interface MutliCommandInfo { - span: Span; - commandName: string; - commandArgs: Array; -} - -const DEFAULT_CONFIG: RedisInstrumentationConfig = { - requireParentSpan: false, -}; - -export class RedisInstrumentation extends InstrumentationBase { - static readonly COMPONENT = 'redis'; - - constructor(config: RedisInstrumentationConfig = {}) { - super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); - } - - override setConfig(config: RedisInstrumentationConfig = {}) { - super.setConfig({ ...DEFAULT_CONFIG, ...config }); - } - - protected init() { - // @node-redis/client is a new package introduced and consumed by 'redis 4.0.x' - // on redis@4.1.0 it was changed to @redis/client. - // we will instrument both packages - return [ - this._getInstrumentationNodeModuleDefinition('@redis/client'), - this._getInstrumentationNodeModuleDefinition('@node-redis/client'), - ]; - } - - private _getInstrumentationNodeModuleDefinition( - basePackageName: string - ): InstrumentationNodeModuleDefinition { - const commanderModuleFile = new InstrumentationNodeModuleFile( - `${basePackageName}/dist/lib/commander.js`, - ['^1.0.0'], - (moduleExports: any, moduleVersion?: string) => { - const transformCommandArguments = - moduleExports.transformCommandArguments; - if (!transformCommandArguments) { - this._diag.error( - 'internal instrumentation error, missing transformCommandArguments function' - ); - return moduleExports; - } - - // function name and signature changed in redis 4.1.0 from 'extendWithCommands' to 'attachCommands' - // the matching internal package names starts with 1.0.x (for redis 4.0.x) - const functionToPatch = moduleVersion?.startsWith('1.0.') - ? 'extendWithCommands' - : 'attachCommands'; - // this is the function that extend a redis client with a list of commands. - // the function patches the commandExecutor to record a span - if (isWrapped(moduleExports?.[functionToPatch])) { - this._unwrap(moduleExports, functionToPatch); - } - this._wrap( - moduleExports, - functionToPatch, - this._getPatchExtendWithCommands(transformCommandArguments) - ); - - return moduleExports; - }, - (moduleExports: any) => { - if (isWrapped(moduleExports?.extendWithCommands)) { - this._unwrap(moduleExports, 'extendWithCommands'); - } - if (isWrapped(moduleExports?.attachCommands)) { - this._unwrap(moduleExports, 'attachCommands'); - } - } - ); - - const multiCommanderModule = new InstrumentationNodeModuleFile( - `${basePackageName}/dist/lib/client/multi-command.js`, - ['^1.0.0'], - (moduleExports: any) => { - const redisClientMultiCommandPrototype = - moduleExports?.default?.prototype; - - if (isWrapped(redisClientMultiCommandPrototype?.exec)) { - this._unwrap(redisClientMultiCommandPrototype, 'exec'); - } - this._wrap( - redisClientMultiCommandPrototype, - 'exec', - this._getPatchMultiCommandsExec() - ); - - if (isWrapped(redisClientMultiCommandPrototype?.addCommand)) { - this._unwrap(redisClientMultiCommandPrototype, 'addCommand'); - } - this._wrap( - redisClientMultiCommandPrototype, - 'addCommand', - this._getPatchMultiCommandsAddCommand() - ); - - return moduleExports; - }, - (moduleExports: any) => { - const redisClientMultiCommandPrototype = - moduleExports?.default?.prototype; - if (isWrapped(redisClientMultiCommandPrototype?.exec)) { - this._unwrap(redisClientMultiCommandPrototype, 'exec'); - } - if (isWrapped(redisClientMultiCommandPrototype?.addCommand)) { - this._unwrap(redisClientMultiCommandPrototype, 'addCommand'); - } - } - ); - - const clientIndexModule = new InstrumentationNodeModuleFile( - `${basePackageName}/dist/lib/client/index.js`, - ['^1.0.0'], - (moduleExports: any) => { - const redisClientPrototype = moduleExports?.default?.prototype; - - // In some @redis/client versions 'multi' is a method. In later - // versions, as of https://github.com/redis/node-redis/pull/2324, - // 'MULTI' is a method and 'multi' is a property defined in the - // constructor that points to 'MULTI', and therefore it will not - // be defined on the prototype. - if (redisClientPrototype?.multi) { - if (isWrapped(redisClientPrototype?.multi)) { - this._unwrap(redisClientPrototype, 'multi'); - } - this._wrap( - redisClientPrototype, - 'multi', - this._getPatchRedisClientMulti() - ); - } - if (redisClientPrototype?.MULTI) { - if (isWrapped(redisClientPrototype?.MULTI)) { - this._unwrap(redisClientPrototype, 'MULTI'); - } - this._wrap( - redisClientPrototype, - 'MULTI', - this._getPatchRedisClientMulti() - ); - } - - if (isWrapped(redisClientPrototype?.sendCommand)) { - this._unwrap(redisClientPrototype, 'sendCommand'); - } - this._wrap( - redisClientPrototype, - 'sendCommand', - this._getPatchRedisClientSendCommand() - ); - - this._wrap( - redisClientPrototype, - 'connect', - this._getPatchedClientConnect() - ); - - return moduleExports; - }, - (moduleExports: any) => { - const redisClientPrototype = moduleExports?.default?.prototype; - if (isWrapped(redisClientPrototype?.multi)) { - this._unwrap(redisClientPrototype, 'multi'); - } - if (isWrapped(redisClientPrototype?.MULTI)) { - this._unwrap(redisClientPrototype, 'MULTI'); - } - if (isWrapped(redisClientPrototype?.sendCommand)) { - this._unwrap(redisClientPrototype, 'sendCommand'); - } - } - ); - - return new InstrumentationNodeModuleDefinition( - basePackageName, - ['^1.0.0'], - (moduleExports: any) => { - return moduleExports; - }, - () => {}, - [commanderModuleFile, multiCommanderModule, clientIndexModule] - ); - } - - // serves both for redis 4.0.x where function name is extendWithCommands - // and redis ^4.1.0 where function name is attachCommands - private _getPatchExtendWithCommands(transformCommandArguments: Function) { - const plugin = this; - return function extendWithCommandsPatchWrapper(original: Function) { - return function extendWithCommandsPatch(this: any, config: any) { - if (config?.BaseClass?.name !== 'RedisClient') { - return original.apply(this, arguments); - } - - const origExecutor = config.executor; - config.executor = function ( - this: any, - command: any, - args: Array - ) { - const redisCommandArguments = transformCommandArguments( - command, - args - ).args; - return plugin._traceClientCommand( - origExecutor, - this, - arguments, - redisCommandArguments - ); - }; - return original.apply(this, arguments); - }; - }; - } - - private _getPatchMultiCommandsExec() { - const plugin = this; - return function execPatchWrapper(original: Function) { - return function execPatch(this: any) { - const execRes = original.apply(this, arguments); - if (typeof execRes?.then !== 'function') { - plugin._diag.error( - 'got non promise result when patching RedisClientMultiCommand.exec' - ); - return execRes; - } - - return execRes - .then((redisRes: unknown[]) => { - const openSpans = this[OTEL_OPEN_SPANS]; - plugin._endSpansWithRedisReplies(openSpans, redisRes); - return redisRes; - }) - .catch((err: Error) => { - const openSpans = this[OTEL_OPEN_SPANS]; - if (!openSpans) { - plugin._diag.error( - 'cannot find open spans to end for redis multi command' - ); - } else { - const replies = - err.constructor.name === 'MultiErrorReply' - ? (err as MultiErrorReply).replies - : new Array(openSpans.length).fill(err); - plugin._endSpansWithRedisReplies(openSpans, replies); - } - return Promise.reject(err); - }); - }; - }; - } - - private _getPatchMultiCommandsAddCommand() { - const plugin = this; - return function addCommandWrapper(original: Function) { - return function addCommandPatch(this: any, args: Array) { - return plugin._traceClientCommand(original, this, arguments, args); - }; - }; - } - - private _getPatchRedisClientMulti() { - return function multiPatchWrapper(original: Function) { - return function multiPatch(this: any) { - const multiRes = original.apply(this, arguments); - multiRes[MULTI_COMMAND_OPTIONS] = this.options; - return multiRes; - }; - }; - } - - private _getPatchRedisClientSendCommand() { - const plugin = this; - return function sendCommandWrapper(original: Function) { - return function sendCommandPatch( - this: any, - args: Array - ) { - return plugin._traceClientCommand(original, this, arguments, args); - }; - }; - } - - private _getPatchedClientConnect() { - const plugin = this; - return function connectWrapper(original: Function) { - return function patchedConnect(this: any): Promise { - const options = this.options; - - const attributes = getClientAttributes(plugin._diag, options); - - const span = plugin.tracer.startSpan( - `${RedisInstrumentation.COMPONENT}-connect`, - { - kind: SpanKind.CLIENT, - attributes, - } - ); - - const res = context.with(trace.setSpan(context.active(), span), () => { - return original.apply(this); - }); - - return res - .then((result: unknown) => { - span.end(); - return result; - }) - .catch((error: Error) => { - span.recordException(error); - span.setStatus({ - code: SpanStatusCode.ERROR, - message: error.message, - }); - span.end(); - return Promise.reject(error); - }); - }; - }; - } - - private _traceClientCommand( - origFunction: Function, - origThis: any, - origArguments: IArguments, - redisCommandArguments: Array - ) { - const hasNoParentSpan = trace.getSpan(context.active()) === undefined; - if (hasNoParentSpan && this.getConfig().requireParentSpan) { - return origFunction.apply(origThis, origArguments); - } - - const clientOptions = origThis.options || origThis[MULTI_COMMAND_OPTIONS]; - - const commandName = redisCommandArguments[0] as string; // types also allows it to be a Buffer, but in practice it only string - const commandArgs = redisCommandArguments.slice(1); - - const dbStatementSerializer = - this.getConfig().dbStatementSerializer || defaultDbStatementSerializer; - - const attributes = getClientAttributes(this._diag, clientOptions); - - try { - const dbStatement = dbStatementSerializer(commandName, commandArgs); - if (dbStatement != null) { - attributes[SEMATTRS_DB_STATEMENT] = dbStatement; - } - } catch (e) { - this._diag.error('dbStatementSerializer throw an exception', e, { - commandName, - }); - } - - const span = this.tracer.startSpan( - `${RedisInstrumentation.COMPONENT}-${commandName}`, - { - kind: SpanKind.CLIENT, - attributes, - } - ); - - const res = context.with(trace.setSpan(context.active(), span), () => { - return origFunction.apply(origThis, origArguments); - }); - if (typeof res?.then === 'function') { - res.then( - (redisRes: unknown) => { - this._endSpanWithResponse( - span, - commandName, - commandArgs, - redisRes, - undefined - ); - }, - (err: any) => { - this._endSpanWithResponse(span, commandName, commandArgs, null, err); - } - ); - } else { - const redisClientMultiCommand = res as { - [OTEL_OPEN_SPANS]?: Array; - }; - redisClientMultiCommand[OTEL_OPEN_SPANS] = - redisClientMultiCommand[OTEL_OPEN_SPANS] || []; - redisClientMultiCommand[OTEL_OPEN_SPANS]!.push({ - span, - commandName, - commandArgs, - }); - } - return res; - } - - private _endSpansWithRedisReplies( - openSpans: Array, - replies: unknown[] - ) { - if (!openSpans) { - return this._diag.error( - 'cannot find open spans to end for redis multi command' - ); - } - if (replies.length !== openSpans.length) { - return this._diag.error( - 'number of multi command spans does not match response from redis' - ); - } - for (let i = 0; i < openSpans.length; i++) { - const { span, commandName, commandArgs } = openSpans[i]; - const currCommandRes = replies[i]; - const [res, err] = - currCommandRes instanceof Error - ? [null, currCommandRes] - : [currCommandRes, undefined]; - this._endSpanWithResponse(span, commandName, commandArgs, res, err); - } - } - - private _endSpanWithResponse( - span: Span, - commandName: string, - commandArgs: Array, - response: unknown, - error: Error | undefined - ) { - const { responseHook } = this.getConfig(); - if (!error && responseHook) { - try { - responseHook(span, commandName, commandArgs, response); - } catch (err) { - this._diag.error('responseHook throw an exception', err); - } - } - if (error) { - span.recordException(error); - span.setStatus({ code: SpanStatusCode.ERROR, message: error?.message }); - } - span.end(); - } -} diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/src/internal-types.ts b/plugins/node/opentelemetry-instrumentation-redis-4/src/internal-types.ts deleted file mode 100644 index cf03d290d1..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/src/internal-types.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Error class introduced in redis@4.6.12. -// https://github.com/redis/node-redis/blob/redis@4.6.12/packages/client/lib/errors.ts#L69-L84 -export interface MultiErrorReply extends Error { - replies: unknown[]; - errorIndexes: Array; -} diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/src/types.ts b/plugins/node/opentelemetry-instrumentation-redis-4/src/types.ts deleted file mode 100644 index e15141a22e..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/src/types.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Span } from '@opentelemetry/api'; -import { InstrumentationConfig } from '@opentelemetry/instrumentation'; - -/** - * Function that can be used to serialize db.statement tag - * @param cmdName - The name of the command (eg. set, get, mset) - * @param cmdArgs - Array of arguments passed to the command - * - * @returns serialized string that will be used as the db.statement attribute. - */ -export type DbStatementSerializer = ( - cmdName: string, - cmdArgs: Array -) => string; - -/** - * Function that can be used to add custom attributes to span on response from redis server - * @param span - The span created for the redis command, on which attributes can be set - * @param cmdName - The name of the command (eg. set, get, mset) - * @param cmdArgs - Array of arguments passed to the command - * @param response - The response object which is returned to the user who called this command. - * Can be used to set custom attributes on the span. - * The type of the response varies depending on the specific command. - */ -export interface RedisResponseCustomAttributeFunction { - ( - span: Span, - cmdName: string, - cmdArgs: Array, - response: unknown - ): void; -} - -export interface RedisInstrumentationConfig extends InstrumentationConfig { - /** Custom serializer function for the db.statement tag */ - dbStatementSerializer?: DbStatementSerializer; - - /** Function for adding custom attributes on db response */ - responseHook?: RedisResponseCustomAttributeFunction; - - /** Require parent to create redis span, default when unset is false */ - requireParentSpan?: boolean; -} diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/src/utils.ts b/plugins/node/opentelemetry-instrumentation-redis-4/src/utils.ts deleted file mode 100644 index b7cc79628d..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/src/utils.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { Attributes, DiagLogger } from '@opentelemetry/api'; -import { - SEMATTRS_DB_SYSTEM, - SEMATTRS_DB_CONNECTION_STRING, - SEMATTRS_NET_PEER_NAME, - SEMATTRS_NET_PEER_PORT, - DBSYSTEMVALUES_REDIS, -} from '@opentelemetry/semantic-conventions'; - -export function getClientAttributes( - diag: DiagLogger, - options: any -): Attributes { - return { - [SEMATTRS_DB_SYSTEM]: DBSYSTEMVALUES_REDIS, - [SEMATTRS_NET_PEER_NAME]: options?.socket?.host, - [SEMATTRS_NET_PEER_PORT]: options?.socket?.port, - [SEMATTRS_DB_CONNECTION_STRING]: - removeCredentialsFromDBConnectionStringAttribute(diag, options?.url), - }; -} - -/** - * removeCredentialsFromDBConnectionStringAttribute removes basic auth from url and user_pwd from query string - * - * Examples: - * redis://user:pass@localhost:6379/mydb => redis://localhost:6379/mydb - * redis://localhost:6379?db=mydb&user_pwd=pass => redis://localhost:6379?db=mydb - */ -function removeCredentialsFromDBConnectionStringAttribute( - diag: DiagLogger, - url?: unknown -): string | undefined { - if (typeof url !== 'string' || !url) { - return; - } - - try { - const u = new URL(url); - u.searchParams.delete('user_pwd'); - u.username = ''; - u.password = ''; - return u.href; - } catch (err) { - diag.error('failed to sanitize redis connection url', err); - } - return; -} diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/test/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis-4/test/redis.test.ts deleted file mode 100644 index 14b439e797..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/test/redis.test.ts +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { diag, DiagLogLevel } from '@opentelemetry/api'; -import { - getTestSpans, - registerInstrumentationTesting, -} from '@opentelemetry/contrib-test-utils'; -import { RedisInstrumentation } from '../src'; -import type { MultiErrorReply } from '../src/internal-types'; -import * as assert from 'assert'; - -import { - redisTestConfig, - redisTestUrl, - shouldTest, - shouldTestLocal, -} from './utils'; -import * as testUtils from '@opentelemetry/contrib-test-utils'; - -const instrumentation = registerInstrumentationTesting( - new RedisInstrumentation() -); - -import { createClient, WatchError } from 'redis'; -import { - Span, - SpanKind, - SpanStatusCode, - trace, - context, -} from '@opentelemetry/api'; -import { - SEMATTRS_DB_CONNECTION_STRING, - SEMATTRS_DB_STATEMENT, - SEMATTRS_DB_SYSTEM, - SEMATTRS_EXCEPTION_MESSAGE, - SEMATTRS_NET_PEER_NAME, - SEMATTRS_NET_PEER_PORT, -} from '@opentelemetry/semantic-conventions'; -import { RedisResponseCustomAttributeFunction } from '../src/types'; -import { hrTimeToMilliseconds, suppressTracing } from '@opentelemetry/core'; - -describe('redis@^4.0.0', () => { - before(function () { - // needs to be "function" to have MochaContext "this" context - if (!shouldTest) { - // this.skip() workaround - // https://github.com/mochajs/mocha/issues/2683#issuecomment-375629901 - this.test!.parent!.pending = true; - this.skip(); - } - - if (shouldTestLocal) { - testUtils.startDocker('redis'); - } - }); - - after(() => { - if (shouldTestLocal) { - testUtils.cleanUpDocker('redis'); - } - }); - - let client: any; - - beforeEach(async () => { - client = createClient({ - url: redisTestUrl, - }); - await context.with(suppressTracing(context.active()), async () => { - await client.connect(); - }); - }); - - afterEach(async () => { - await client?.disconnect(); - }); - - describe('redis commands', () => { - it('simple set and get', async () => { - await client.set('key', 'value'); - const value = await client.get('key'); - assert.strictEqual(value, 'value'); // verify we did not screw up the normal functionality - - const spans = getTestSpans(); - assert.strictEqual(spans.length, 2); - - const setSpan = spans.find(s => s.name.includes('SET')); - assert.ok(setSpan); - assert.strictEqual(setSpan?.kind, SpanKind.CLIENT); - assert.strictEqual(setSpan?.name, 'redis-SET'); - assert.strictEqual(setSpan?.attributes[SEMATTRS_DB_SYSTEM], 'redis'); - assert.strictEqual( - setSpan?.attributes[SEMATTRS_DB_STATEMENT], - 'SET key [1 other arguments]' - ); - assert.strictEqual( - setSpan?.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - setSpan?.attributes[SEMATTRS_NET_PEER_PORT], - redisTestConfig.port - ); - assert.strictEqual( - setSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], - redisTestUrl - ); - - const getSpan = spans.find(s => s.name.includes('GET')); - assert.ok(getSpan); - assert.strictEqual(getSpan?.kind, SpanKind.CLIENT); - assert.strictEqual(getSpan?.name, 'redis-GET'); - assert.strictEqual(getSpan?.attributes[SEMATTRS_DB_SYSTEM], 'redis'); - assert.strictEqual(getSpan?.attributes[SEMATTRS_DB_STATEMENT], 'GET key'); - assert.strictEqual( - getSpan?.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - getSpan?.attributes[SEMATTRS_NET_PEER_PORT], - redisTestConfig.port - ); - assert.strictEqual( - getSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], - redisTestUrl - ); - }); - - it('send general command', async () => { - const res = await client.sendCommand(['SET', 'key', 'value']); - assert.strictEqual(res, 'OK'); // verify we did not screw up the normal functionality - - const [setSpan] = getTestSpans(); - - assert.ok(setSpan); - assert.strictEqual( - setSpan?.attributes[SEMATTRS_DB_STATEMENT], - 'SET key [1 other arguments]' - ); - assert.strictEqual( - setSpan?.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - setSpan?.attributes[SEMATTRS_NET_PEER_PORT], - redisTestConfig.port - ); - }); - - it('command with error', async () => { - await client.set('string-key', 'string-value'); - await assert.rejects(async () => await client.incr('string-key')); - - const [_setSpan, incrSpan] = getTestSpans(); - - assert.ok(incrSpan); - assert.strictEqual(incrSpan?.status.code, SpanStatusCode.ERROR); - assert.strictEqual( - incrSpan?.status.message, - 'ERR value is not an integer or out of range' - ); - - const exceptions = incrSpan.events.filter( - event => event.name === 'exception' - ); - assert.strictEqual(exceptions.length, 1); - assert.strictEqual( - exceptions?.[0].attributes?.[SEMATTRS_EXCEPTION_MESSAGE], - 'ERR value is not an integer or out of range' - ); - }); - }); - - describe('client connect', () => { - it('produces a span', async () => { - const newClient = createClient({ - url: redisTestUrl, - }); - - after(async () => { - await newClient.disconnect(); - }); - - await newClient.connect(); - - const [span] = getTestSpans(); - - assert.strictEqual(span.name, 'redis-connect'); - - assert.strictEqual(span.attributes[SEMATTRS_DB_SYSTEM], 'redis'); - assert.strictEqual( - span.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - span.attributes[SEMATTRS_NET_PEER_PORT], - redisTestConfig.port - ); - assert.strictEqual( - span.attributes[SEMATTRS_DB_CONNECTION_STRING], - redisTestUrl - ); - }); - - it('sets error status on connection failure', async () => { - const redisURL = `redis://${redisTestConfig.host}:${ - redisTestConfig.port + 1 - }`; - const newClient = createClient({ - url: redisURL, - }); - - await assert.rejects(newClient.connect()); - - const [span] = getTestSpans(); - - assert.strictEqual(span.name, 'redis-connect'); - assert.strictEqual(span.status.code, SpanStatusCode.ERROR); - assert.strictEqual( - span.attributes[SEMATTRS_DB_CONNECTION_STRING], - redisURL - ); - }); - - it('omits basic auth from DB_CONNECTION_STRING span attribute', async () => { - const redisURL = `redis://myuser:mypassword@${redisTestConfig.host}:${ - redisTestConfig.port + 1 - }`; - const expectAttributeConnString = `redis://${redisTestConfig.host}:${ - redisTestConfig.port + 1 - }`; - const newClient = createClient({ - url: redisURL, - }); - - await assert.rejects(newClient.connect()); - - const [span] = getTestSpans(); - - assert.strictEqual(span.name, 'redis-connect'); - assert.strictEqual(span.status.code, SpanStatusCode.ERROR); - assert.strictEqual( - span.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - span.attributes[SEMATTRS_DB_CONNECTION_STRING], - expectAttributeConnString - ); - }); - - it('omits user_pwd query parameter from DB_CONNECTION_STRING span attribute', async () => { - const redisURL = `redis://${redisTestConfig.host}:${ - redisTestConfig.port + 1 - }?db=mydb&user_pwd=mypassword`; - const expectAttributeConnString = `redis://${redisTestConfig.host}:${ - redisTestConfig.port + 1 - }?db=mydb`; - const newClient = createClient({ - url: redisURL, - }); - - await assert.rejects(newClient.connect()); - - const [span] = getTestSpans(); - - assert.strictEqual(span.name, 'redis-connect'); - assert.strictEqual(span.status.code, SpanStatusCode.ERROR); - assert.strictEqual( - span.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - span.attributes[SEMATTRS_DB_CONNECTION_STRING], - expectAttributeConnString - ); - }); - - it('with empty string for client URL, there is no crash and no diag.error', async () => { - // Note: This messily leaves the diag logger set for other tests. - const diagErrors = [] as any; - diag.setLogger( - { - verbose() {}, - debug() {}, - info() {}, - warn() {}, - error(...args) { - diagErrors.push(args); - }, - }, - DiagLogLevel.WARN - ); - - const newClient = createClient({ url: '' }); - try { - await newClient.connect(); - } catch (_err) { - // Ignore. If the test Redis is not at the default port we expect this - // to error. - } - await newClient.disconnect(); - - const [span] = getTestSpans(); - assert.strictEqual(span.name, 'redis-connect'); - assert.strictEqual(diagErrors.length, 0, "no diag.error's"); - }); - }); - - describe('multi (transactions) commands', () => { - it('multi commands', async () => { - await client.set('another-key', 'another-value'); - const [setKeyReply, otherKeyValue] = await client - .multi() - .set('key', 'value') - .get('another-key') - .exec(); // ['OK', 'another-value'] - - assert.strictEqual(setKeyReply, 'OK'); // verify we did not screw up the normal functionality - assert.strictEqual(otherKeyValue, 'another-value'); // verify we did not screw up the normal functionality - - const [setSpan, multiSetSpan, multiGetSpan] = getTestSpans(); - - assert.ok(setSpan); - - assert.ok(multiSetSpan); - assert.strictEqual(multiSetSpan.name, 'redis-SET'); - assert.strictEqual( - multiSetSpan.attributes[SEMATTRS_DB_STATEMENT], - 'SET key [1 other arguments]' - ); - assert.strictEqual( - multiSetSpan?.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - multiSetSpan?.attributes[SEMATTRS_NET_PEER_PORT], - redisTestConfig.port - ); - assert.strictEqual( - multiSetSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], - redisTestUrl - ); - - assert.ok(multiGetSpan); - assert.strictEqual(multiGetSpan.name, 'redis-GET'); - assert.strictEqual( - multiGetSpan.attributes[SEMATTRS_DB_STATEMENT], - 'GET another-key' - ); - assert.strictEqual( - multiGetSpan?.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - multiGetSpan?.attributes[SEMATTRS_NET_PEER_PORT], - redisTestConfig.port - ); - assert.strictEqual( - multiGetSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], - redisTestUrl - ); - }); - - it('multi command with generic command', async () => { - const [setReply] = await client - .multi() - .addCommand(['SET', 'key', 'value']) - .exec(); - assert.strictEqual(setReply, 'OK'); // verify we did not screw up the normal functionality - - const [multiSetSpan] = getTestSpans(); - assert.ok(multiSetSpan); - assert.strictEqual( - multiSetSpan.attributes[SEMATTRS_DB_STATEMENT], - 'SET key [1 other arguments]' - ); - assert.strictEqual( - multiSetSpan?.attributes[SEMATTRS_NET_PEER_NAME], - redisTestConfig.host - ); - assert.strictEqual( - multiSetSpan?.attributes[SEMATTRS_NET_PEER_PORT], - redisTestConfig.port - ); - assert.strictEqual( - multiSetSpan?.attributes[SEMATTRS_DB_CONNECTION_STRING], - redisTestUrl - ); - }); - - it('multi command with error', async () => { - let replies; - try { - replies = await client.multi().set('key', 'value').incr('key').exec(); - } catch (err) { - // Starting in redis@4.6.12 `multi().exec()` will *throw* a - // MultiErrorReply, with `err.replies`, if any of the commands error. - replies = (err as MultiErrorReply).replies; - } - const [setReply, incrReply] = replies; - - assert.strictEqual(setReply, 'OK'); // verify we did not screw up the normal functionality - assert.ok(incrReply instanceof Error); // verify we did not screw up the normal functionality - - const [multiSetSpan, multiIncrSpan] = getTestSpans(); - - assert.ok(multiSetSpan); - assert.strictEqual(multiSetSpan.status.code, SpanStatusCode.UNSET); - - assert.ok(multiIncrSpan); - assert.strictEqual(multiIncrSpan.status.code, SpanStatusCode.ERROR); - assert.strictEqual( - multiIncrSpan.status.message, - 'ERR value is not an integer or out of range' - ); - }); - - it('multi command that rejects', async () => { - const watchedKey = 'watched-key'; - await client.watch(watchedKey); - await client.set(watchedKey, 'a different value'); - try { - await client.multi().get(watchedKey).exec(); - assert.fail('expected WatchError to be thrown and caught in try/catch'); - } catch (error) { - assert.ok(error instanceof WatchError); - } - - // All the multi spans' status are set to ERROR. - const [_watchSpan, _setSpan, multiGetSpan] = getTestSpans(); - assert.strictEqual(multiGetSpan?.status.code, SpanStatusCode.ERROR); - assert.strictEqual( - multiGetSpan?.status.message, - 'One (or more) of the watched keys has been changed' - ); - }); - - it('duration covers create until server response', async () => { - await client.set('another-key', 'another-value'); - const multiClient = client.multi(); - let commands = multiClient.set('key', 'value'); - // wait 10 ms before adding next command - // simulate long operation - await new Promise(resolve => setTimeout(resolve, 10)); - commands = commands.get('another-key'); - const [setKeyReply, otherKeyValue] = await commands.exec(); // ['OK', 'another-value'] - - assert.strictEqual(setKeyReply, 'OK'); // verify we did not screw up the normal functionality - assert.strictEqual(otherKeyValue, 'another-value'); // verify we did not screw up the normal functionality - - const [_setSpan, multiSetSpan, multiGetSpan] = getTestSpans(); - // verify that commands span started when it was added to multi and not when "sent". - // they were called with 10 ms gap between them, so it should be reflected in the span start time - // could be nice feature in the future to capture an event for when it is actually sent - const startTimeDiff = - hrTimeToMilliseconds(multiGetSpan.startTime) - - hrTimeToMilliseconds(multiSetSpan.startTime); - assert.ok( - startTimeDiff >= 9, - `diff of start time should be >= 10 and it's ${startTimeDiff}` - ); - - const endTimeDiff = - hrTimeToMilliseconds(multiGetSpan.endTime) - - hrTimeToMilliseconds(multiSetSpan.endTime); - assert.ok(endTimeDiff < 10); // spans should all end together when multi response arrives from redis server - }); - - it('response hook for multi commands', async () => { - const responseHook: RedisResponseCustomAttributeFunction = ( - span: Span, - cmdName: string, - cmdArgs: Array, - response: unknown - ) => { - span.setAttribute('test.cmd.name', cmdName); - span.setAttribute('test.cmd.args', cmdArgs as string[]); - span.setAttribute('test.db.response', response as string); - }; - instrumentation.setConfig({ responseHook }); - - await client.set('another-key', 'another-value'); - const [setKeyReply, otherKeyValue] = await client - .multi() - .set('key', 'value') - .get('another-key') - .exec(); // ['OK', 'another-value'] - assert.strictEqual(setKeyReply, 'OK'); // verify we did not screw up the normal functionality - assert.strictEqual(otherKeyValue, 'another-value'); // verify we did not screw up the normal functionality - - const [_setSpan, multiSetSpan, multiGetSpan] = getTestSpans(); - - assert.ok(multiSetSpan); - assert.strictEqual(multiSetSpan.attributes['test.cmd.name'], 'SET'); - assert.deepStrictEqual(multiSetSpan.attributes['test.cmd.args'], [ - 'key', - 'value', - ]); - assert.strictEqual(multiSetSpan.attributes['test.db.response'], 'OK'); - - assert.ok(multiGetSpan); - assert.strictEqual(multiGetSpan.attributes['test.cmd.name'], 'GET'); - assert.deepStrictEqual(multiGetSpan.attributes['test.cmd.args'], [ - 'another-key', - ]); - assert.strictEqual( - multiGetSpan.attributes['test.db.response'], - 'another-value' - ); - }); - }); - - describe('config', () => { - describe('dbStatementSerializer', () => { - it('custom dbStatementSerializer', async () => { - const dbStatementSerializer = ( - cmdName: string, - cmdArgs: Array - ) => { - return `${cmdName} ${cmdArgs.join(' ')}`; - }; - - instrumentation.setConfig({ dbStatementSerializer }); - await client.set('key', 'value'); - const [span] = getTestSpans(); - assert.strictEqual( - span.attributes[SEMATTRS_DB_STATEMENT], - 'SET key value' - ); - }); - - it('dbStatementSerializer throws', async () => { - const dbStatementSerializer = () => { - throw new Error('dbStatementSerializer error'); - }; - - instrumentation.setConfig({ dbStatementSerializer }); - await client.set('key', 'value'); - const [span] = getTestSpans(); - assert.ok(span); - assert.ok(!(SEMATTRS_DB_STATEMENT in span.attributes)); - }); - }); - - describe('responseHook', () => { - it('valid response hook', async () => { - const responseHook: RedisResponseCustomAttributeFunction = ( - span: Span, - cmdName: string, - cmdArgs: Array, - response: unknown - ) => { - span.setAttribute('test.cmd.name', cmdName); - span.setAttribute('test.cmd.args', cmdArgs as string[]); - span.setAttribute('test.db.response', response as string); - }; - instrumentation.setConfig({ responseHook }); - await client.set('key', 'value'); - const [span] = getTestSpans(); - assert.ok(span); - assert.strictEqual(span.attributes['test.cmd.name'], 'SET'); - assert.deepStrictEqual(span.attributes['test.cmd.args'], [ - 'key', - 'value', - ]); - assert.strictEqual(span.attributes['test.db.response'], 'OK'); - }); - - it('responseHook throws', async () => { - const responseHook = () => { - throw new Error('responseHook error'); - }; - instrumentation.setConfig({ responseHook }); - const res = await client.set('key', 'value'); - assert.strictEqual(res, 'OK'); // package is still functional - const [span] = getTestSpans(); - assert.ok(span); - }); - }); - - describe('requireParentSpan', () => { - it('set to true', async () => { - instrumentation.setConfig({ requireParentSpan: true }); - - // no parent span => no redis span - const res = await client.set('key', 'value'); - assert.strictEqual(res, 'OK'); // verify we did not screw up the normal functionality - assert.ok(getTestSpans().length === 0); - - // has ambient span => redis span - const span = trace.getTracer('test').startSpan('test span'); - await context.with(trace.setSpan(context.active(), span), async () => { - const res = await client.set('key', 'value'); - assert.strictEqual(res, 'OK'); // verify we did not screw up the normal functionality - assert.ok(getTestSpans().length === 1); - }); - span.end(); - }); - }); - }); -}); diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/test/utils.ts b/plugins/node/opentelemetry-instrumentation-redis-4/test/utils.ts deleted file mode 100644 index cc0e0a6609..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/test/utils.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export const redisTestConfig = { - host: process.env.OPENTELEMETRY_REDIS_HOST || 'localhost', - port: +(process.env.OPENTELEMETRY_REDIS_PORT || 63790), -}; - -export const redisTestUrl = `redis://${redisTestConfig.host}:${redisTestConfig.port}`; - -export const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; -export const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/tsconfig.json b/plugins/node/opentelemetry-instrumentation-redis-4/tsconfig.json deleted file mode 100644 index 28be80d266..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../../tsconfig.base", - "compilerOptions": { - "rootDir": ".", - "outDir": "build" - }, - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ] -} From d50bc22fb6d21eac93863b43d0452490e146afe1 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 15:58:40 -0700 Subject: [PATCH 18/28] loosen types on v2/v3 tests (mostly) to not have to have v3 redis types around to compile --- .../src/v2-v3/internal-types.ts | 3 +++ .../src/v2-v3/utils.ts | 7 +++---- .../test/v2-v3/redis.test.ts | 19 +++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/internal-types.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/internal-types.ts index 25c2fc6b34..a3421deeb9 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/internal-types.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/internal-types.ts @@ -31,3 +31,6 @@ export interface RedisCommand { callback: (err: Error | null, reply: unknown) => void; call_on_write: boolean; } + +// Exported from "@types/redis@2.8.32". +export type Callback = (err: Error | null, reply: T) => void; diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/utils.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/utils.ts index 15df6043bf..456ebf9fe4 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/utils.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import type * as redisTypes from 'redis'; import { context, Span, SpanStatusCode } from '@opentelemetry/api'; import { EventEmitter } from 'events'; @@ -29,14 +28,14 @@ export const endSpan = (span: Span, err?: Error | null) => { }; export const getTracedCreateClient = (original: Function) => { - return function createClientTrace(this: redisTypes.RedisClient) { - const client: redisTypes.RedisClient = original.apply(this, arguments); + return function createClientTrace(this: any) { + const client = original.apply(this, arguments); return context.bind(context.active(), client); }; }; export const getTracedCreateStreamTrace = (original: Function) => { - return function create_stream_trace(this: redisTypes.RedisClient) { + return function create_stream_trace(this: any) { if (!Object.prototype.hasOwnProperty.call(this, 'stream')) { Object.defineProperty(this, 'stream', { get() { diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts index 6cbf5e21f4..dd07c6e1e6 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts @@ -43,7 +43,7 @@ const instrumentation = registerInstrumentationTesting( new RedisInstrumentation() ); -import * as redisTypes from 'redis'; +import type { Callback } from '../../src/v2-v3/internal-types'; import { RedisResponseCustomAttributeFunction } from '../../src/types'; const CONFIG = { @@ -65,7 +65,7 @@ const unsetStatus: SpanStatus = { }; describe('redis v2-v3', () => { - let redis: typeof redisTypes; + let redis: any; const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; const tracer = trace.getTracer('external'); @@ -95,7 +95,7 @@ describe('redis v2-v3', () => { describe('#createClient()', () => { it('should propagate the current span to event handlers', done => { const span = tracer.startSpan('test span'); - let client: redisTypes.RedisClient; + let client: any; const readyHandler = () => { assert.strictEqual(trace.getSpan(context.active()), span); client.quit(done); @@ -114,21 +114,21 @@ describe('redis v2-v3', () => { }); describe('#send_internal_message()', () => { - let client: redisTypes.RedisClient; + let client: any; const REDIS_OPERATIONS: Array<{ description: string; command: string; args: string[]; expectedDbStatement: string; - method: (cb: redisTypes.Callback) => unknown; + method: (cb: Callback) => unknown; }> = [ { description: 'insert', command: 'hset', args: ['hash', 'random', 'random'], expectedDbStatement: 'hash random [1 other arguments]', - method: (cb: redisTypes.Callback) => + method: (cb: Callback) => client.hset('hash', 'random', 'random', cb), }, { @@ -136,21 +136,20 @@ describe('redis v2-v3', () => { command: 'get', args: ['test'], expectedDbStatement: 'test', - method: (cb: redisTypes.Callback) => - client.get('test', cb), + method: (cb: Callback) => client.get('test', cb), }, { description: 'delete', command: 'del', args: ['test'], expectedDbStatement: 'test', - method: (cb: redisTypes.Callback) => client.del('test', cb), + method: (cb: Callback) => client.del('test', cb), }, ]; before(done => { client = redis.createClient(URL); - client.on('error', err => { + client.on('error', (err: any) => { done(err); }); client.on('ready', done); From 91c42621686f4b9c07ee22422a1a87c9b9bd59de Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 16:00:58 -0700 Subject: [PATCH 19/28] drop @types/redis dep; fix release-please config --- .release-please-manifest.json | 1 - package-lock.json | 20 ------------------- .../package.json | 1 - 3 files changed, 22 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4c811c3413..6c664982a6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -54,7 +54,6 @@ "plugins/node/opentelemetry-instrumentation-pg": "0.54.0", "plugins/node/opentelemetry-instrumentation-pino": "0.49.0", "plugins/node/opentelemetry-instrumentation-redis": "0.49.1", - "plugins/node/opentelemetry-instrumentation-redis-4": "0.49.0", "plugins/node/opentelemetry-instrumentation-restify": "0.48.1", "plugins/node/opentelemetry-instrumentation-router": "0.47.0", "plugins/node/opentelemetry-instrumentation-winston": "0.47.0", diff --git a/package-lock.json b/package-lock.json index 675ffce3f8..9af3fabe67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10649,15 +10649,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/@types/redis": { - "version": "2.8.32", - "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.32.tgz", - "integrity": "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -33848,7 +33839,6 @@ "@opentelemetry/sdk-trace-node": "^2.0.0", "@types/mocha": "10.0.10", "@types/node": "18.18.14", - "@types/redis": "2.8.32", "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "^4.7.1", @@ -41236,7 +41226,6 @@ "@opentelemetry/semantic-conventions": "^1.27.0", "@types/mocha": "10.0.10", "@types/node": "18.18.14", - "@types/redis": "2.8.32", "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "^4.7.1", @@ -44185,15 +44174,6 @@ } } }, - "@types/redis": { - "version": "2.8.32", - "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.32.tgz", - "integrity": "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index 5c0e7cf689..ec9cbeb8e5 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -56,7 +56,6 @@ "@opentelemetry/sdk-trace-node": "^2.0.0", "@types/mocha": "10.0.10", "@types/node": "18.18.14", - "@types/redis": "2.8.32", "cross-env": "7.0.3", "nyc": "17.1.0", "redis": "^4.7.1", From 0d6f1ef0285a9fc7e67f084c5db6946869d7c7d1 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 16:01:12 -0700 Subject: [PATCH 20/28] another release-please config update --- release-please-config.json | 1 - 1 file changed, 1 deletion(-) diff --git a/release-please-config.json b/release-please-config.json index 9bbf8c8763..c876839294 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -61,7 +61,6 @@ "plugins/node/opentelemetry-instrumentation-pg": {}, "plugins/node/opentelemetry-instrumentation-pino": {}, "plugins/node/opentelemetry-instrumentation-redis": {}, - "plugins/node/opentelemetry-instrumentation-redis-4": {}, "plugins/node/opentelemetry-instrumentation-restify": {}, "plugins/node/opentelemetry-instrumentation-router": {}, "plugins/node/opentelemetry-instrumentation-winston": {}, From d2fa3a2828b30b58b749128a3dda2196d7628c83 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 26 Jun 2025 16:31:18 -0700 Subject: [PATCH 21/28] drop instr-redis-4 from auto-instrumentations-node --- .../auto-instrumentations-node/package.json | 1 - .../auto-instrumentations-node/src/utils.ts | 6 +- package-lock.json | 178 +----------------- 3 files changed, 3 insertions(+), 182 deletions(-) diff --git a/metapackages/auto-instrumentations-node/package.json b/metapackages/auto-instrumentations-node/package.json index f13f47b463..abd48457e4 100644 --- a/metapackages/auto-instrumentations-node/package.json +++ b/metapackages/auto-instrumentations-node/package.json @@ -82,7 +82,6 @@ "@opentelemetry/instrumentation-pg": "^0.54.0", "@opentelemetry/instrumentation-pino": "^0.49.0", "@opentelemetry/instrumentation-redis": "^0.49.1", - "@opentelemetry/instrumentation-redis-4": "^0.49.0", "@opentelemetry/instrumentation-restify": "^0.48.1", "@opentelemetry/instrumentation-router": "^0.47.0", "@opentelemetry/instrumentation-runtime-node": "^0.16.0", diff --git a/metapackages/auto-instrumentations-node/src/utils.ts b/metapackages/auto-instrumentations-node/src/utils.ts index 82d552695a..eea8d06869 100644 --- a/metapackages/auto-instrumentations-node/src/utils.ts +++ b/metapackages/auto-instrumentations-node/src/utils.ts @@ -49,8 +49,7 @@ import { NetInstrumentation } from '@opentelemetry/instrumentation-net'; import { OracleInstrumentation } from '@opentelemetry/instrumentation-oracledb'; import { PgInstrumentation } from '@opentelemetry/instrumentation-pg'; import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino'; -import { RedisInstrumentation as RedisInstrumentationV2 } from '@opentelemetry/instrumentation-redis'; -import { RedisInstrumentation as RedisInstrumentationV4 } from '@opentelemetry/instrumentation-redis-4'; +import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis'; import { RestifyInstrumentation } from '@opentelemetry/instrumentation-restify'; import { RouterInstrumentation } from '@opentelemetry/instrumentation-router'; import { RuntimeNodeInstrumentation } from '@opentelemetry/instrumentation-runtime-node'; @@ -128,8 +127,7 @@ const InstrumentationMap = { '@opentelemetry/instrumentation-oracledb': OracleInstrumentation, '@opentelemetry/instrumentation-pg': PgInstrumentation, '@opentelemetry/instrumentation-pino': PinoInstrumentation, - '@opentelemetry/instrumentation-redis': RedisInstrumentationV2, - '@opentelemetry/instrumentation-redis-4': RedisInstrumentationV4, + '@opentelemetry/instrumentation-redis': RedisInstrumentation, '@opentelemetry/instrumentation-restify': RestifyInstrumentation, '@opentelemetry/instrumentation-router': RouterInstrumentation, '@opentelemetry/instrumentation-runtime-node': RuntimeNodeInstrumentation, diff --git a/package-lock.json b/package-lock.json index 9af3fabe67..bd41880ed4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -309,7 +309,6 @@ "@opentelemetry/instrumentation-pg": "^0.54.0", "@opentelemetry/instrumentation-pino": "^0.49.0", "@opentelemetry/instrumentation-redis": "^0.49.1", - "@opentelemetry/instrumentation-redis-4": "^0.49.0", "@opentelemetry/instrumentation-restify": "^0.48.1", "@opentelemetry/instrumentation-router": "^0.47.0", "@opentelemetry/instrumentation-runtime-node": "^0.16.0", @@ -8205,10 +8204,6 @@ "resolved": "plugins/node/opentelemetry-instrumentation-redis", "link": true }, - "node_modules/@opentelemetry/instrumentation-redis-4": { - "resolved": "plugins/node/opentelemetry-instrumentation-redis-4", - "link": true - }, "node_modules/@opentelemetry/instrumentation-restify": { "resolved": "plugins/node/opentelemetry-instrumentation-restify", "link": true @@ -8670,71 +8665,6 @@ "streamx": "^2.15.0" } }, - "node_modules/@redis/bloom": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", - "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/client": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.1.0.tgz", - "integrity": "sha512-xO9JDIgzsZYDl3EvFhl6LC52DP3q3GCMUer8zHgKV6qSYsq1zB+pZs9+T80VgcRogrlRYhi4ZlfX6A+bHiBAgA==", - "dev": true, - "dependencies": { - "cluster-key-slot": "1.1.0", - "generic-pool": "3.8.2", - "yallist": "4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@redis/client/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@redis/graph": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", - "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz", - "integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/search": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.0.6.tgz", - "integrity": "sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/time-series": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", - "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==", - "dev": true, - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, "node_modules/@rollup/plugin-commonjs": { "version": "26.0.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-26.0.3.tgz", @@ -33856,6 +33786,7 @@ "plugins/node/opentelemetry-instrumentation-redis-4": { "name": "@opentelemetry/instrumentation-redis-4", "version": "0.49.0", + "extraneous": true, "license": "Apache-2.0", "dependencies": { "@opentelemetry/instrumentation": "^0.202.0", @@ -33885,20 +33816,6 @@ "@opentelemetry/api": "^1.3.0" } }, - "plugins/node/opentelemetry-instrumentation-redis-4/node_modules/redis": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.1.0.tgz", - "integrity": "sha512-5hvJ8wbzpCCiuN1ges6tx2SAh2XXCY0ayresBmu40/SGusWHFW86TAlIPpbimMX2DFHOX7RN34G2XlPA1Z43zg==", - "dev": true, - "dependencies": { - "@redis/bloom": "1.0.2", - "@redis/client": "1.1.0", - "@redis/graph": "1.0.1", - "@redis/json": "1.0.3", - "@redis/search": "1.0.6", - "@redis/time-series": "1.0.3" - } - }, "plugins/node/opentelemetry-instrumentation-restify": { "name": "@opentelemetry/instrumentation-restify", "version": "0.48.1", @@ -39969,7 +39886,6 @@ "@opentelemetry/instrumentation-pg": "^0.54.0", "@opentelemetry/instrumentation-pino": "^0.49.0", "@opentelemetry/instrumentation-redis": "^0.49.1", - "@opentelemetry/instrumentation-redis-4": "^0.49.0", "@opentelemetry/instrumentation-restify": "^0.48.1", "@opentelemetry/instrumentation-router": "^0.47.0", "@opentelemetry/instrumentation-runtime-node": "^0.16.0", @@ -41234,44 +41150,6 @@ "typescript": "5.0.4" } }, - "@opentelemetry/instrumentation-redis-4": { - "version": "file:plugins/node/opentelemetry-instrumentation-redis-4", - "requires": { - "@opentelemetry/api": "^1.3.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/contrib-test-utils": "^0.48.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/redis-common": "^0.37.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/sdk-trace-node": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/mocha": "10.0.10", - "@types/node": "18.18.14", - "cross-env": "7.0.3", - "nyc": "17.1.0", - "redis": "4.1.0", - "rimraf": "5.0.10", - "test-all-versions": "6.1.0", - "typescript": "5.0.4" - }, - "dependencies": { - "redis": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.1.0.tgz", - "integrity": "sha512-5hvJ8wbzpCCiuN1ges6tx2SAh2XXCY0ayresBmu40/SGusWHFW86TAlIPpbimMX2DFHOX7RN34G2XlPA1Z43zg==", - "dev": true, - "requires": { - "@redis/bloom": "1.0.2", - "@redis/client": "1.1.0", - "@redis/graph": "1.0.1", - "@redis/json": "1.0.3", - "@redis/search": "1.0.6", - "@redis/time-series": "1.0.3" - } - } - } - }, "@opentelemetry/instrumentation-restify": { "version": "file:plugins/node/opentelemetry-instrumentation-restify", "requires": { @@ -42579,60 +42457,6 @@ } } }, - "@redis/bloom": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", - "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==", - "dev": true, - "requires": {} - }, - "@redis/client": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.1.0.tgz", - "integrity": "sha512-xO9JDIgzsZYDl3EvFhl6LC52DP3q3GCMUer8zHgKV6qSYsq1zB+pZs9+T80VgcRogrlRYhi4ZlfX6A+bHiBAgA==", - "dev": true, - "requires": { - "cluster-key-slot": "1.1.0", - "generic-pool": "3.8.2", - "yallist": "4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "@redis/graph": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", - "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==", - "dev": true, - "requires": {} - }, - "@redis/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz", - "integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==", - "dev": true, - "requires": {} - }, - "@redis/search": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.0.6.tgz", - "integrity": "sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA==", - "dev": true, - "requires": {} - }, - "@redis/time-series": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", - "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==", - "dev": true, - "requires": {} - }, "@rollup/plugin-commonjs": { "version": "26.0.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-26.0.3.tgz", From 7408ca16b93e6c322cbef3a0dd95a41bb34efd65 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 27 Jun 2025 08:51:20 -0700 Subject: [PATCH 22/28] flail to fix "npm run compile" for test/v4/redis.test.ts I say "flail" because I'm not sure if the import type ... from '@redis/client'; worked before *because `@types/redis` was installed?!* or something else was different. --- .../opentelemetry-instrumentation-redis/test/v4/redis.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts index c21800bd71..d4d6897ae8 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts @@ -36,7 +36,7 @@ const instrumentation = registerInstrumentationTesting( ); import { createClient } from 'redis'; -import type { RedisClientType } from '@redis/client'; +import type { RedisClientType } from 'redis'; import { Span, SpanKind, From 33399f3f7a71826fc216a41d0f3c2d52a2db7403 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 27 Jun 2025 09:07:14 -0700 Subject: [PATCH 23/28] remove 'extraneous' package-lock section for dropped instrumentation-redis-4 workspace package --- package-lock.json | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index bd41880ed4..c19c8c3b5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33783,39 +33783,6 @@ "@opentelemetry/api": "^1.3.0" } }, - "plugins/node/opentelemetry-instrumentation-redis-4": { - "name": "@opentelemetry/instrumentation-redis-4", - "version": "0.49.0", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/redis-common": "^0.37.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "devDependencies": { - "@opentelemetry/api": "^1.3.0", - "@opentelemetry/context-async-hooks": "^2.0.0", - "@opentelemetry/contrib-test-utils": "^0.48.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/sdk-trace-base": "^2.0.0", - "@opentelemetry/sdk-trace-node": "^2.0.0", - "@types/mocha": "10.0.10", - "@types/node": "18.18.14", - "cross-env": "7.0.3", - "nyc": "17.1.0", - "redis": "4.1.0", - "rimraf": "5.0.10", - "test-all-versions": "6.1.0", - "typescript": "5.0.4" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, "plugins/node/opentelemetry-instrumentation-restify": { "name": "@opentelemetry/instrumentation-restify", "version": "0.48.1", From f8e7b937aaece882283069a5f64f717b5832bcc2 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 27 Jun 2025 09:26:07 -0700 Subject: [PATCH 24/28] update README about moved sources and link to the latest release source code --- .../CHANGELOG.md | 479 ------------------ .../LICENSE | 201 -------- .../README.md | 105 +--- 3 files changed, 3 insertions(+), 782 deletions(-) delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/CHANGELOG.md delete mode 100644 plugins/node/opentelemetry-instrumentation-redis-4/LICENSE diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/CHANGELOG.md b/plugins/node/opentelemetry-instrumentation-redis-4/CHANGELOG.md deleted file mode 100644 index d9ad35a265..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/CHANGELOG.md +++ /dev/null @@ -1,479 +0,0 @@ -# Changelog - -## [0.49.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.48.0...instrumentation-redis-4-v0.49.0) (2025-06-02) - - -### Features - -* **deps:** update deps matching '@opentelemetry/*' ([#2871](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2871)) ([d33c6f2](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/d33c6f232a3c5673e618fa62692d2d3bbfe4c0fc)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.47.0 to ^0.48.0 - -## [0.48.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.47.0...instrumentation-redis-4-v0.48.0) (2025-05-15) - - -### Features - -* **deps:** update deps matching '@opentelemetry/*' ([#2828](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2828)) ([59c2a4c](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/59c2a4c002992518da2d91b4ceb24f8479ad2346)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.46.0 to ^0.47.0 - -## [0.47.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.46.1...instrumentation-redis-4-v0.47.0) (2025-03-18) - - -### ⚠ BREAKING CHANGES - -* chore!: Update to 2.x and 0.200.x @opentelemetry/* packages from opentelemetry-js.git per [2.x upgrade guide](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/upgrade-to-2.x.md) - * The minimum supported Node.js has been raised to ^18.19.0 || >=20.6.0. This means that support for Node.js 14 and 16 has been dropped. - * The minimum supported TypeScript version has been raised to 5.0.4. - * The compilation target for transpiled TypeScript has been raised to ES2022 (from ES2017). - -### Bug Fixes - -* **deps:** update otel core experimental to ^0.57.2 ([#2716](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2716)) ([d2a9a20](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/d2a9a20f1cd8c46c842e18490a4eba36fd71c2da)) - - -### Miscellaneous Chores - -* update to JS SDK 2.x ([#2738](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2738)) ([7fb4ba3](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/7fb4ba3bc36dc616bd86375cfd225722b850d0d5)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @opentelemetry/redis-common bumped from ^0.36.2 to ^0.37.0 - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.45.1 to ^0.46.0 - -## [0.46.1](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.46.0...instrumentation-redis-4-v0.46.1) (2025-02-19) - - -### Bug Fixes - -* **deps:** update otel core experimental to ^0.57.1 ([#2687](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2687)) ([5e20fe2](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/5e20fe2f450a1be4ea100e8a6d196e33ccff0cda)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.45.0 to ^0.45.1 - -## [0.46.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.45.0...instrumentation-redis-4-v0.46.0) (2024-12-18) - - -### Features - -* **deps:** update deps matching '@opentelemetry/*' ([#2608](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2608)) ([aa46705](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/aa46705d2fd1bd5ee6d763ac8cd73a7630889d34)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.44.0 to ^0.45.0 - -## [0.45.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.44.0...instrumentation-redis-4-v0.45.0) (2024-12-04) - - -### Features - -* **deps:** update deps matching '@opentelemetry/*' ([#2582](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2582)) ([5df02cb](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/5df02cbb35681d2b5cce359dda7b023d7bf339f2)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.43.0 to ^0.44.0 - -## [0.44.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.43.0...instrumentation-redis-4-v0.44.0) (2024-11-18) - - -### Features - -* **deps:** update deps matching '@opentelemetry/*' ([#2535](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2535)) ([5223a6c](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/5223a6ca10c5930cf2753271e1e670ae682d6d9c)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.42.0 to ^0.43.0 - -## [0.43.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.42.1...instrumentation-redis-4-v0.43.0) (2024-10-25) - - -### Features - -* update "@opentelemetry/*" dependencies to 1.27.0/0.54.0 ([2822511](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/2822511a8acffb875ebd67ff2cf95980a9ddc01e)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.41.0 to ^0.42.0 - -## [0.42.1](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.42.0...instrumentation-redis-4-v0.42.1) (2024-10-08) - - -### Bug Fixes - -* **instrumentation-redis-4:** avoid diag.error spam when configured client URL is the empty string ([#2399](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2399)) ([ec3b9c8](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/ec3b9c87aa2c79dc8cdcb4023df71dcafc6f08a4)), closes [#2389](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2389) - -## [0.42.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.41.1...instrumentation-redis-4-v0.42.0) (2024-09-02) - - -### Features - -* update deps matching "@opentelemetry/" ([9fa058e](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/9fa058ebb919de4e2a4e1af95b3c792c6ea962ac)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.40.0 to ^0.41.0 - -## [0.41.1](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.41.0...instrumentation-redis-4-v0.41.1) (2024-08-27) - - -### Bug Fixes - -* **instrumentation-redis-4:** avoid crash from incorrect this._diag ref ([#2397](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2397)) ([de7a6cb](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/de7a6cb77e643ed0de82e514510089fba5ae0405)), closes [#2389](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2389) - -## [0.41.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.40.0...instrumentation-redis-4-v0.41.0) (2024-07-03) - - -### ⚠ BREAKING CHANGES - -* standardize supported versions and set upper bound limit ([#2196](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2196)) - -### Bug Fixes - -* standardize supported versions and set upper bound limit ([#2196](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2196)) ([01c28ae](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/01c28ae016ed32f9968e52bc91e3e3700dcef82e)) - -## [0.40.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.39.0...instrumentation-redis-4-v0.40.0) (2024-06-06) - - -### Features - -* update otel core dependencies ([#2257](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2257)) ([71c15d5](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/71c15d597276773c19c16c1117b8d151892e5366)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.39.0 to ^0.40.0 - -## [0.39.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.38.0...instrumentation-redis-4-v0.39.0) (2024-04-25) - - -### Features - -* **deps:** update otel-js to 0.51.0 ([80cbee7](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/80cbee73130c65c8ccd78384485a7be8d2a4a84b)) -* remove generic type from instrumentations ([80cbee7](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/80cbee73130c65c8ccd78384485a7be8d2a4a84b)) - - -### Bug Fixes - -* revert modifications to Apache license ([#2105](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2105)) ([4590c8d](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/4590c8df184bbcb9bd67ce1111df9f25f865ccf2)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @opentelemetry/redis-common bumped from ^0.36.1 to ^0.36.2 - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.38.0 to ^0.39.0 - -## [0.38.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.37.0...instrumentation-redis-4-v0.38.0) (2024-04-03) - - -### Features - -* **deps:** update otel-js to 1.23.0/0.50.0 ([#2076](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2076)) ([d5f079b](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/d5f079b3992395dcfb3b791c9fdaeefd6d6526f8)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.37.0 to ^0.38.0 - -## [0.37.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.36.0...instrumentation-redis-4-v0.37.0) (2024-03-06) - - -### Features - -* **deps:** update otel-js to 1.22.0/0.49.1 ([edc426b](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/edc426b348bc5f45ff6816bcd5ea7473251a05df)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.36.0 to ^0.37.0 - -## [0.36.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.35.6...instrumentation-redis-4-v0.36.0) (2024-01-29) - - -### Features - -* **deps:** update otel-js to 1.21.0/0.48.0 ([9624486](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/96244869d0fe22e6006fa6ef5e54839e06afb99d)) - - -### Bug Fixes - -* **instrumentation-redis-4:** fix multi.exec() instrumentation for redis >=4.6.12 ([#1904](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1904)) ([fce7d3b](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/fce7d3b5e478ff7525c9ffe99e59bf35f8c06207)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.35.1 to ^0.36.0 - -## [0.35.6](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.35.5...instrumentation-redis-4-v0.35.6) (2024-01-04) - - -### Bug Fixes - -* **deps:** update otel core experimental ([#1866](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1866)) ([9366543](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/9366543f5572e1e976ce176ddeb0b438f6c16c45)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.35.0 to ^0.35.1 - -## [0.35.4](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.35.3...instrumentation-redis-4-v0.35.4) (2023-11-13) - - -### Bug Fixes - -* **deps:** update otel core experimental to v0.45.0 ([#1779](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1779)) ([7348635](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/734863562c25cd0497aa3f51eccb2bf8bbd5e711)) -* **deps:** update otel core experimental to v0.45.1 ([#1781](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1781)) ([7f420e2](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/7f420e25a8d396c83fd38101088434210705e365)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.34.2 to ^0.34.3 - -## [0.35.3](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.35.2...instrumentation-redis-4-v0.35.3) (2023-10-13) - - -### Bug Fixes - -* **instrumentation-redis-4:** avoid shimmer warning by only wrapping multi/MULTI if they exist ([#1729](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1729)) ([247a81c](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/247a81c047264ba638abb9a2ef2ca14801094040)) -* **instrumentation-redis-4:** fix unhandledRejection in client.multi(...) handling ([#1730](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1730)) ([d953531](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/d95353179279e3cf35ec37b6ca18f1e920691e16)) - -## [0.35.2](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.35.1...instrumentation-redis-4-v0.35.2) (2023-10-10) - - -### Bug Fixes - -* **deps:** update otel core experimental to v0.43.0 ([#1676](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1676)) ([deb9aa4](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/deb9aa441dc7d2b0fd5ec11b41c934a1e93134fd)) -* **deps:** update otel core experimental to v0.44.0 ([#1725](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1725)) ([540a0d1](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/540a0d1ff5641522abba560d59a298084f786630)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.34.1 to ^0.34.2 - -## [0.35.1](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.35.0...instrumentation-redis-4-v0.35.1) (2023-08-14) - - -### Bug Fixes - -* **deps:** update otel core experimental to v0.41.2 ([#1628](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1628)) ([4f11245](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/4f1124524aee565c3cfbf3975aa5d3d039377621)) -* **redis-4:** omit credentials from db.connection_string span attribute ([#1562](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1562)) ([ccf1efe](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/ccf1efe0cf8f144ab0d0aab490dfff499bd3158e)) -* Revert "feat(minification): Add importHelpers and tslib as a dependency ([#1545](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1545))" ([#1611](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1611)) ([e5bca5f](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/e5bca5fe5b27adc59c8de8fe4087d38b69d93bd4)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @opentelemetry/redis-common bumped from ^0.36.0 to ^0.36.1 - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.34.0 to ^0.34.1 - -## [0.35.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.34.6...instrumentation-redis-4-v0.35.0) (2023-07-12) - - -### Features - -* **minification:** Add importHelpers and tslib as a dependency ([#1545](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1545)) ([65f612e](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/65f612e35c4d67b9935dc3a9155588b35d915482)) - - -### Bug Fixes - -* **deps:** update otel core experimental to ^0.41.0 ([#1566](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1566)) ([84a2377](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/84a2377845c313f0ca68b4de7f3e7a464be68885)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @opentelemetry/redis-common bumped from ^0.35.1 to ^0.36.0 - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.33.4 to ^0.34.0 - -## [0.34.6](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.34.5...instrumentation-redis-4-v0.34.6) (2023-06-12) - - -### Bug Fixes - -* **deps:** update otel core experimental to ^0.40.0 ([#1527](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1527)) ([4e18a46](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/4e18a46396eb2f06e86790dbbd68075c4c2dc83b)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.33.3 to ^0.33.4 - -## [0.34.5](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.34.4...instrumentation-redis-4-v0.34.5) (2023-05-16) - - -### Bug Fixes - -* **deps:** update otel core experimental to ^0.39.1 ([#1493](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1493)) ([8ef95bc](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/8ef95bccc2d03302089f256f3d0ee091869b4c44)) -* **eslint-config:** replace gts with prettier and eslint ([#1439](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1439)) ([2571c37](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/2571c371be1b5738442200cab2415b6a04c32aab)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @opentelemetry/redis-common bumped from ^0.35.0 to ^0.35.1 - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.33.2 to ^0.33.3 - -## [0.34.4](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.34.3...instrumentation-redis-4-v0.34.4) (2023-04-25) - - -### Bug Fixes - -* **deps:** update otel core experimental to ^0.38.0 ([#1468](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1468)) ([565a2b2](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/565a2b2c6fde88af3f5401ef6a5a9643d0d66349)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.33.1 to ^0.33.2 - -## [0.34.2](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.34.1...instrumentation-redis-4-v0.34.2) (2023-02-07) - - -### Bug Fixes - -* **deps:** update otel core experimental to ^0.35.1 ([#1358](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1358)) ([ff109b7](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/ff109b77928cc9a139a21c63d6b54399bb017fa4)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.33.0 to ^0.33.1 - -## [0.34.1](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.34.0...instrumentation-redis-4-v0.34.1) (2022-12-20) - - -### Bug Fixes - -* **redis-4:** add support to new version of redis ([#1324](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1324)) ([378f130](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/378f130befb2bd8be42d367b9db5ae9329d57b5e)) -* **redis:** serialize non sensitive arguments into db.statement attribute ([#1299](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1299)) ([092a250](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/092a2509bcf884e1b997e0eaec3a6ca02cfd2058)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * @opentelemetry/redis-common bumped from ^0.33.0 to ^0.34.0 - -## [0.34.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.33.1...instrumentation-redis-4-v0.34.0) (2022-11-16) - - -### Features - -* update experimental deps to `^0.34.0`, core deps to `^1.8.0`, api to `^1.3.0` ([#1278](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1278)) ([e9fe8e1](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/e9fe8e13e34f54e96c50525cadeb74ac048c5624)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.32.0 to ^0.33.0 - -## [0.33.1](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.33.0...instrumentation-redis-4-v0.33.1) (2022-11-02) - - -### Bug Fixes - -* separate public and internal types for all instrumentations ([#1251](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1251)) ([e72ea58](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/e72ea58cfb888a90590970f63d3a042a8ea3aaf2)) - -## [0.33.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.32.0...instrumentation-redis-4-v0.33.0) (2022-09-15) - - -### Features - -* add redis 4 connect span ([#1125](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1125)) ([dbf37fb](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/dbf37fb99b9168ebd0febc0da0ec21c0082e9967)) - -## [0.32.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.31.0...instrumentation-redis-4-v0.32.0) (2022-09-02) - - -### Features - -* update experimental Otel deps to ^0.31.0 ([#1096](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1096)) ([4c8843b](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/4c8843be14896d1159a622c07eb3a049401ccba1)) -* update experimental Otel deps to ^0.32.0 ([#1143](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1143)) ([6fb1911](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/6fb191139aed2ca763300dcf9adb51121a88f97e)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.31.0 to ^0.32.0 - -## [0.31.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.30.0...instrumentation-redis-4-v0.31.0) (2022-06-08) - - -### Features - -* update core dependencies stable ^1.3.1 experimental ^0.29.2 ([141b155](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/141b155e344980b51264e26b26c117b2113bcef6)) - - -### Dependencies - -* The following workspace dependencies were updated - * devDependencies - * @opentelemetry/contrib-test-utils bumped from ^0.30.0 to ^0.31.0 - -## [0.30.0](https://github.com/open-telemetry/opentelemetry-js-contrib/compare/instrumentation-redis-4-v0.29.0...instrumentation-redis-4-v0.30.0) (2022-05-25) - - -### Features - -* **instrumentation-redis:** add support for redis@^4.0.0 ([#982](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/982)) ([1da0216](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/1da0216180de694c15ec356d476f465811757ae4)) -* upstream mocha instrumentation testing plugin from ext-js [#621](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/621) ([#669](https://github.com/open-telemetry/opentelemetry-js-contrib/issues/669)) ([a5170c4](https://github.com/open-telemetry/opentelemetry-js-contrib/commit/a5170c494706a2bec3ba51e59966d0ca8a41d00e)) diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/LICENSE b/plugins/node/opentelemetry-instrumentation-redis-4/LICENSE deleted file mode 100644 index 261eeb9e9f..0000000000 --- a/plugins/node/opentelemetry-instrumentation-redis-4/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/plugins/node/opentelemetry-instrumentation-redis-4/README.md b/plugins/node/opentelemetry-instrumentation-redis-4/README.md index 85b0516974..80407ca373 100644 --- a/plugins/node/opentelemetry-instrumentation-redis-4/README.md +++ b/plugins/node/opentelemetry-instrumentation-redis-4/README.md @@ -1,105 +1,6 @@ -# OpenTelemetry redis Instrumentation for Node.js +# OpenTelemetry redis v4 Instrumentation for Node.js -> ⚠️ **DEPRECATED**: The support for `redis@4` instrumentation is now part of `@opentelemetry/instrumentation-redis`. please use it instead. +> ⚠️ **DEPRECATED**: The `@opentelemetry/instrumentation-redis-4` (note the "-4" suffix) instrumentation is deprecated. The support for `redis@4` instrumentation is now part of `@opentelemetry/instrumentation-redis` (as of v0.50.0). Please use it instead. -[![NPM Published Version][npm-img]][npm-url] -[![Apache License][license-image]][license-image] +The source code for this instrumentation has been moved to the "../opentelemetry-instrumentation-redis/" package. Use [the "instrumentation-redis-4-v0.49.0" git tag to see the package source code for the last release (v0.49.0)](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/instrumentation-redis-4-v0.49.0/plugins/node/opentelemetry-instrumentation-redis-4). -This module provides automatic instrumentation for the [`redis@^4.0.0`](https://github.com/NodeRedis/node_redis) module, which may be loaded using the [`@opentelemetry/sdk-trace-node`](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node) package and is included in the [`@opentelemetry/auto-instrumentations-node`](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) bundle. - -If total installation size is not constrained, it is recommended to use the [`@opentelemetry/auto-instrumentations-node`](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) bundle with [@opentelemetry/sdk-node](`https://www.npmjs.com/package/@opentelemetry/sdk-node`) for the most seamless instrumentation experience. - -Compatible with OpenTelemetry JS API and SDK `1.0+`. - -## Installation - -```bash -npm install --save @opentelemetry/instrumentation-redis-4 -``` - -### Supported Versions - -- [`redis`](https://www.npmjs.com/package/redis) versions `>=4.0.0` - -For versions `redis@^2.6.0` and `redis@^3.0.0`, please use `@opentelemetry/instrumentation-redis` - -## Usage - -OpenTelemetry Redis Instrumentation allows the user to automatically collect trace data and export them to the backend of choice, to give observability to distributed systems when working with [redis](https://www.npmjs.com/package/redis). - -To load a specific instrumentation (**redis** in this case), specify it in the registerInstrumentations' configuration - -```javascript -const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); -const { RedisInstrumentation } = require('@opentelemetry/instrumentation-redis-4'); -const { registerInstrumentations } = require('@opentelemetry/instrumentation'); - -const provider = new NodeTracerProvider(); -provider.register(); - -registerInstrumentations({ - instrumentations: [ - new RedisInstrumentation(), - ], -}) -``` - -### Redis Instrumentation Options - -Redis instrumentation has a few options available to choose from. You can set the following: - -| Options | Type | Description | -| ----------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -| `dbStatementSerializer` | `DbStatementSerializer` (function) | Redis instrumentation will serialize the command to the `db.statement` attribute using the specified function. | -| `responseHook` | `RedisResponseCustomAttributeFunction` (function) | Function for adding custom attributes on db response. Receives params: `span, cmdName, cmdArgs, response` | -| `requireParentSpan` | `boolean` | Require parent to create redis span, default when unset is false. | - -#### Custom `db.statement` Serializer - -The instrumentation serializes the command into a Span attribute called `db.statement`. The standard serialization format attempts to be as informative as possible while avoiding the export of potentially sensitive data. The number of serialized arguments depends on the specific command, see the configuration -list in `@opentelemetry/redis-common`. - -It is also possible to define a custom serialization function. The function -will receive the command name and arguments and must return a string. - -Here is a simple example to serialize the command name and all command arguments. -Notice that it might capture sensitive data and big payloads: - -```javascript -const { RedisInstrumentation } = require('@opentelemetry/instrumentation-redis'); -const redisInstrumentation = new RedisInstrumentation({ - dbStatementSerializer: function (cmdName, cmdArgs) { - return [cmdName, ...cmdArgs].join(" "); - }, -}); -``` - -## Semantic Conventions - -This package uses `@opentelemetry/semantic-conventions` version `1.22+`, which implements Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md) - -Attributes collected: - -| Attribute | Short Description | -| ---------------------- | ---------------------------------------------------------------------------- | -| `db.connection_string` | The connection string used to connect to the database (without credentials). | -| `db.statement` | The database statement being executed. | -| `db.system` | An identifier for the database management system (DBMS) product being used. | -| `net.peer.name` | Remote hostname or similar, see note below. | -| `net.peer.port` | Remote port number. | - -## Useful links - -- For more information on OpenTelemetry, visit: -- For more about OpenTelemetry JavaScript: -- For help or feedback on this project, join us in [GitHub Discussions][discussions-url] - -## License - -Apache 2.0 - See [LICENSE][license-url] for more information. - -[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions -[license-url]: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/LICENSE -[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat -[npm-url]: https://www.npmjs.com/package/@opentelemetry/instrumentation-redis-4 -[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Finstrumentation-redis-4.svg From aef400b46b2bdefaaf554d06b372869b935a2169 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 27 Jun 2025 14:41:17 -0700 Subject: [PATCH 25/28] drop some unneeded type casting --- .../test/v4/redis.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts index d4d6897ae8..b2646c3a74 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v4/redis.test.ts @@ -81,7 +81,7 @@ describe('redis v4', () => { beforeEach(async () => { client = createClient({ url: redisTestUrl, - }) as unknown as RedisClientType; + }); await context.with(suppressTracing(context.active()), async () => { await client.connect(); }); @@ -191,7 +191,7 @@ describe('redis v4', () => { it('produces a span', async () => { const newClient = createClient({ url: redisTestUrl, - }) as unknown as RedisClientType; + }); after(async () => { await newClient.disconnect(); @@ -224,7 +224,7 @@ describe('redis v4', () => { }`; const newClient = createClient({ url: redisURL, - }) as unknown as RedisClientType; + }); await assert.rejects(newClient.connect()); @@ -247,7 +247,7 @@ describe('redis v4', () => { }`; const newClient = createClient({ url: redisURL, - }) as unknown as RedisClientType; + }); await assert.rejects(newClient.connect()); @@ -274,7 +274,7 @@ describe('redis v4', () => { }?db=mydb`; const newClient = createClient({ url: redisURL, - }) as unknown as RedisClientType; + }); await assert.rejects(newClient.connect()); @@ -308,7 +308,7 @@ describe('redis v4', () => { DiagLogLevel.WARN ); - const newClient = createClient({ url: '' }) as unknown as RedisClientType; + const newClient = createClient({ url: '' }); try { await newClient.connect(); } catch (_err) { From de0d5bf5d3011d8d4f48f3e781249768219be964 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 27 Jun 2025 14:45:16 -0700 Subject: [PATCH 26/28] import cleanup from review feedback --- .../test/v2-v3/redis.test.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts b/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts index dd07c6e1e6..529399823f 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/test/v2-v3/redis.test.ts @@ -24,10 +24,6 @@ import { ROOT_CONTEXT, } from '@opentelemetry/api'; import * as testUtils from '@opentelemetry/contrib-test-utils'; -import { - getTestSpans, - registerInstrumentationTesting, -} from '@opentelemetry/contrib-test-utils'; import * as assert from 'assert'; import { RedisInstrumentation } from '../../src'; import { @@ -39,7 +35,7 @@ import { SEMATTRS_NET_PEER_PORT, } from '@opentelemetry/semantic-conventions'; -const instrumentation = registerInstrumentationTesting( +const instrumentation = testUtils.registerInstrumentationTesting( new RedisInstrumentation() ); @@ -184,9 +180,9 @@ describe('redis v2-v3', () => { context.with(trace.setSpan(context.active(), span), () => { operation.method((err, _result) => { assert.ifError(err); - assert.strictEqual(getTestSpans().length, 1); + assert.strictEqual(testUtils.getTestSpans().length, 1); span.end(); - const endedSpans = getTestSpans(); + const endedSpans = testUtils.getTestSpans(); assert.strictEqual(endedSpans.length, 2); assert.strictEqual( endedSpans[0].name, @@ -238,7 +234,7 @@ describe('redis v2-v3', () => { operation.method((err, _) => { assert.ifError(err); span.end(); - const endedSpans = getTestSpans(); + const endedSpans = testUtils.getTestSpans(); assert.strictEqual(endedSpans.length, 2); const expectedStatement = dbStatementSerializer( operation.command, @@ -276,7 +272,7 @@ describe('redis v2-v3', () => { it(`should apply responseHook for operation ${operation.description}`, done => { operation.method((err, reply) => { assert.ifError(err); - const endedSpans = getTestSpans(); + const endedSpans = testUtils.getTestSpans(); assert.strictEqual( endedSpans[0].attributes[dataFieldName], new String(reply).toString() @@ -305,7 +301,7 @@ describe('redis v2-v3', () => { it(`should not fail because of responseHook error for operation ${operation.description}`, done => { operation.method((err, _reply) => { assert.ifError(err); - const endedSpans = getTestSpans(); + const endedSpans = testUtils.getTestSpans(); assert.strictEqual(endedSpans.length, 1); done(); }); @@ -324,7 +320,7 @@ describe('redis v2-v3', () => { context.with(ROOT_CONTEXT, () => { operation.method((err, _) => { assert.ifError(err); - const endedSpans = getTestSpans(); + const endedSpans = testUtils.getTestSpans(); assert.strictEqual(endedSpans.length, 0); done(); }); @@ -336,7 +332,7 @@ describe('redis v2-v3', () => { context.with(trace.setSpan(context.active(), span), () => { operation.method((err, _) => { assert.ifError(err); - const endedSpans = getTestSpans(); + const endedSpans = testUtils.getTestSpans(); assert.strictEqual(endedSpans.length, 1); done(); }); From 3f925be36068690d28035c703c140a62f9ece95e Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 27 Jun 2025 14:47:29 -0700 Subject: [PATCH 27/28] can use more accurate "import type" here --- .../src/v2-v3/instrumentation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/instrumentation.ts index d9b37c4dd3..3e1cf09f19 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-redis/src/v2-v3/instrumentation.ts @@ -28,7 +28,7 @@ import { import { RedisInstrumentationConfig } from '../types'; /** @knipignore */ import { PACKAGE_NAME, PACKAGE_VERSION } from '../version'; -import { RedisCommand, RedisPluginClientTypes } from './internal-types'; +import type { RedisCommand, RedisPluginClientTypes } from './internal-types'; import { SpanKind, context, trace } from '@opentelemetry/api'; import { DBSYSTEMVALUES_REDIS, From ebcca8b3cac17ee3946bc3636c839b345135d418 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Wed, 2 Jul 2025 14:20:19 -0700 Subject: [PATCH 28/28] remove final references to the redis-4 instrumentation (from Amir's review) --- .github/component-label-map.yml | 6 ------ .github/component_owners.yml | 2 -- packages/opentelemetry-redis-common/README.md | 1 - 3 files changed, 9 deletions(-) diff --git a/.github/component-label-map.yml b/.github/component-label-map.yml index d5d893aae2..66e0743da3 100644 --- a/.github/component-label-map.yml +++ b/.github/component-label-map.yml @@ -210,12 +210,6 @@ pkg:instrumentation-redis: - plugins/node/opentelemetry-instrumentation-redis/** - packages/opentelemetry-test-utils/** - packages/opentelemetry-redis-common/** -pkg:instrumentation-redis-4: - - changed-files: - - any-glob-to-any-file: - - plugins/node/opentelemetry-instrumentation-redis-4/** - - packages/opentelemetry-test-utils/** - - packages/opentelemetry-redis-common/** pkg:instrumentation-restify: - changed-files: - any-glob-to-any-file: diff --git a/.github/component_owners.yml b/.github/component_owners.yml index e21c924fef..24dfd4ff9b 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -132,8 +132,6 @@ components: - maryliag plugins/node/opentelemetry-instrumentation-pino: - seemk - plugins/node/opentelemetry-instrumentation-redis-4: - - blumamir plugins/node/opentelemetry-instrumentation-redis: - blumamir plugins/node/opentelemetry-instrumentation-restify: [] diff --git a/packages/opentelemetry-redis-common/README.md b/packages/opentelemetry-redis-common/README.md index bb8de2d704..95ba85ac60 100644 --- a/packages/opentelemetry-redis-common/README.md +++ b/packages/opentelemetry-redis-common/README.md @@ -4,4 +4,3 @@ This is an internal utils package used for the different redis instrumentations: 1. ioredis 2. redis -3. redis-4