From 3a4df2342995afee9af26d9d115073fdce6e0ddf Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Tue, 28 Jul 2026 12:14:33 +0200 Subject: [PATCH] ref(node): Remove vendored MongoDB instrumentation This instrumentation is dead code: the MongoDB integration is provided by the channel-based implementation in `@sentry/server-utils` (default since #22501), and the vendored OpenTelemetry instrumentation here is no longer wired up. Ref: #22346 Co-Authored-By: Claude Opus 4.8 --- .../src/integrations/tracing/mongo/index.ts | 6 - .../tracing/mongo/vendored/instrumentation.ts | 159 ------------ .../tracing/mongo/vendored/internal-types.ts | 137 ---------- .../tracing/mongo/vendored/patches.ts | 238 ------------------ .../tracing/mongo/vendored/utils.ts | 67 ----- 5 files changed, 607 deletions(-) delete mode 100644 packages/node/src/integrations/tracing/mongo/index.ts delete mode 100644 packages/node/src/integrations/tracing/mongo/vendored/instrumentation.ts delete mode 100644 packages/node/src/integrations/tracing/mongo/vendored/internal-types.ts delete mode 100644 packages/node/src/integrations/tracing/mongo/vendored/patches.ts delete mode 100644 packages/node/src/integrations/tracing/mongo/vendored/utils.ts diff --git a/packages/node/src/integrations/tracing/mongo/index.ts b/packages/node/src/integrations/tracing/mongo/index.ts deleted file mode 100644 index 91a1a68ea548..000000000000 --- a/packages/node/src/integrations/tracing/mongo/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { MongoDBInstrumentation } from './vendored/instrumentation'; -import { generateInstrumentOnce } from '../../../otel/instrument'; - -const INTEGRATION_NAME = 'Mongo' as const; - -export const instrumentMongo = generateInstrumentOnce(INTEGRATION_NAME, () => new MongoDBInstrumentation()); diff --git a/packages/node/src/integrations/tracing/mongo/vendored/instrumentation.ts b/packages/node/src/integrations/tracing/mongo/vendored/instrumentation.ts deleted file mode 100644 index 292ff2222425..000000000000 --- a/packages/node/src/integrations/tracing/mongo/vendored/instrumentation.ts +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - * - * NOTICE from the Sentry authors: - * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/15ef7506553f631ea4181391e0c5725a56f0d082/packages/instrumentation-mongodb - * - Upstream version: @opentelemetry/instrumentation-mongodb@0.71.0 - * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs - * - Dropped the OTel connection-usage metrics (no Sentry MeterProvider consumes them) and the - * session/connect patches that existed only to feed them - * - Dropped the env-gated stable-semconv dual emission; only the (default) old semantic - * conventions are emitted, matching the previous default span output - */ - -import { InstrumentationBase, InstrumentationNodeModuleDefinition, isWrapped } from '@opentelemetry/instrumentation'; -import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; -import { SDK_VERSION } from '@sentry/core'; -import { InstrumentationNodeModuleFile } from '../../InstrumentationNodeModuleFile'; -import type { WireProtocolInternal } from './internal-types'; -import * as patches from './patches'; - -const PACKAGE_NAME = '@sentry/instrumentation-mongodb'; - -/** mongodb instrumentation plugin */ -export class MongoDBInstrumentation extends InstrumentationBase { - public constructor(config: InstrumentationConfig = {}) { - super(PACKAGE_NAME, SDK_VERSION, config); - } - - public init(): InstrumentationNodeModuleDefinition[] { - const { v3PatchConnection, v3UnpatchConnection } = this._getV3ConnectionPatches(); - - const { v4PatchConnectionCallback, v4PatchConnectionPromise, v4UnpatchConnection } = this._getV4ConnectionPatches(); - const { v4PatchConnectionPool, v4UnpatchConnectionPool } = this._getV4ConnectionPoolPatches(); - - return [ - new InstrumentationNodeModuleDefinition('mongodb', ['>=3.3.0 <4'], undefined, undefined, [ - new InstrumentationNodeModuleFile( - 'mongodb/lib/core/wireprotocol/index.js', - ['>=3.3.0 <4'], - v3PatchConnection, - v3UnpatchConnection, - ), - ]), - new InstrumentationNodeModuleDefinition('mongodb', ['>=4.0.0 <8'], undefined, undefined, [ - new InstrumentationNodeModuleFile( - 'mongodb/lib/cmap/connection.js', - ['>=4.0.0 <6.4'], - v4PatchConnectionCallback, - v4UnpatchConnection, - ), - new InstrumentationNodeModuleFile( - 'mongodb/lib/cmap/connection.js', - ['>=6.4.0 <8'], - v4PatchConnectionPromise, - v4UnpatchConnection, - ), - new InstrumentationNodeModuleFile( - 'mongodb/lib/cmap/connection_pool.js', - ['>=4.0.0 <6.4'], - v4PatchConnectionPool, - v4UnpatchConnectionPool, - ), - ]), - ]; - } - - private _getV3ConnectionPatches() { - return { - v3PatchConnection: (moduleExports: T) => { - // patch insert operation - if (isWrapped(moduleExports.insert)) { - this._unwrap(moduleExports, 'insert'); - } - this._wrap(moduleExports, 'insert', patches.getV3PatchOperation('insert')); - // patch remove operation - if (isWrapped(moduleExports.remove)) { - this._unwrap(moduleExports, 'remove'); - } - this._wrap(moduleExports, 'remove', patches.getV3PatchOperation('remove')); - // patch update operation - if (isWrapped(moduleExports.update)) { - this._unwrap(moduleExports, 'update'); - } - this._wrap(moduleExports, 'update', patches.getV3PatchOperation('update')); - // patch other command - if (isWrapped(moduleExports.command)) { - this._unwrap(moduleExports, 'command'); - } - this._wrap(moduleExports, 'command', patches.getV3PatchCommand()); - // patch query - if (isWrapped(moduleExports.query)) { - this._unwrap(moduleExports, 'query'); - } - this._wrap(moduleExports, 'query', patches.getV3PatchFind()); - // patch get more operation on cursor - if (isWrapped(moduleExports.getMore)) { - this._unwrap(moduleExports, 'getMore'); - } - this._wrap(moduleExports, 'getMore', patches.getV3PatchCursor()); - return moduleExports; - }, - v3UnpatchConnection: (moduleExports?: T) => { - if (moduleExports === undefined) return; - this._unwrap(moduleExports, 'insert'); - this._unwrap(moduleExports, 'remove'); - this._unwrap(moduleExports, 'update'); - this._unwrap(moduleExports, 'command'); - this._unwrap(moduleExports, 'query'); - this._unwrap(moduleExports, 'getMore'); - }, - }; - } - - private _getV4ConnectionPoolPatches() { - return { - v4PatchConnectionPool: (moduleExports: any) => { - const poolPrototype = moduleExports.ConnectionPool.prototype; - - if (isWrapped(poolPrototype.checkOut)) { - this._unwrap(poolPrototype, 'checkOut'); - } - - this._wrap(poolPrototype, 'checkOut', patches.getV4ConnectionPoolCheckOut()); - return moduleExports; - }, - v4UnpatchConnectionPool: (moduleExports?: any) => { - if (moduleExports === undefined) return; - - this._unwrap(moduleExports.ConnectionPool.prototype, 'checkOut'); - }, - }; - } - - private _getV4ConnectionPatches() { - return { - v4PatchConnectionCallback: (moduleExports: any) => { - if (isWrapped(moduleExports.Connection.prototype.command)) { - this._unwrap(moduleExports.Connection.prototype, 'command'); - } - - this._wrap(moduleExports.Connection.prototype, 'command', patches.getV4PatchCommandCallback()); - return moduleExports; - }, - v4PatchConnectionPromise: (moduleExports: any) => { - if (isWrapped(moduleExports.Connection.prototype.command)) { - this._unwrap(moduleExports.Connection.prototype, 'command'); - } - - this._wrap(moduleExports.Connection.prototype, 'command', patches.getV4PatchCommandPromise()); - return moduleExports; - }, - v4UnpatchConnection: (moduleExports?: any) => { - if (moduleExports === undefined) return; - this._unwrap(moduleExports.Connection.prototype, 'command'); - }, - }; - } -} diff --git a/packages/node/src/integrations/tracing/mongo/vendored/internal-types.ts b/packages/node/src/integrations/tracing/mongo/vendored/internal-types.ts deleted file mode 100644 index 3a192ffa11d6..000000000000 --- a/packages/node/src/integrations/tracing/mongo/vendored/internal-types.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - * - * NOTICE from the Sentry authors: - * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/15ef7506553f631ea4181391e0c5725a56f0d082/packages/instrumentation-mongodb - * - Upstream version: @opentelemetry/instrumentation-mongodb@0.71.0 - * - Trimmed to the driver-internal types actually used by the instrumentation - */ - -export type MongoInternalCommand = { - findandmodify: boolean; - createIndexes: boolean; - count: boolean; - aggregate: boolean; - ismaster: boolean; - indexes?: unknown[]; - query?: Record; - limit?: number; - q?: Record; - u?: Record; -}; - -export type CursorState = { cmd: MongoInternalCommand } & Record; - -// https://github.com/mongodb/node-mongodb-native/blob/3.6/lib/core/wireprotocol/index.js -export type WireProtocolInternal = { - insert: ( - server: MongoInternalTopology, - ns: string, - ops: unknown[], - options: unknown | Function, - callback?: Function, - ) => unknown; - update: ( - server: MongoInternalTopology, - ns: string, - ops: unknown[], - options: unknown | Function, - callback?: Function, - ) => unknown; - remove: ( - server: MongoInternalTopology, - ns: string, - ops: unknown[], - options: unknown | Function, - callback?: Function, - ) => unknown; - killCursors: (server: MongoInternalTopology, ns: string, cursorState: CursorState, callback: Function) => unknown; - getMore: ( - server: MongoInternalTopology, - ns: string, - cursorState: CursorState, - batchSize: number, - options: unknown | Function, - callback?: Function, - ) => unknown; - query: ( - server: MongoInternalTopology, - ns: string, - cmd: MongoInternalCommand, - cursorState: CursorState, - options: unknown | Function, - callback?: Function, - ) => unknown; - command: ( - server: MongoInternalTopology, - ns: string, - cmd: MongoInternalCommand, - options: unknown | Function, - callback?: Function, - ) => unknown; -}; - -// https://github.com/mongodb/node-mongodb-native/blob/3.6/lib/topologies/server.js#L172 -// https://github.com/mongodb/node-mongodb-native/blob/2.2/lib/server.js#L174 -export type MongoInternalTopology = { - s?: { - // those are for mongodb@3 - options?: { - host?: string; - port?: number; - servername?: string; - }; - // those are for mongodb@2 - host?: string; - port?: number; - }; - // mongodb@3 with useUnifiedTopology option - description?: { - address?: string; - }; -}; - -export enum MongodbCommandType { - CREATE_INDEXES = 'createIndexes', - FIND_AND_MODIFY = 'findAndModify', - IS_MASTER = 'isMaster', - COUNT = 'count', - AGGREGATE = 'aggregate', - UNKNOWN = 'unknown', -} - -// https://github.com/mongodb/js-bson/blob/main/src/bson.ts -export type Document = { - [key: string]: any; -}; - -// https://github.com/mongodb/node-mongodb-native/blob/v6.4.0/src/utils.ts#L281 -export interface MongodbNamespace { - db: string; - collection?: string; -} - -export type V4Connection = { - command: Function; - // From version 6.4.0 the method does not expect a callback and returns a promise - // https://github.com/mongodb/node-mongodb-native/blob/v6.4.2/src/cmap/connection.ts - commandPromise( - ns: MongodbNamespace, - cmd: Document, - options: undefined | unknown, - // From v6.6.0 we have this new param which is a constructor function - // https://github.com/mongodb/node-mongodb-native/blob/v6.6.0/src/cmap/connection.ts#L588 - responseType: undefined | unknown, - ): Promise; - // Earlier versions expect a callback param and return void - // https://github.com/mongodb/node-mongodb-native/blob/v4.2.2/src/cmap/connection.ts - commandCallback(ns: MongodbNamespace, cmd: Document, options: undefined | unknown, callback: any): void; -}; - -// https://github.com/mongodb/node-mongodb-native/blob/v4.2.2/src/cmap/connection_pool.ts -export type V4ConnectionPool = { - // Instrumentation just cares about carrying the async context so - // types of callback params are not needed - checkOut: (callback: (error: any, connection: any) => void) => void; -}; diff --git a/packages/node/src/integrations/tracing/mongo/vendored/patches.ts b/packages/node/src/integrations/tracing/mongo/vendored/patches.ts deleted file mode 100644 index ea29755c32d5..000000000000 --- a/packages/node/src/integrations/tracing/mongo/vendored/patches.ts +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - * - * NOTICE from the Sentry authors: - * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/15ef7506553f631ea4181391e0c5725a56f0d082/packages/instrumentation-mongodb - * - Upstream version: @opentelemetry/instrumentation-mongodb@0.71.0 - * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs - */ - -import { getActiveSpan, withActiveSpan } from '@sentry/core'; -import type { - CursorState, - MongodbNamespace, - MongoInternalCommand, - MongoInternalTopology, - V4Connection, - V4ConnectionPool, - WireProtocolInternal, -} from './internal-types'; -import { - getV3CommandOperation, - getV3SpanAttributes, - getV4SpanAttributes, - patchEnd, - shouldSkipInstrumentation, - startMongoSpan, -} from './utils'; - -/** Creates spans for v3 common operations (insert/update/remove). */ -export function getV3PatchOperation(operationName: 'insert' | 'update' | 'remove') { - return (original: WireProtocolInternal[typeof operationName]) => { - return function patchedServerCommand( - this: unknown, - server: MongoInternalTopology, - ns: string, - ops: unknown[], - options: unknown | Function, - callback?: Function, - ) { - const resultHandler = typeof options === 'function' ? options : callback; - if (shouldSkipInstrumentation() || typeof resultHandler !== 'function' || typeof ops !== 'object') { - if (typeof options === 'function') { - return original.call(this, server, ns, ops, options); - } else { - return original.call(this, server, ns, ops, options, callback); - } - } - - const span = startMongoSpan(getV3SpanAttributes(ns, server, ops[0] as any, operationName)); - - const patchedCallback = patchEnd(span, resultHandler); - // handle when options is the callback to send the correct number of args - if (typeof options === 'function') { - return original.call(this, server, ns, ops, patchedCallback); - } else { - return original.call(this, server, ns, ops, options, patchedCallback); - } - }; - }; -} - -/** Creates spans for the v3 command operation. */ -export function getV3PatchCommand() { - return (original: WireProtocolInternal['command']) => { - return function patchedServerCommand( - this: unknown, - server: MongoInternalTopology, - ns: string, - cmd: MongoInternalCommand, - options: unknown | Function, - callback?: Function, - ) { - const resultHandler = typeof options === 'function' ? options : callback; - - if (shouldSkipInstrumentation() || typeof resultHandler !== 'function' || typeof cmd !== 'object') { - if (typeof options === 'function') { - return original.call(this, server, ns, cmd, options); - } else { - return original.call(this, server, ns, cmd, options, callback); - } - } - - const operationName = getV3CommandOperation(cmd as unknown as Record); - const span = startMongoSpan(getV3SpanAttributes(ns, server, cmd, operationName)); - - const patchedCallback = patchEnd(span, resultHandler); - // handle when options is the callback to send the correct number of args - if (typeof options === 'function') { - return original.call(this, server, ns, cmd, patchedCallback); - } else { - return original.call(this, server, ns, cmd, options, patchedCallback); - } - }; - }; -} - -/** Creates spans for the v4 (<6.4) callback-style command operation. */ -export function getV4PatchCommandCallback() { - return (original: V4Connection['commandCallback']) => { - return function patchedV4ServerCommand( - this: any, - ns: MongodbNamespace, - cmd: any, - options: undefined | unknown, - callback: any, - ) { - const resultHandler = callback; - const commandType = Object.keys(cmd)[0]; - - if (typeof cmd !== 'object' || cmd.ismaster || cmd.hello) { - return original.call(this, ns, cmd, options, callback); - } - - let span = undefined; - if (!shouldSkipInstrumentation()) { - span = startMongoSpan(getV4SpanAttributes(this, ns, cmd, commandType)); - } - const patchedCallback = patchEnd(span, resultHandler); - - return original.call(this, ns, cmd, options, patchedCallback); - }; - }; -} - -/** Creates spans for the v4 (>=6.4) promise-style command operation. */ -export function getV4PatchCommandPromise() { - return (original: V4Connection['commandPromise']) => { - return function patchedV4ServerCommand(this: any, ...args: Parameters) { - const [ns, cmd] = args; - const commandType = Object.keys(cmd)[0]; - const resultHandler = () => undefined; - - if (typeof cmd !== 'object' || cmd.ismaster || cmd.hello) { - return original.apply(this, args); - } - - let span = undefined; - if (!shouldSkipInstrumentation()) { - span = startMongoSpan(getV4SpanAttributes(this, ns, cmd, commandType)); - } - - const patchedCallback = patchEnd(span, resultHandler); - - const result = original.apply(this, args); - result.then( - (res: any) => patchedCallback(null, res), - (err: any) => patchedCallback(err), - ); - - return result; - }; - }; -} - -/** Creates spans for the v3 find operation. */ -export function getV3PatchFind() { - return (original: WireProtocolInternal['query']) => { - return function patchedServerCommand( - this: unknown, - server: MongoInternalTopology, - ns: string, - cmd: MongoInternalCommand, - cursorState: CursorState, - options: unknown | Function, - callback?: Function, - ) { - const resultHandler = typeof options === 'function' ? options : callback; - - if (shouldSkipInstrumentation() || typeof resultHandler !== 'function' || typeof cmd !== 'object') { - if (typeof options === 'function') { - return original.call(this, server, ns, cmd, cursorState, options); - } else { - return original.call(this, server, ns, cmd, cursorState, options, callback); - } - } - - const span = startMongoSpan(getV3SpanAttributes(ns, server, cmd, 'find')); - - const patchedCallback = patchEnd(span, resultHandler); - // handle when options is the callback to send the correct number of args - if (typeof options === 'function') { - return original.call(this, server, ns, cmd, cursorState, patchedCallback); - } else { - return original.call(this, server, ns, cmd, cursorState, options, patchedCallback); - } - }; - }; -} - -/** Creates spans for the v3 getMore (cursor) operation. */ -export function getV3PatchCursor() { - return (original: WireProtocolInternal['getMore']) => { - return function patchedServerCommand( - this: unknown, - server: MongoInternalTopology, - ns: string, - cursorState: CursorState, - batchSize: number, - options: unknown | Function, - callback?: Function, - ) { - const resultHandler = typeof options === 'function' ? options : callback; - - if (shouldSkipInstrumentation() || typeof resultHandler !== 'function') { - if (typeof options === 'function') { - return original.call(this, server, ns, cursorState, batchSize, options); - } else { - return original.call(this, server, ns, cursorState, batchSize, options, callback); - } - } - - const span = startMongoSpan(getV3SpanAttributes(ns, server, cursorState.cmd, 'getMore')); - - const patchedCallback = patchEnd(span, resultHandler); - // handle when options is the callback to send the correct number of args - if (typeof options === 'function') { - return original.call(this, server, ns, cursorState, batchSize, patchedCallback); - } else { - return original.call(this, server, ns, cursorState, batchSize, options, patchedCallback); - } - }; - }; -} - -// This patch will become unnecessary once https://jira.mongodb.org/browse/NODE-5639 is done. -export function getV4ConnectionPoolCheckOut() { - return (original: V4ConnectionPool['checkOut']) => { - return function patchedCheckout(this: unknown, callback: (error: any, connection: any) => void) { - // The pool runs the callback in a detached context, so re-activate the span that was - // active when `checkOut` was called — otherwise the pooled operation finds no parent. - const parentSpan = getActiveSpan(); - return original.call(this, function (this: unknown, ...args: [any, any]) { - return withActiveSpan(parentSpan ?? null, () => callback.apply(this, args)); - }); - }; - }; -} diff --git a/packages/node/src/integrations/tracing/mongo/vendored/utils.ts b/packages/node/src/integrations/tracing/mongo/vendored/utils.ts deleted file mode 100644 index 22876deae063..000000000000 --- a/packages/node/src/integrations/tracing/mongo/vendored/utils.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - * - * NOTICE from the Sentry authors: - * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/15ef7506553f631ea4181391e0c5725a56f0d082/packages/instrumentation-mongodb - * - Upstream version: @opentelemetry/instrumentation-mongodb@0.71.0 - * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs - * - The db/net attribute extraction, `db.statement` scrubbing and span - * builder are shared with the orchestrion mongodb integration in - * `@sentry/server-utils` so the two emit an identical span shape. - * Only the OTel-specific callback/context helpers below remain here. - */ - -import type { Span, SpanAttributes } from '@sentry/core'; -import { getActiveSpan, SPAN_STATUS_ERROR, withActiveSpan } from '@sentry/core'; -import { - getV3CommandOperation, - getV3SpanAttributes as sharedGetV3SpanAttributes, - getV4SpanAttributes as sharedGetV4SpanAttributes, - startMongoSpan, -} from '@sentry/server-utils'; - -const ORIGIN = 'auto.db.otel.mongo'; - -export { getV3CommandOperation, startMongoSpan }; - -/** Determine a span's attributes from the v4 connection context (OTel origin). */ -export function getV4SpanAttributes(connectionCtx: any, ns: any, command?: any, operation?: string): SpanAttributes { - return sharedGetV4SpanAttributes(connectionCtx, ns, command, operation, ORIGIN); -} - -/** Determine a span's attributes from the v3 topology (OTel origin). */ -export function getV3SpanAttributes(ns: string, topology: any, command?: any, operation?: string): SpanAttributes { - return sharedGetV3SpanAttributes(ns, topology, command, operation, ORIGIN); -} - -/** - * Wraps the result handler so it ends the span (with error status on failure) and runs the - * original callback re-activated under the parent span — mongodb loses the async context when - * it invokes the callback on a later tick. - */ -export function patchEnd(span: Span | undefined, resultHandler: Function): Function { - const parentSpan = getActiveSpan(); - let spanEnded = false; - - return function patchedEnd(this: {}, ...args: unknown[]) { - if (!spanEnded) { - spanEnded = true; - const error = args[0]; - if (span) { - if (error instanceof Error) { - span.setStatus({ code: SPAN_STATUS_ERROR, message: error.message }); - } - span.end(); - } - } - - return withActiveSpan(parentSpan ?? null, () => resultHandler.apply(this, args)); - }; -} - -// The instrumentation only creates spans when there is an active parent span, to avoid emitting -// orphaned mongodb spans. -export function shouldSkipInstrumentation(): boolean { - return !getActiveSpan(); -}