UNPKG

@sentry/node

Version:

Sentry Node SDK using OpenTelemetry for performance instrumentation

256 lines (237 loc) 9.43 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const api = require('@opentelemetry/api'); const core = require('@sentry/core'); const instrumentation = require('@opentelemetry/instrumentation'); const semanticConventions = require('@opentelemetry/semantic-conventions'); const redisCommon = require('./redis-common.js'); const semconv = require('./semconv.js'); /* * 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. * * NOTICE from the Sentry authors: * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/instrumentation-ioredis-v0.62.0/packages/instrumentation-ioredis * - Upstream version: @opentelemetry/instrumentation-ioredis@0.62.0 * - Minor TypeScript adjustments for this repository's compiler settings */ /* eslint-disable -- vendored @opentelemetry/instrumentation-ioredis */ const PACKAGE_NAME = '@opentelemetry/instrumentation-ioredis'; const PACKAGE_VERSION = '0.62.0'; // ---- utils ---- function endSpan(span, err) { if (err) { span.recordException(err); span.setStatus({ code: api.SpanStatusCode.ERROR, message: err.message, }); } span.end(); } // ---- IORedisInstrumentation ---- const DEFAULT_CONFIG = { requireParentSpan: true, }; class IORedisInstrumentation extends instrumentation.InstrumentationBase { constructor(config = {}) { super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); this._setSemconvStabilityFromEnv(); } _setSemconvStabilityFromEnv() { this._netSemconvStability = instrumentation.semconvStabilityFromStr('http', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']); this._dbSemconvStability = instrumentation.semconvStabilityFromStr('database', process.env['OTEL_SEMCONV_STABILITY_OPT_IN']); } setConfig(config = {}) { super.setConfig({ ...DEFAULT_CONFIG, ...config }); } init() { return [ new instrumentation.InstrumentationNodeModuleDefinition( 'ioredis', ['>=2.0.0 <6'], (module, moduleVersion) => { const moduleExports = module[Symbol.toStringTag] === 'Module' ? module.default // ESM : module; // CommonJS if (instrumentation.isWrapped(moduleExports.prototype.sendCommand)) { this._unwrap(moduleExports.prototype, 'sendCommand'); } this._wrap(moduleExports.prototype, 'sendCommand', this._patchSendCommand(moduleVersion)); if (instrumentation.isWrapped(moduleExports.prototype.connect)) { this._unwrap(moduleExports.prototype, 'connect'); } this._wrap(moduleExports.prototype, 'connect', this._patchConnection()); return module; }, (module) => { if (module === undefined) return; const moduleExports = module[Symbol.toStringTag] === 'Module' ? module.default // ESM : module; // CommonJS this._unwrap(moduleExports.prototype, 'sendCommand'); this._unwrap(moduleExports.prototype, 'connect'); }, ), ]; } _patchSendCommand(moduleVersion) { return (original) => { return this._traceSendCommand(original, moduleVersion); }; } _patchConnection() { return (original) => { return this._traceConnection(original); }; } _traceSendCommand(original, moduleVersion) { const instrumentation$1 = this; return function ( cmd) { if (arguments.length < 1 || typeof cmd !== 'object') { return original.apply(this, arguments); } const config = instrumentation$1.getConfig(); const dbStatementSerializer = config.dbStatementSerializer || redisCommon.defaultDbStatementSerializer; const hasNoParentSpan = api.trace.getSpan(api.context.active()) === undefined; if (config.requireParentSpan === true && hasNoParentSpan) { return original.apply(this, arguments); } const attributes = {}; const { host, port } = this.options; const dbQueryText = dbStatementSerializer(cmd.name, cmd.args); if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.OLD) { attributes[semconv.ATTR_DB_SYSTEM] = semconv.DB_SYSTEM_VALUE_REDIS; attributes[semconv.ATTR_DB_STATEMENT] = dbQueryText; attributes[semconv.ATTR_DB_CONNECTION_STRING] = `redis://${host}:${port}`; } if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.STABLE) { attributes[semanticConventions.ATTR_DB_SYSTEM_NAME] = semconv.DB_SYSTEM_NAME_VALUE_REDIS; attributes[semanticConventions.ATTR_DB_QUERY_TEXT] = dbQueryText; } if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.OLD) { attributes[semconv.ATTR_NET_PEER_NAME] = host; attributes[semconv.ATTR_NET_PEER_PORT] = port; } if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.STABLE) { attributes[semanticConventions.ATTR_SERVER_ADDRESS] = host; attributes[semanticConventions.ATTR_SERVER_PORT] = port; } attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis'; const span = instrumentation$1.tracer.startSpan(cmd.name, { kind: api.SpanKind.CLIENT, attributes, }); const { requestHook } = config; if (requestHook) { instrumentation.safeExecuteInTheMiddle( () => requestHook(span, { moduleVersion, cmdName: cmd.name, cmdArgs: cmd.args, }), (e) => { if (e) { api.diag.error('ioredis instrumentation: request hook failed', e); } }, true, ); } try { const result = original.apply(this, arguments); const origResolve = cmd.resolve; cmd.resolve = function (result) { instrumentation.safeExecuteInTheMiddle( () => config.responseHook?.(span, cmd.name, cmd.args, result), (e) => { if (e) { api.diag.error('ioredis instrumentation: response hook failed', e); } }, true, ); endSpan(span, null); origResolve(result); }; const origReject = cmd.reject; cmd.reject = function (err) { endSpan(span, err); origReject(err); }; return result; } catch (error) { endSpan(span, error ); throw error; } }; } _traceConnection(original) { const instrumentation$1 = this; return function () { const hasNoParentSpan = api.trace.getSpan(api.context.active()) === undefined; if (instrumentation$1.getConfig().requireParentSpan === true && hasNoParentSpan) { return original.apply(this, arguments); } const attributes = {}; const { host, port } = this.options; if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.OLD) { attributes[semconv.ATTR_DB_SYSTEM] = semconv.DB_SYSTEM_VALUE_REDIS; attributes[semconv.ATTR_DB_STATEMENT] = 'connect'; attributes[semconv.ATTR_DB_CONNECTION_STRING] = `redis://${host}:${port}`; } if (instrumentation$1._dbSemconvStability & instrumentation.SemconvStability.STABLE) { attributes[semanticConventions.ATTR_DB_SYSTEM_NAME] = semconv.DB_SYSTEM_NAME_VALUE_REDIS; attributes[semanticConventions.ATTR_DB_QUERY_TEXT] = 'connect'; } if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.OLD) { attributes[semconv.ATTR_NET_PEER_NAME] = host; attributes[semconv.ATTR_NET_PEER_PORT] = port; } if (instrumentation$1._netSemconvStability & instrumentation.SemconvStability.STABLE) { attributes[semanticConventions.ATTR_SERVER_ADDRESS] = host; attributes[semanticConventions.ATTR_SERVER_PORT] = port; } attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = 'auto.db.otel.redis'; const span = instrumentation$1.tracer.startSpan('connect', { kind: api.SpanKind.CLIENT, attributes, }); try { const result = original.apply(this, arguments); if (typeof result?.then === 'function') { return result.then( (value) => { endSpan(span, null); return value; }, (error) => { endSpan(span, error); return Promise.reject(error); }, ); } endSpan(span, null); return result; } catch (error) { endSpan(span, error ); throw error; } }; } } exports.IORedisInstrumentation = IORedisInstrumentation; //# sourceMappingURL=ioredis-instrumentation.js.map