UNPKG

autotel

Version:
188 lines (185 loc) 7.06 kB
'use strict'; var chunkHZ3FYBJG_cjs = require('./chunk-HZ3FYBJG.cjs'); var chunkESLWRGAG_cjs = require('./chunk-ESLWRGAG.cjs'); require('./chunk-YREV3LGG.cjs'); require('./chunk-JEQ2X3Z6.cjs'); var api = require('@opentelemetry/api'); function HttpInstrumented(options = {}) { const serviceName = options.serviceName || "http-client"; const slowRequestThresholdMs = options.slowRequestThresholdMs ?? 3e3; return function(target, _context) { return class extends target { // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(...args) { super(...args); const proto = target.prototype; const methodNames = Object.getOwnPropertyNames(proto).filter( (name) => name !== "constructor" && typeof proto[name] === "function" && !name.startsWith("_") ); for (const methodName of methodNames) { const originalMethod = proto[methodName]; if (originalMethod.constructor.name === "AsyncFunction" || originalMethod.toString().startsWith("async ")) { const wrappedMethod = async (...args2) => { const config = chunkESLWRGAG_cjs.getConfig(); const tracer = config.tracer; const url = options.urlExtractor ? options.urlExtractor(args2) : args2[0]; const method = options.methodExtractor ? options.methodExtractor(methodName, args2) : inferHttpMethod(methodName); const spanName = url ? `HTTP ${method} ${extractPath(url)}` : `HTTP ${method}`; return tracer.startActiveSpan(spanName, async (span) => { const startTime = performance.now(); try { span.setAttributes({ "http.method": method, "http.url": url || "unknown", "service.name": serviceName, "operation.name": `${serviceName}.${methodName}` }); if (url) { const urlObj = parseUrl(url); span.setAttributes({ "http.scheme": urlObj.protocol, "http.host": urlObj.host, "http.target": urlObj.path }); } if (options.attributesFromArgs) { span.setAttributes(options.attributesFromArgs(args2)); } const result = await originalMethod.apply(this, args2); const duration = performance.now() - startTime; const statusCode = extractStatusCode(result); if (statusCode) { span.setAttribute("http.status_code", statusCode); if (statusCode >= 400) { span.setStatus({ code: api.SpanStatusCode.ERROR, message: `HTTP ${statusCode}` }); } else { span.setStatus({ code: api.SpanStatusCode.OK }); } } else { span.setStatus({ code: api.SpanStatusCode.OK }); } span.setAttributes({ "http.duration_ms": duration }); if (duration > slowRequestThresholdMs) { span.setAttribute("http.slow_request", true); span.setAttribute( "http.slow_request_threshold_ms", slowRequestThresholdMs ); } return result; } catch (error) { const duration = performance.now() - startTime; span.setStatus({ code: api.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : "Unknown error" }); span.setAttributes({ "http.duration_ms": duration, "error.type": error instanceof Error ? error.constructor.name : "Unknown", "error.message": error instanceof Error ? error.message : "Unknown error" }); throw error; } finally { span.end(); } }); }; this[methodName] = wrappedMethod; } } } }; }; } async function traceHttpRequest(spanName, fn, attributes) { const config = chunkESLWRGAG_cjs.getConfig(); const tracer = config.tracer; return tracer.startActiveSpan(spanName, async (span) => { try { if (attributes) { span.setAttributes(attributes); } const result = await fn(); span.setStatus({ code: api.SpanStatusCode.OK }); return result; } catch (error) { span.setStatus({ code: api.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : "Unknown error" }); throw error; } finally { span.end(); } }); } function inferHttpMethod(methodName) { const lower = methodName.toLowerCase(); if (lower.includes("get") || lower.includes("fetch") || lower.includes("list")) return "GET"; if (lower.includes("post") || lower.includes("create")) return "POST"; if (lower.includes("put") || lower.includes("update")) return "PUT"; if (lower.includes("delete") || lower.includes("remove")) return "DELETE"; if (lower.includes("patch")) return "PATCH"; return "GET"; } function extractPath(url) { try { const urlObj = new URL(url); return urlObj.pathname; } catch { return url.split("?")[0] || url; } } function parseUrl(url) { try { const urlObj = new URL(url); return { protocol: urlObj.protocol.replace(":", ""), host: urlObj.host, path: urlObj.pathname + urlObj.search }; } catch { return { protocol: "http", host: "unknown", path: url }; } } function extractStatusCode(result) { if (result && typeof result === "object") { if ("status" in result && typeof result.status === "number") { return result.status; } if ("statusCode" in result && typeof result.statusCode === "number") { return result.statusCode; } } return void 0; } function injectTraceContext(headers = {}) { const currentContext = chunkHZ3FYBJG_cjs.getActiveContextWithBaggage(); api.propagation.inject(currentContext, headers); return headers; } function extractTraceContext(headers) { const carrier = {}; for (const [key, value] of Object.entries(headers)) { if (value !== void 0) { carrier[key] = Array.isArray(value) ? value[0] ?? "" : value; } } return api.propagation.extract(api.context.active(), carrier); } exports.HttpInstrumented = HttpInstrumented; exports.extractTraceContext = extractTraceContext; exports.injectTraceContext = injectTraceContext; exports.traceHttpRequest = traceHttpRequest; //# sourceMappingURL=http.cjs.map //# sourceMappingURL=http.cjs.map