UNPKG

@opentelemetry/instrumentation-nestjs-core

Version:
169 lines 7.85 kB
"use strict"; /* * Copyright The OpenTelemetry Authors * SPDX-License-Identifier: Apache-2.0 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NestInstrumentation = void 0; const api = require("@opentelemetry/api"); const instrumentation_1 = require("@opentelemetry/instrumentation"); const semantic_conventions_1 = require("@opentelemetry/semantic-conventions"); /** @knipignore */ const version_1 = require("./version"); const semconv_1 = require("./semconv"); const enums_1 = require("./enums"); const supportedVersions = ['>=4.0.0 <12']; class NestInstrumentation extends instrumentation_1.InstrumentationBase { static COMPONENT = '@nestjs/core'; static COMMON_ATTRIBUTES = { component: NestInstrumentation.COMPONENT, }; _semconvStability; constructor(config = {}) { super(version_1.PACKAGE_NAME, version_1.PACKAGE_VERSION, config); this._semconvStability = (0, instrumentation_1.semconvStabilityFromStr)('http', process.env.OTEL_SEMCONV_STABILITY_OPT_IN); } init() { const module = new instrumentation_1.InstrumentationNodeModuleDefinition(NestInstrumentation.COMPONENT, supportedVersions); module.files.push(this.getNestFactoryFileInstrumentation(supportedVersions), this.getRouterExecutionContextFileInstrumentation(supportedVersions)); return module; } getNestFactoryFileInstrumentation(versions) { return new instrumentation_1.InstrumentationNodeModuleFile('@nestjs/core/nest-factory.js', versions, (NestFactoryStatic, moduleVersion) => { this.ensureWrapped(NestFactoryStatic.NestFactoryStatic.prototype, 'create', createWrapNestFactoryCreate(this.tracer, moduleVersion)); return NestFactoryStatic; }, (NestFactoryStatic) => { this._unwrap(NestFactoryStatic.NestFactoryStatic.prototype, 'create'); }); } getRouterExecutionContextFileInstrumentation(versions) { return new instrumentation_1.InstrumentationNodeModuleFile('@nestjs/core/router/router-execution-context.js', versions, (RouterExecutionContext, moduleVersion) => { this.ensureWrapped(RouterExecutionContext.RouterExecutionContext.prototype, 'create', createWrapCreateHandler(this.tracer, moduleVersion, this._semconvStability)); return RouterExecutionContext; }, (RouterExecutionContext) => { this._unwrap(RouterExecutionContext.RouterExecutionContext.prototype, 'create'); }); } ensureWrapped(obj, methodName, wrapper) { if ((0, instrumentation_1.isWrapped)(obj[methodName])) { this._unwrap(obj, methodName); } this._wrap(obj, methodName, wrapper); } } exports.NestInstrumentation = NestInstrumentation; function createWrapNestFactoryCreate(tracer, moduleVersion) { return function wrapCreate(original) { return function createWithTrace(nestModule /* serverOrOptions */ ) { const span = tracer.startSpan('Create Nest App', { attributes: { ...NestInstrumentation.COMMON_ATTRIBUTES, [enums_1.AttributeNames.TYPE]: enums_1.NestType.APP_CREATION, [enums_1.AttributeNames.VERSION]: moduleVersion, [enums_1.AttributeNames.MODULE]: nestModule.name, }, }); const spanContext = api.trace.setSpan(api.context.active(), span); return api.context.with(spanContext, async () => { try { return await original.apply(this, arguments); } catch (e) { throw addError(span, e); } finally { span.end(); } }); }; }; } function createWrapCreateHandler(tracer, moduleVersion, semconvStability) { return function wrapCreateHandler(original) { return function createHandlerWithTrace(instance, callback) { arguments[1] = createWrapHandler(tracer, moduleVersion, callback); const handler = original.apply(this, arguments); const callbackName = callback.name; const instanceName = instance.constructor && instance.constructor.name ? instance.constructor.name : 'UnnamedInstance'; const spanName = callbackName ? `${instanceName}.${callbackName}` : instanceName; return function (req, res, next) { const attributes = { ...NestInstrumentation.COMMON_ATTRIBUTES, [enums_1.AttributeNames.VERSION]: moduleVersion, [enums_1.AttributeNames.TYPE]: enums_1.NestType.REQUEST_CONTEXT, [semantic_conventions_1.ATTR_HTTP_ROUTE]: req.route?.path || req.routeOptions?.url || req.routerPath, [enums_1.AttributeNames.CONTROLLER]: instanceName, [enums_1.AttributeNames.CALLBACK]: callbackName, }; if (semconvStability & instrumentation_1.SemconvStability.OLD) { attributes[semconv_1.ATTR_HTTP_METHOD] = req.method; attributes[semconv_1.ATTR_HTTP_URL] = req.originalUrl || req.url; } if (semconvStability & instrumentation_1.SemconvStability.STABLE) { attributes[semantic_conventions_1.ATTR_HTTP_REQUEST_METHOD] = req.method; attributes[semantic_conventions_1.ATTR_URL_FULL] = req.originalUrl || req.url; } const span = tracer.startSpan(spanName, { attributes }); const spanContext = api.trace.setSpan(api.context.active(), span); return api.context.with(spanContext, async () => { try { return await handler.apply(this, arguments); } catch (e) { throw addError(span, e); } finally { span.end(); } }); }; }; }; } function createWrapHandler(tracer, moduleVersion, handler) { const spanName = handler.name || 'anonymous nest handler'; const options = { attributes: { ...NestInstrumentation.COMMON_ATTRIBUTES, [enums_1.AttributeNames.VERSION]: moduleVersion, [enums_1.AttributeNames.TYPE]: enums_1.NestType.REQUEST_HANDLER, [enums_1.AttributeNames.CALLBACK]: handler.name, }, }; const wrappedHandler = function () { const span = tracer.startSpan(spanName, options); const spanContext = api.trace.setSpan(api.context.active(), span); return api.context.with(spanContext, async () => { try { return await handler.apply(this, arguments); } catch (e) { throw addError(span, e); } finally { span.end(); } }); }; if (handler.name) { Object.defineProperty(wrappedHandler, 'name', { value: handler.name }); } // Get the current metadata and set onto the wrapper to ensure other decorators ( ie: NestJS EventPattern / RolesGuard ) // won't be affected by the use of this instrumentation Reflect.getMetadataKeys(handler).forEach(metadataKey => { Reflect.defineMetadata(metadataKey, Reflect.getMetadata(metadataKey, handler), wrappedHandler); }); return wrappedHandler; } const addError = (span, error) => { span.recordException(error); span.setStatus({ code: api.SpanStatusCode.ERROR, message: error.message }); return error; }; //# sourceMappingURL=instrumentation.js.map