UNPKG

@sentry/node

Version:

Sentry Node SDK using OpenTelemetry for performance instrumentation

229 lines (200 loc) • 8.45 kB
Object.defineProperty(exports, '__esModule', { value: true }); const core = require('@opentelemetry/core'); const instrumentation = require('@opentelemetry/instrumentation'); const core$1 = require('@sentry/core'); const utils = require('@sentry/utils'); const helpers = require('./helpers.js'); const supportedVersions = ['>=8.0.0 <11']; /** * Custom instrumentation for nestjs. * * This hooks into the @Injectable decorator, which is applied on class middleware, interceptors and guards. */ class SentryNestInstrumentation extends instrumentation.InstrumentationBase { static __initStatic() {this.COMPONENT = '@nestjs/common';} static __initStatic2() {this.COMMON_ATTRIBUTES = { component: SentryNestInstrumentation.COMPONENT, };} constructor(config = {}) { super('sentry-nestjs', utils.SDK_VERSION, config); } /** * Initializes the instrumentation by defining the modules to be patched. */ init() { const moduleDef = new instrumentation.InstrumentationNodeModuleDefinition(SentryNestInstrumentation.COMPONENT, supportedVersions); moduleDef.files.push( this._getInjectableFileInstrumentation(supportedVersions), this._getCatchFileInstrumentation(supportedVersions), ); return moduleDef; } /** * Wraps the @Injectable decorator. */ _getInjectableFileInstrumentation(versions) { return new instrumentation.InstrumentationNodeModuleFile( '@nestjs/common/decorators/core/injectable.decorator.js', versions, (moduleExports) => { if (core.isWrapped(moduleExports.Injectable)) { this._unwrap(moduleExports, 'Injectable'); } this._wrap(moduleExports, 'Injectable', this._createWrapInjectable()); return moduleExports; }, (moduleExports) => { this._unwrap(moduleExports, 'Injectable'); }, ); } /** * Wraps the @Catch decorator. */ _getCatchFileInstrumentation(versions) { return new instrumentation.InstrumentationNodeModuleFile( '@nestjs/common/decorators/core/catch.decorator.js', versions, (moduleExports) => { if (core.isWrapped(moduleExports.Catch)) { this._unwrap(moduleExports, 'Catch'); } this._wrap(moduleExports, 'Catch', this._createWrapCatch()); return moduleExports; }, (moduleExports) => { this._unwrap(moduleExports, 'Catch'); }, ); } /** * Creates a wrapper function for the @Injectable decorator. */ _createWrapInjectable() { // eslint-disable-next-line @typescript-eslint/no-explicit-any return function wrapInjectable(original) { return function wrappedInjectable(options) { return function (target) { // patch middleware if (typeof target.prototype.use === 'function' && !target.__SENTRY_INTERNAL__) { // patch only once if (helpers.isPatched(target)) { return original(options)(target); } target.prototype.use = new Proxy(target.prototype.use, { apply: (originalUse, thisArgUse, argsUse) => { const [req, res, next, ...args] = argsUse; const prevSpan = core$1.getActiveSpan(); return core$1.startSpanManual(helpers.getMiddlewareSpanOptions(target), (span) => { const nextProxy = new Proxy(next, { apply: (originalNext, thisArgNext, argsNext) => { span.end(); if (prevSpan) { return core$1.withActiveSpan(prevSpan, () => { return Reflect.apply(originalNext, thisArgNext, argsNext); }); } else { return Reflect.apply(originalNext, thisArgNext, argsNext); } }, }); return originalUse.apply(thisArgUse, [req, res, nextProxy, args]); }); }, }); } // patch guards if (typeof target.prototype.canActivate === 'function' && !target.__SENTRY_INTERNAL__) { // patch only once if (helpers.isPatched(target)) { return original(options)(target); } target.prototype.canActivate = new Proxy(target.prototype.canActivate, { apply: (originalCanActivate, thisArgCanActivate, argsCanActivate) => { return core$1.startSpan(helpers.getMiddlewareSpanOptions(target), () => { return originalCanActivate.apply(thisArgCanActivate, argsCanActivate); }); }, }); } // patch pipes if (typeof target.prototype.transform === 'function' && !target.__SENTRY_INTERNAL__) { if (helpers.isPatched(target)) { return original(options)(target); } target.prototype.transform = new Proxy(target.prototype.transform, { apply: (originalTransform, thisArgTransform, argsTransform) => { return core$1.startSpan(helpers.getMiddlewareSpanOptions(target), () => { return originalTransform.apply(thisArgTransform, argsTransform); }); }, }); } // patch interceptors if (typeof target.prototype.intercept === 'function' && !target.__SENTRY_INTERNAL__) { if (helpers.isPatched(target)) { return original(options)(target); } target.prototype.intercept = new Proxy(target.prototype.intercept, { apply: (originalIntercept, thisArgIntercept, argsIntercept) => { const [executionContext, next, args] = argsIntercept; const prevSpan = core$1.getActiveSpan(); return core$1.startSpanManual(helpers.getMiddlewareSpanOptions(target), (span) => { const nextProxy = new Proxy(next, { get: (thisArgNext, property, receiver) => { if (property === 'handle') { const originalHandle = Reflect.get(thisArgNext, property, receiver); // eslint-disable-next-line @typescript-eslint/no-explicit-any return (...args) => { span.end(); if (prevSpan) { return core$1.withActiveSpan(prevSpan, () => { return Reflect.apply(originalHandle, thisArgNext, args); }); } else { return Reflect.apply(originalHandle, thisArgNext, args); } }; } return Reflect.get(target, property, receiver); }, }); return originalIntercept.apply(thisArgIntercept, [executionContext, nextProxy, args]); }); }, }); } return original(options)(target); }; }; }; } /** * Creates a wrapper function for the @Catch decorator. Used to instrument exception filters. */ _createWrapCatch() { // eslint-disable-next-line @typescript-eslint/no-explicit-any return function wrapCatch(original) { return function wrappedCatch(...exceptions) { return function (target) { if (typeof target.prototype.catch === 'function' && !target.__SENTRY_INTERNAL__) { // patch only once if (helpers.isPatched(target)) { return original(...exceptions)(target); } target.prototype.catch = new Proxy(target.prototype.catch, { apply: (originalCatch, thisArgCatch, argsCatch) => { return core$1.startSpan(helpers.getMiddlewareSpanOptions(target), () => { return originalCatch.apply(thisArgCatch, argsCatch); }); }, }); } return original(...exceptions)(target); }; }; }; } } SentryNestInstrumentation.__initStatic(); SentryNestInstrumentation.__initStatic2(); exports.SentryNestInstrumentation = SentryNestInstrumentation; //# sourceMappingURL=sentry-nest-instrumentation.js.map