{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Attributes } from '@opentelemetry/api';\nimport {\n ATTR_DB_CONNECTION_STRING,\n ATTR_DB_NAME,\n ATTR_DB_USER,\n ATTR_NET_PEER_NAME,\n ATTR_NET_PEER_PORT,\n} from './semconv';\nimport type * as mysqlTypes from 'mysql2';\nimport { MySQL2InstrumentationQueryMaskingHook } from './types';\nimport { SemconvStability } from '@opentelemetry/instrumentation';\nimport {\n ATTR_DB_NAMESPACE,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n} from '@opentelemetry/semantic-conventions';\n\ntype formatType = typeof mysqlTypes.format;\n\n/*\n Following types declare an expectation on mysql2 types and define a subset we\n use in the instrumentation of the types actually defined in mysql2 package\n\n We need to import them here so that the installing party of the instrumentation\n doesn't have to absolutely install the mysql2 package as well - specially\n important for auto-loaders and meta-packages.\n*/\ninterface QueryOptions {\n sql: string;\n values?: any | any[] | { [param: string]: any };\n}\n\ninterface Query {\n sql: string;\n}\n\ninterface Config {\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n connectionConfig?: Config;\n}\n\n/**\n * Get an Attributes map from a mysql connection config object\n *\n * @param config ConnectionConfig\n */\nexport function getConnectionAttributes(\n config: Config,\n dbSemconvStability: SemconvStability,\n netSemconvStability: SemconvStability\n): Attributes {\n const { host, port, database, user } = getConfig(config);\n\n const attrs: Attributes = {};\n if (dbSemconvStability & SemconvStability.OLD) {\n attrs[ATTR_DB_CONNECTION_STRING] = getJDBCString(host, port, database);\n attrs[ATTR_DB_NAME] = database;\n attrs[ATTR_DB_USER] = user;\n }\n if (dbSemconvStability & SemconvStability.STABLE) {\n attrs[ATTR_DB_NAMESPACE] = database;\n }\n\n const portNumber = parseInt(port, 10);\n if (netSemconvStability & SemconvStability.OLD) {\n attrs[ATTR_NET_PEER_NAME] = host;\n if (!isNaN(portNumber)) {\n attrs[ATTR_NET_PEER_PORT] = portNumber;\n }\n }\n if (netSemconvStability & SemconvStability.STABLE) {\n attrs[ATTR_SERVER_ADDRESS] = host;\n if (!isNaN(portNumber)) {\n attrs[ATTR_SERVER_PORT] = portNumber;\n }\n }\n\n return attrs;\n}\n\nfunction getConfig(config: any) {\n const { host, port, database, user } =\n (config && config.connectionConfig) || config || {};\n return { host, port, database, user };\n}\n\nfunction getJDBCString(\n host: string | undefined,\n port: number | undefined,\n database: string | undefined\n) {\n let jdbcString = `jdbc:mysql://${host || 'localhost'}`;\n\n if (typeof port === 'number') {\n jdbcString += `:${port}`;\n }\n\n if (typeof database === 'string') {\n jdbcString += `/${database}`;\n }\n\n return jdbcString;\n}\n\n/**\n * Conjures up the value for the db.query.text attribute by formatting a SQL query.\n */\nexport function getQueryText(\n query: string | Query | QueryOptions,\n format?: formatType,\n values?: any[],\n maskStatement = false,\n maskStatementHook: MySQL2InstrumentationQueryMaskingHook = defaultMaskingHook\n): string {\n const [querySql, queryValues] =\n typeof query === 'string'\n ? [query, values]\n : [query.sql, hasValues(query) ? values || query.values : values];\n try {\n if (maskStatement) {\n return maskStatementHook(querySql);\n } else if (format && queryValues) {\n return format(querySql, queryValues);\n } else {\n return querySql;\n }\n } catch (e) {\n return 'Could not determine the query due to an error in masking or formatting';\n }\n}\n\n/**\n * Replaces numeric values and quoted strings in the query with placeholders ('?').\n *\n * - `\\b\\d+\\b`: Matches whole numbers (integers) and replaces them with '?'.\n * - `([\"'])(?:(?=(\\\\?))\\2.)*?\\1`:\n * - Matches quoted strings (both single `'` and double `\"` quotes).\n * - Uses a lookahead `(?=(\\\\?))` to detect an optional backslash without consuming it immediately.\n * - Captures the optional backslash `\\2` and ensures escaped quotes inside the string are handled correctly.\n * - Ensures that only complete quoted strings are replaced with '?'.\n *\n * This prevents accidental replacement of escaped quotes within strings and ensures that the\n * query structure remains intact while masking sensitive data.\n */\nfunction defaultMaskingHook(query: string): string {\n return query\n .replace(/\\b\\d+\\b/g, '?')\n .replace(/([\"'])(?:(?=(\\\\?))\\2.)*?\\1/g, '?');\n}\n\nfunction hasValues(obj: Query | QueryOptions): obj is QueryOptions {\n return 'values' in obj;\n}\n\n/**\n * The span name SHOULD be set to a low cardinality value\n * representing the statement executed on the database.\n *\n * @returns SQL statement without variable arguments or SQL verb\n */\nexport function getSpanName(query: string | Query | QueryOptions): string {\n const rawQuery = typeof query === 'object' ? query.sql : query;\n // Extract the SQL verb\n const firstSpace = rawQuery?.indexOf(' ');\n if (typeof firstSpace === 'number' && firstSpace !== -1) {\n return rawQuery?.substring(0, firstSpace);\n }\n return rawQuery;\n}\n\nexport const once = (fn: Function) => {\n let called = false;\n return (...args: unknown[]) => {\n if (called) return;\n called = true;\n return fn(...args);\n };\n};\n\nexport function getConnectionPrototypeToInstrument(connection: any) {\n const connectionPrototype = connection.prototype;\n const basePrototype = Object.getPrototypeOf(connectionPrototype);\n\n // mysql2@3.11.5 included a refactoring, where most code was moved out of the `Connection` class and into a shared base\n // so we need to instrument that instead, see https://github.com/sidorares/node-mysql2/pull/3081\n // This checks if the functions we're instrumenting are there on the base - we cannot use the presence of a base\n // prototype since EventEmitter is the base for mysql2@<=3.11.4\n if (\n typeof basePrototype?.query === 'function' &&\n typeof basePrototype?.execute === 'function'\n ) {\n return basePrototype;\n }\n\n // otherwise instrument the connection directly.\n return connectionPrototype;\n}\n"]}