UNPKG

nestjs-otel

Version:
85 lines (84 loc) 3.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Span = Span; const api_1 = require("@opentelemetry/api"); const opentelemetry_constants_1 = require("../../opentelemetry.constants"); const opentelemetry_utils_1 = require("../../opentelemetry.utils"); const recordException = (span, error) => { span.recordException(error); span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message }); }; const handleOnResult = (span, onResult, result) => { if (onResult) { try { const attrs = onResult(result); if (attrs?.attributes) { span.setAttributes(attrs.attributes); } } catch (error) { recordException(span, error); } } }; function Span(nameOrOptions, maybeOptions) { return (target, propertyKey, propertyDescriptor) => { let name; let options; if (typeof nameOrOptions === "string") { name = nameOrOptions; options = maybeOptions ?? {}; } else { name = `${target.constructor.name}.${String(propertyKey)}`; options = nameOrOptions ?? {}; } const originalFunction = propertyDescriptor.value; if (typeof originalFunction !== "function") { throw new Error(`The @Span decorator can be only used on functions, but ${propertyKey.toString()} is not a function.`); } const wrappedFunction = function PropertyDescriptor(...args) { const tracer = api_1.trace.getTracer(opentelemetry_constants_1.OTEL_TRACER_NAME); const spanOptions = typeof options === "function" ? options(...args) : options; const { onResult, ...otelOptions } = spanOptions || {}; return tracer.startActiveSpan(name, otelOptions, (span) => { try { const result = originalFunction.apply(this, args); if (result && typeof result.then === "function" && typeof result.catch === "function") { return result .then((res) => { handleOnResult(span, onResult, res); return res; }) .catch((error) => { recordException(span, error); // Throw error to propagate it further throw error; }) .finally(() => { span.end(); }); } handleOnResult(span, onResult, result); span.end(); return result; } catch (error) { recordException(span, error); span.end(); // Throw error to propagate it further throw error; } }); }; // Wrap the original function in a proxy to ensure that the function name is preserved. // This should also preserve parameters for OpenAPI and other libraries // that rely on the function name as metadata key. propertyDescriptor.value = new Proxy(originalFunction, { apply: (_, thisArg, args) => wrappedFunction.apply(thisArg, args), }); (0, opentelemetry_utils_1.copyMetadataFromFunctionToFunction)(originalFunction, propertyDescriptor.value); }; }