autotel
Version:
Write Once, Observe Anywhere
188 lines (185 loc) • 7.06 kB
JavaScript
;
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