From 7761d30bef132b682fcc28fd9530d26570750493 Mon Sep 17 00:00:00 2001 From: Andrei Borza Date: Tue, 28 Jul 2026 12:14:49 +0200 Subject: [PATCH] ref(node): Remove vendored tedious instrumentation This instrumentation is dead code: the tedious 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/tedious/index.ts | 6 - .../tedious/vendored/instrumentation.ts | 214 ------------------ .../tracing/tedious/vendored/semconv.ts | 34 --- .../tracing/tedious/vendored/tedious-types.ts | 30 --- .../tracing/tedious/vendored/utils.ts | 47 ---- .../test/integrations/tracing/tedious.test.ts | 28 --- 6 files changed, 359 deletions(-) delete mode 100644 packages/node/src/integrations/tracing/tedious/index.ts delete mode 100644 packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts delete mode 100644 packages/node/src/integrations/tracing/tedious/vendored/semconv.ts delete mode 100644 packages/node/src/integrations/tracing/tedious/vendored/tedious-types.ts delete mode 100644 packages/node/src/integrations/tracing/tedious/vendored/utils.ts delete mode 100644 packages/node/test/integrations/tracing/tedious.test.ts diff --git a/packages/node/src/integrations/tracing/tedious/index.ts b/packages/node/src/integrations/tracing/tedious/index.ts deleted file mode 100644 index 521faf0cd9a8..000000000000 --- a/packages/node/src/integrations/tracing/tedious/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { TediousInstrumentation } from './vendored/instrumentation'; -import { generateInstrumentOnce } from '../../../otel/instrument'; - -const INTEGRATION_NAME = 'Tedious' as const; - -export const instrumentTedious = generateInstrumentOnce(INTEGRATION_NAME, () => new TediousInstrumentation({})); diff --git a/packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts b/packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts deleted file mode 100644 index a4ae168e849d..000000000000 --- a/packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts +++ /dev/null @@ -1,214 +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-tedious - * - Upstream version: @opentelemetry/instrumentation-tedious@0.37.0 - * - Minor TypeScript strictness adjustments - * - Span creation migrated to the @sentry/core API; origin folded into span creation - */ - -import { EventEmitter } from 'events'; -import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; -import { InstrumentationBase, InstrumentationNodeModuleDefinition, isWrapped } from '@opentelemetry/instrumentation'; -import { - DB_NAME, - DB_STATEMENT, - DB_SYSTEM, - DB_USER, - NET_PEER_NAME, - NET_PEER_PORT, - SENTRY_KIND, -} from '@sentry/conventions/attributes'; -import { DB_SYSTEM_VALUE_MSSQL, ATTR_DB_SQL_TABLE } from './semconv'; -import type * as tedious from './tedious-types'; -import { getSpanName, once } from './utils'; -import type { SpanAttributes } from '@sentry/core'; -import { - SDK_VERSION, - SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, - SPAN_STATUS_ERROR, - startInactiveSpan, - withActiveSpan, -} from '@sentry/core'; - -const PACKAGE_NAME = '@sentry/instrumentation-tedious'; - -const CURRENT_DATABASE = Symbol('opentelemetry.instrumentation-tedious.current-database'); - -const PATCHED_METHODS = ['callProcedure', 'execSql', 'execSqlBatch', 'execBulkLoad', 'prepare', 'execute']; - -type UnknownFunction = (...args: any[]) => any; -type ApproxConnection = EventEmitter & { - [CURRENT_DATABASE]: string; - config: any; -}; -type ApproxRequest = EventEmitter & { - sqlTextOrProcedure: string | undefined; - callback: any; - table: string | undefined; - parametersByName: any; -}; - -function setDatabase(this: ApproxConnection, databaseName: string) { - Object.defineProperty(this, CURRENT_DATABASE, { - value: databaseName, - writable: true, - }); -} - -export class TediousInstrumentation extends InstrumentationBase { - static readonly COMPONENT = 'tedious'; - - constructor(config: InstrumentationConfig = {}) { - super(PACKAGE_NAME, SDK_VERSION, config); - } - - protected init() { - return [ - new InstrumentationNodeModuleDefinition( - TediousInstrumentation.COMPONENT, - ['>=1.11.0 <20'], - (moduleExports: typeof tedious) => { - const ConnectionPrototype: any = moduleExports.Connection.prototype; - for (const method of PATCHED_METHODS) { - if (isWrapped(ConnectionPrototype[method])) { - this._unwrap(ConnectionPrototype, method); - } - this._wrap(ConnectionPrototype, method, this._patchQuery(method) as any); - } - - if (isWrapped(ConnectionPrototype.connect)) { - this._unwrap(ConnectionPrototype, 'connect'); - } - // oxlint-disable-next-line typescript/unbound-method - this._wrap(ConnectionPrototype, 'connect', this._patchConnect); - - return moduleExports; - }, - (moduleExports: typeof tedious) => { - if (moduleExports === undefined) return; - const ConnectionPrototype: any = moduleExports.Connection.prototype; - for (const method of PATCHED_METHODS) { - this._unwrap(ConnectionPrototype, method); - } - this._unwrap(ConnectionPrototype, 'connect'); - }, - ), - ]; - } - - private _patchConnect(original: UnknownFunction): UnknownFunction { - return function patchedConnect(this: ApproxConnection) { - setDatabase.call(this, this.config?.options?.database); - - // remove the listener first in case it's already added - this.removeListener('databaseChange', setDatabase); - this.on('databaseChange', setDatabase); - - this.once('end', () => { - this.removeListener('databaseChange', setDatabase); - }); - return original.apply(this, arguments as unknown as any[]); - }; - } - - private _patchQuery(operation: string) { - return (originalMethod: UnknownFunction): UnknownFunction => { - const thisPlugin = this; - - function patchedMethod(this: ApproxConnection, request: ApproxRequest) { - if (!(request instanceof EventEmitter)) { - thisPlugin._diag.warn(`Unexpected invocation of patched ${operation} method. Span not recorded`); - return originalMethod.apply(this, arguments as unknown as any[]); - } - let procCount = 0; - let statementCount = 0; - const incrementStatementCount = () => statementCount++; - const incrementProcCount = () => procCount++; - const databaseName = this[CURRENT_DATABASE]; - const sql = (request => { - // Required for <11.0.9 - if (request.sqlTextOrProcedure === 'sp_prepare' && request.parametersByName?.stmt?.value) { - return request.parametersByName.stmt.value; - } - return request.sqlTextOrProcedure; - })(request); - - const attributes: SpanAttributes = { - [SENTRY_KIND]: 'client', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.otel.tedious', - // eslint-disable-next-line typescript/no-deprecated - [DB_SYSTEM]: DB_SYSTEM_VALUE_MSSQL, - // eslint-disable-next-line typescript/no-deprecated - [DB_NAME]: databaseName, - // >=4 uses `authentication` object; older versions just userName and password pair - // eslint-disable-next-line typescript/no-deprecated - [DB_USER]: this.config?.userName ?? this.config?.authentication?.options?.userName, - // eslint-disable-next-line typescript/no-deprecated - [DB_STATEMENT]: sql, - // eslint-disable-next-line typescript/no-deprecated - [ATTR_DB_SQL_TABLE]: request.table, - // eslint-disable-next-line typescript/no-deprecated - [NET_PEER_NAME]: this.config?.server, - // eslint-disable-next-line typescript/no-deprecated - [NET_PEER_PORT]: this.config?.options?.port, - }; - const span = startInactiveSpan({ - name: getSpanName(operation, databaseName, sql, request.table), - attributes, - }); - - const endSpan = once((err?: any) => { - request.removeListener('done', incrementStatementCount); - request.removeListener('doneInProc', incrementStatementCount); - request.removeListener('doneProc', incrementProcCount); - request.removeListener('error', endSpan); - this.removeListener('end', endSpan); - - span.setAttribute('tedious.procedure_count', procCount); - span.setAttribute('tedious.statement_count', statementCount); - if (err) { - span.setStatus({ - code: SPAN_STATUS_ERROR, - message: err.message, - }); - // TODO(3290): set `error.type` attribute? - } - span.end(); - }); - - request.on('done', incrementStatementCount); - request.on('doneInProc', incrementStatementCount); - request.on('doneProc', incrementProcCount); - request.once('error', endSpan); - this.on('end', endSpan); - - if (typeof request.callback === 'function') { - thisPlugin._wrap(request, 'callback', thisPlugin._patchCallbackQuery(endSpan)); - } else { - thisPlugin._diag.error('Expected request.callback to be a function'); - } - - return withActiveSpan(span, () => originalMethod.apply(this, arguments as unknown as any[])); - } - - Object.defineProperty(patchedMethod, 'length', { - value: originalMethod.length, - writable: false, - }); - - return patchedMethod; - }; - } - - private _patchCallbackQuery(endSpan: Function) { - return (originalCallback: Function) => { - return function (this: any, err: Error | undefined | null, _rowCount?: number, _rows?: any) { - endSpan(err); - return originalCallback.apply(this, arguments); - }; - }; - } -} diff --git a/packages/node/src/integrations/tracing/tedious/vendored/semconv.ts b/packages/node/src/integrations/tracing/tedious/vendored/semconv.ts deleted file mode 100644 index da4fe8c816b4..000000000000 --- a/packages/node/src/integrations/tracing/tedious/vendored/semconv.ts +++ /dev/null @@ -1,34 +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-tedious - * - Upstream version: @opentelemetry/instrumentation-tedious@0.37.0 - */ - -/* - * This file contains a copy of unstable semantic convention definitions - * used by this package. - * @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv - */ - -/** - * Deprecated, use `db.collection.name` instead. - * - * @example "mytable" - * - * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`. - * - * @deprecated Replaced by `db.collection.name`, but only if not extracting the value from `db.query.text`. - */ -export const ATTR_DB_SQL_TABLE = 'db.sql.table' as const; - -/** - * Enum value "mssql" for attribute `db.system`. - * - * Microsoft SQL Server - * - * @experimental This enum value is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`. - */ -export const DB_SYSTEM_VALUE_MSSQL = 'mssql' as const; diff --git a/packages/node/src/integrations/tracing/tedious/vendored/tedious-types.ts b/packages/node/src/integrations/tracing/tedious/vendored/tedious-types.ts deleted file mode 100644 index f51ca322e363..000000000000 --- a/packages/node/src/integrations/tracing/tedious/vendored/tedious-types.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Simplified types inlined from tedious. - */ - -import { EventEmitter } from 'events'; - -export declare class Connection extends EventEmitter { - config: any; - connect(connectListener?: (err?: Error) => void): void; - execSql(request: Request): void; - [key: string]: any; -} - -export declare class Request extends EventEmitter { - sqlTextOrProcedure: string | undefined; - callback: any; - table: string | undefined; - parametersByName: any; - constructor( - sqlTextOrProcedure: string | undefined, - callback: (error: Error | null | undefined, rowCount?: number, rows?: any) => void, - ); - addParameter(name: string, type: any, value?: unknown, options?: any): void; - [key: string]: any; -} - -export declare const TYPES: { - VarBinary: any; - [key: string]: any; -}; diff --git a/packages/node/src/integrations/tracing/tedious/vendored/utils.ts b/packages/node/src/integrations/tracing/tedious/vendored/utils.ts deleted file mode 100644 index 0eb092e5fcff..000000000000 --- a/packages/node/src/integrations/tracing/tedious/vendored/utils.ts +++ /dev/null @@ -1,47 +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-tedious - * - Upstream version: @opentelemetry/instrumentation-tedious@0.37.0 - */ -/* eslint-disable */ - -/** - * The span name SHOULD be set to a low cardinality value - * representing the statement executed on the database. - * - * @returns Operation executed on Tedious Connection. Does not map to SQL statement in any way. - */ -export function getSpanName( - operation: string, - db: string | undefined, - sql: string | undefined, - bulkLoadTable: string | undefined, -): string { - if (operation === 'execBulkLoad' && bulkLoadTable && db) { - return `${operation} ${bulkLoadTable} ${db}`; - } - if (operation === 'callProcedure') { - // `sql` refers to procedure name with `callProcedure` - if (db) { - return `${operation} ${sql} ${db}`; - } - return `${operation} ${sql}`; - } - // do not use `sql` in general case because of high-cardinality - if (db) { - return `${operation} ${db}`; - } - return `${operation}`; -} - -export const once = (fn: Function) => { - let called = false; - return (...args: unknown[]) => { - if (called) return; - called = true; - return fn(...args); - }; -}; diff --git a/packages/node/test/integrations/tracing/tedious.test.ts b/packages/node/test/integrations/tracing/tedious.test.ts deleted file mode 100644 index bcf2f9261fb6..000000000000 --- a/packages/node/test/integrations/tracing/tedious.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { getSpanName } from '../../../src/integrations/tracing/tedious/vendored/utils'; - -describe('getSpanName', () => { - it('names execBulkLoad with the table and database', () => { - expect(getSpanName('execBulkLoad', 'master', undefined, 'test_bulk')).toBe('execBulkLoad test_bulk master'); - }); - - it('names callProcedure with the procedure and database', () => { - expect(getSpanName('callProcedure', 'master', '[dbo].[test_proced]', undefined)).toBe( - 'callProcedure [dbo].[test_proced] master', - ); - }); - - it('names callProcedure with the procedure when no database', () => { - expect(getSpanName('callProcedure', undefined, '[dbo].[test_proced]', undefined)).toBe( - 'callProcedure [dbo].[test_proced]', - ); - }); - - it('names a general operation with the database, not the sql', () => { - expect(getSpanName('execSql', 'master', 'SELECT GETDATE()', undefined)).toBe('execSql master'); - }); - - it('names a general operation with just the operation when no database', () => { - expect(getSpanName('execSql', undefined, 'SELECT GETDATE()', undefined)).toBe('execSql'); - }); -});