@sentry/node
Version:
Sentry Node SDK using OpenTelemetry for performance instrumentation
229 lines (200 loc) • 8.45 kB
JavaScript
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