UNPKG

autotel

Version:
1,185 lines (1,182 loc) 39.8 kB
import { setSpanName } from './chunk-DSMSIVTG.js'; import { runInOperationContext } from './chunk-SEO6NAQT.js'; import { createTraceContext, getActiveContextWithBaggage, getContextStorage, getEventQueue, enterOrRun } from './chunk-Z7VAOK5X.js'; import { getConfig as getConfig$1, getSdk } from './chunk-ZDPIWKWD.js'; import { AlwaysSampler, AUTOTEL_SAMPLING_TAIL_KEEP, AUTOTEL_SAMPLING_TAIL_EVALUATED } from './chunk-DPSA4QLA.js'; import { getConfig } from './chunk-J5QENANM.js'; import { trace as trace$1, SpanStatusCode, context, propagation } from '@opentelemetry/api'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; var inferenceCache = /* @__PURE__ */ new Map(); var MAX_CACHE_SIZE = 50; function captureStackTrace() { const originalStackTraceLimit = Error.stackTraceLimit; Error.stackTraceLimit = 10; const err = new Error("Stack trace capture"); const stack = err.stack || ""; Error.stackTraceLimit = originalStackTraceLimit; return stack; } function parseCallLocation(stack) { const lines = stack.split("\n"); let skippedExternalFrame = false; for (const line of lines) { if (line.includes("variable-name-inference.ts") || line.includes("variable-name-inference.js") || line.includes("functional.ts") || line.includes("functional.js")) { continue; } const match = line.match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/) || line.match(/^.*?([^:]+):(\d+):(\d+)/); if (match) { let filePath = match[1].trim(); if (filePath.startsWith("file://")) { try { filePath = fileURLToPath(filePath); } catch { continue; } } if (!skippedExternalFrame) { skippedExternalFrame = true; continue; } return { file: filePath, line: Number.parseInt(match[2], 10), column: Number.parseInt(match[3], 10) }; } } return void 0; } function readSourceLine(filePath, lineNumber) { try { if (typeof readFileSync !== "function") { return void 0; } const content = readFileSync(filePath, "utf8"); const lines = content.split("\n"); return lines[lineNumber - 1]; } catch { return void 0; } } function extractVariableName(sourceLine) { const trimmed = sourceLine.trim(); const patterns = [ // export const varName = anyFunction( /export\s+const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/, // const varName = anyFunction( /const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/, // export let varName = anyFunction( /export\s+let\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/, // let varName = anyFunction( /let\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/, // export var varName = anyFunction( /export\s+var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/, // var varName = anyFunction( /var\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/ ]; for (const pattern of patterns) { const match = trimmed.match(pattern); if (match && match[1]) { return match[1]; } } return void 0; } function cacheInference(key, value) { if (inferenceCache.size >= MAX_CACHE_SIZE) { const firstKey = inferenceCache.keys().next().value; if (firstKey) { inferenceCache.delete(firstKey); } } inferenceCache.set(key, value); } function inferVariableNameFromCallStack() { try { const stack = captureStackTrace(); const callLocation = parseCallLocation(stack); if (!callLocation) { return void 0; } const cacheKey = `${callLocation.file}:${callLocation.line}`; if (inferenceCache.has(cacheKey)) { return inferenceCache.get(cacheKey); } const sourceLine = readSourceLine(callLocation.file, callLocation.line); if (!sourceLine) { return void 0; } const variableName = extractVariableName(sourceLine); cacheInference(cacheKey, variableName); return variableName; } catch { return void 0; } } // src/functional.ts var FACTORY_NAME_HINTS = /* @__PURE__ */ new Set([ "ctx", "_ctx", "context", "tracecontext", "tracectx" ]); var TRACE_FACTORY_SET = /* @__PURE__ */ new WeakSet(); var SINGLE_LINE_COMMENT_REGEX = /\/\/.*$/gm; var MULTI_LINE_COMMENT_REGEX = /\/\*[\s\S]*?\*\//gm; var PARAM_TOKEN_SANITIZE_REGEX = new RegExp(String.raw`[{}\[\]\s]`, "g"); function markAsTraceFactory(fn) { TRACE_FACTORY_SET.add(fn); } function hasFactoryMark(fn) { return TRACE_FACTORY_SET.has(fn); } function sanitizeParameterToken(token) { const [firstToken] = token.split("="); return (firstToken ?? "").replaceAll(PARAM_TOKEN_SANITIZE_REGEX, "").trim(); } function getFirstParameterToken(fn) { let source = Function.prototype.toString.call(fn); source = source.replaceAll(MULTI_LINE_COMMENT_REGEX, "").replaceAll(SINGLE_LINE_COMMENT_REGEX, "").trim(); const arrowMatch = source.match( /^(?:async\s*)?(?:\(([^)]*)\)|([^=()]+))\s*=>/ ); if (arrowMatch) { const params = (arrowMatch[1] ?? arrowMatch[2] ?? "").split(","); const first = params[0]?.trim(); if (first) { return sanitizeParameterToken(first); } return null; } const functionMatch = source.match(/^[^(]*\(([^)]*)\)/); if (functionMatch) { const params = functionMatch[1]?.split(","); const first = params?.[0]?.trim(); if (first) { return sanitizeParameterToken(first); } } return null; } function looksLikeTraceFactory(fn) { if (hasFactoryMark(fn)) { return true; } if (fn.length === 0) { if (!isAsyncFunction(fn)) { try { const result = fn(); return typeof result === "function"; } catch { return false; } } return false; } const firstParam = getFirstParameterToken(fn); if (!firstParam) { return false; } const normalized = firstParam.toLowerCase(); if (FACTORY_NAME_HINTS.has(normalized) || normalized.startsWith("ctx") || normalized.startsWith("_ctx") || normalized.startsWith("trace") || normalized.endsWith("ctx") || // Match baseCtx, spanCtx, etc. normalized.includes("context")) { return true; } return false; } function isFactoryReturningFunction(fnWithCtx) { if (isAsyncFunction(fnWithCtx)) { return false; } try { const result = fnWithCtx(createDummyCtx()); return typeof result === "function"; } catch { return false; } } function isTraceFactoryFunction(fn) { if (typeof fn !== "function") { return false; } if (hasFactoryMark(fn)) { return true; } if (looksLikeTraceFactory(fn)) { markAsTraceFactory(fn); return true; } return false; } function ensureTraceFactory(fnOrFactory) { if (isTraceFactoryFunction(fnOrFactory)) { return fnOrFactory; } const plainFn = fnOrFactory; const factory = (ctx2) => { return plainFn; }; markAsTraceFactory(factory); return factory; } function wrapFactoryWithTracing(fnOrFactory, options, variableName) { const factory = ensureTraceFactory(fnOrFactory); const sampleFn = factory(createDummyCtx()); const innerFunctionName = inferFunctionName( sampleFn ); const callStackVariableName = innerFunctionName ? void 0 : inferVariableNameFromCallStack(); const factoryName = inferFunctionName(factory); const effectiveVariableName = variableName || innerFunctionName || callStackVariableName || factoryName; const useAsyncWrapper = isAsyncFunction(sampleFn); if (useAsyncWrapper) { return wrapWithTracing( factory, options, effectiveVariableName ); } return wrapWithTracingSync( factory, options, effectiveVariableName ); } var MAX_ERROR_MESSAGE_LENGTH = 500; function createDummyCtx() { return { traceId: "", spanId: "", correlationId: "", setAttribute: () => { }, setAttributes: () => { }, setStatus: () => { }, recordException: () => { }, addEvent: () => { }, addLink: () => { }, addLinks: () => { }, updateName: () => { }, isRecording: () => false, getBaggage: () => { }, setBaggage: () => "", deleteBaggage: () => { }, getAllBaggage: () => /* @__PURE__ */ new Map() }; } function isAsyncFunction(fn) { return typeof fn === "function" && fn.constructor?.name === "AsyncFunction"; } var INSTRUMENTED_SYMBOL = /* @__PURE__ */ Symbol.for("autotel.functional.instrumented"); function hasInstrumentationFlag(value) { return (typeof value === "function" || typeof value === "object") && value !== null && Boolean(value[INSTRUMENTED_SYMBOL]); } function truncateErrorMessage(message) { if (message.length <= MAX_ERROR_MESSAGE_LENGTH) { return message; } return `${message.slice(0, MAX_ERROR_MESSAGE_LENGTH)}... (truncated)`; } function inferFunctionName(fn) { const displayName = fn.displayName; if (displayName) { return displayName; } if (fn.name && fn.name !== "anonymous" && fn.name !== "") { return fn.name; } const source = Function.prototype.toString.call(fn); const match = source.match(/function\s+([^(\s]+)/); if (match && match[1] && match[1] !== "anonymous") { return match[1]; } return void 0; } function getSpanName(options, fn, variableName) { if (options.name) { return options.name; } let fnName = variableName || inferFunctionName(fn); fnName = fnName || "anonymous"; if (options.serviceName) { return `${options.serviceName}.${fnName}`; } if (fnName && fnName !== "anonymous") { return fnName; } return "unknown"; } function shouldSkip(key, fn, skip) { if (key.startsWith("_")) { return true; } if (!skip || skip.length === 0) { return false; } for (const rule of skip) { if (typeof rule === "string" && key === rule) { return true; } else if (rule instanceof RegExp && rule.test(key)) { return true; } else if (typeof rule === "function" && rule(key, fn)) { return true; } } return false; } function getCtxValue() { const activeSpan = trace$1.getActiveSpan(); if (!activeSpan) return null; return createTraceContext(activeSpan); } var ctx = new Proxy( {}, { get(_target, prop) { const ctxValue = getCtxValue(); if (!ctxValue) { return; } return ctxValue[prop]; }, has(_target, prop) { const ctxValue = getCtxValue(); if (!ctxValue) { return false; } return prop in ctxValue; }, ownKeys() { const ctxValue = getCtxValue(); if (!ctxValue) { return []; } return Object.keys(ctxValue); }, getOwnPropertyDescriptor(_target, prop) { const ctxValue = getCtxValue(); if (!ctxValue) { return; } return Object.getOwnPropertyDescriptor(ctxValue, prop); } } ); function wrapWithTracing(fnFactory, options, variableName) { if (hasInstrumentationFlag(fnFactory)) ; const config = getConfig(); const tracer = config.tracer; const meter = config.meter; const sampler = options.sampler || new AlwaysSampler(); const tempFn = fnFactory(createDummyCtx()); const spanName = getSpanName(options, tempFn, variableName); const callCounter = options.withMetrics ? meter.createCounter(`${spanName}.calls`, { description: `Call count for ${spanName}`, unit: "1" }) : void 0; const durationHistogram = options.withMetrics ? meter.createHistogram(`${spanName}.duration`, { description: `Duration for ${spanName}`, unit: "ms" }) : void 0; const wrappedFunction = async function wrappedFunction2(...args) { const samplingContext = { operationName: spanName, args, metadata: {} }; const shouldSample = sampler.shouldSample(samplingContext); const needsTailSampling = "needsTailSampling" in sampler && typeof sampler.needsTailSampling === "function" ? sampler.needsTailSampling() : false; if (!shouldSample && !needsTailSampling) { const fn = fnFactory(createDummyCtx()); return await fn.call(this, ...args); } const startTime = performance.now(); const isRootSpan = options.startNewRoot || trace$1.getActiveSpan() === void 0; const shouldAutoFlush = options.flushOnRootSpanEnd ?? getConfig$1()?.flushOnRootSpanEnd ?? true; const shouldAutoFlushSpans = getConfig$1()?.forceFlushOnShutdown ?? false; const flushIfNeeded = async () => { if (!shouldAutoFlush || !isRootSpan) return; try { const queue = getEventQueue(); if (queue && queue.size() > 0) { await queue.flush(); } if (shouldAutoFlushSpans) { const sdk = getSdk(); if (sdk) { try { const sdkAny = sdk; if (typeof sdkAny.getTracerProvider === "function") { const tracerProvider = sdkAny.getTracerProvider(); if (tracerProvider && typeof tracerProvider.forceFlush === "function") { await tracerProvider.forceFlush(); } } } catch { } } } } catch (error) { const initConfig = getConfig$1(); const logger = initConfig?.logger; if (logger?.error) { logger.error( { err: error instanceof Error ? error : void 0 }, `[autotel] Auto-flush failed${error instanceof Error ? "" : `: ${String(error)}`}` ); } } }; const spanOptions = {}; if (options.startNewRoot) { spanOptions.root = true; } if (options.spanKind !== void 0) { spanOptions.kind = options.spanKind; } const parentContext = getActiveContextWithBaggage(); return tracer.startActiveSpan( spanName, spanOptions, parentContext, async (span2) => { return runInOperationContext(spanName, async () => { let shouldKeepSpan = true; setSpanName(span2, spanName); const initialContext = context.active(); const contextStorage = getContextStorage(); if (!contextStorage.getStore()) { enterOrRun(contextStorage, initialContext); } const ctxValue = createTraceContext(span2); const fn = fnFactory(ctxValue); const argsAttributes = options.attributesFromArgs ? options.attributesFromArgs(args) : {}; const handleTailSampling = (success, duration, error) => { if (needsTailSampling && "shouldKeepTrace" in sampler && typeof sampler.shouldKeepTrace === "function") { shouldKeepSpan = sampler.shouldKeepTrace(samplingContext, { success, duration, error }); span2.setAttribute(AUTOTEL_SAMPLING_TAIL_KEEP, shouldKeepSpan); span2.setAttribute(AUTOTEL_SAMPLING_TAIL_EVALUATED, true); } }; const onSuccess = async (result) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "success" }); durationHistogram?.record(duration, { operation: spanName, status: "success" }); const resultAttributes = options.attributesFromResult ? options.attributesFromResult(result) : {}; span2.setStatus({ code: SpanStatusCode.OK }); span2.setAttributes({ ...argsAttributes, ...resultAttributes, "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": true }); handleTailSampling(true, duration); span2.end(); await flushIfNeeded(); return result; }; const onError = async (error) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "error" }); durationHistogram?.record(duration, { operation: spanName, status: "error" }); const errorMessage = error instanceof Error ? error.message : "Unknown error"; const truncatedMessage = truncateErrorMessage(errorMessage); span2.setStatus({ code: SpanStatusCode.ERROR, message: truncatedMessage }); span2.setAttributes({ ...argsAttributes, "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": false, error: true, "exception.type": error instanceof Error ? error.constructor.name : "Error", "exception.message": truncatedMessage }); if (error instanceof Error && error.stack) { span2.setAttribute( "exception.stack", error.stack.slice(0, MAX_ERROR_MESSAGE_LENGTH) ); } span2.recordException( error instanceof Error ? error : new Error(String(error)) ); handleTailSampling(false, duration, error); span2.end(); await flushIfNeeded(); throw error; }; try { callCounter?.add(1, { operation: spanName, status: "started" }); const executeWithContext = async () => { const currentContext = getActiveContextWithBaggage(); return context.with(currentContext, async () => { return fn.call(this, ...args); }); }; const result = await executeWithContext(); return await onSuccess(result); } catch (error) { await onError(error); throw error; } }); } ); }; wrappedFunction[INSTRUMENTED_SYMBOL] = true; Object.defineProperty(wrappedFunction, "name", { value: tempFn.name || "trace", configurable: true }); return wrappedFunction; } function wrapWithTracingSync(fnFactory, options, variableName) { if (hasInstrumentationFlag(fnFactory)) ; const config = getConfig(); const tracer = config.tracer; const meter = config.meter; const sampler = options.sampler || new AlwaysSampler(); const tempFn = fnFactory(createDummyCtx()); const spanName = getSpanName(options, tempFn, variableName); const callCounter = options.withMetrics ? meter.createCounter(`${spanName}.calls`, { description: `Call count for ${spanName}`, unit: "1" }) : void 0; const durationHistogram = options.withMetrics ? meter.createHistogram(`${spanName}.duration`, { description: `Duration for ${spanName}`, unit: "ms" }) : void 0; function wrappedFunction(...args) { const samplingContext = { operationName: spanName, args, metadata: {} }; const shouldSample = sampler.shouldSample(samplingContext); const needsTailSampling = "needsTailSampling" in sampler && typeof sampler.needsTailSampling === "function" ? sampler.needsTailSampling() : false; if (!shouldSample && !needsTailSampling) { const fn = fnFactory(createDummyCtx()); return fn.call(this, ...args); } const startTime = performance.now(); const isRootSpan = options.startNewRoot || trace$1.getActiveSpan() === void 0; const shouldAutoFlush = options.flushOnRootSpanEnd ?? getConfig$1()?.flushOnRootSpanEnd ?? true; const shouldAutoFlushSpans = getConfig$1()?.forceFlushOnShutdown ?? false; const flushIfNeeded = () => { if (!shouldAutoFlush || !isRootSpan) return; const queue = getEventQueue(); if (queue && queue.size() > 0) { void queue.flush().catch((error) => { const initConfig = getConfig$1(); const logger = initConfig?.logger; if (logger?.error) { logger.error( { err: error instanceof Error ? error : void 0 }, `[autotel] Auto-flush failed${error instanceof Error ? "" : `: ${String(error)}`}` ); } }); } if (shouldAutoFlushSpans) { const sdk = getSdk(); if (sdk) { try { const sdkAny = sdk; if (typeof sdkAny.getTracerProvider === "function") { const tracerProvider = sdkAny.getTracerProvider(); if (tracerProvider && typeof tracerProvider.forceFlush === "function") { void tracerProvider.forceFlush().catch((error) => { const initConfig = getConfig$1(); const logger = initConfig?.logger; if (logger?.error) { logger.error( { err: error instanceof Error ? error : void 0 }, `[autotel] Span flush failed${error instanceof Error ? "" : `: ${String(error)}`}` ); } }); } } } catch { } } } }; const spanOptions = {}; if (options.startNewRoot) { spanOptions.root = true; } if (options.spanKind !== void 0) { spanOptions.kind = options.spanKind; } const parentContext = getActiveContextWithBaggage(); return tracer.startActiveSpan( spanName, spanOptions, parentContext, (span2) => { return runInOperationContext(spanName, () => { let shouldKeepSpan = true; setSpanName(span2, spanName); const ctxValue = createTraceContext(span2); const fn = fnFactory(ctxValue); const argsAttributes = options.attributesFromArgs ? options.attributesFromArgs(args) : {}; const handleTailSampling = (success, duration, error) => { if (needsTailSampling && "shouldKeepTrace" in sampler && typeof sampler.shouldKeepTrace === "function") { shouldKeepSpan = sampler.shouldKeepTrace(samplingContext, { success, duration, error }); span2.setAttribute(AUTOTEL_SAMPLING_TAIL_KEEP, shouldKeepSpan); span2.setAttribute(AUTOTEL_SAMPLING_TAIL_EVALUATED, true); } }; const onSuccess = (result) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "success" }); durationHistogram?.record(duration, { operation: spanName, status: "success" }); const resultAttributes = options.attributesFromResult ? options.attributesFromResult(result) : {}; span2.setStatus({ code: SpanStatusCode.OK }); span2.setAttributes({ ...argsAttributes, ...resultAttributes, "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": true }); handleTailSampling(true, duration); span2.end(); void flushIfNeeded(); return result; }; const onError = (error) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "error" }); durationHistogram?.record(duration, { operation: spanName, status: "error" }); const errorMessage = error instanceof Error ? error.message : "Unknown error"; const truncatedMessage = truncateErrorMessage(errorMessage); span2.setStatus({ code: SpanStatusCode.ERROR, message: truncatedMessage }); span2.setAttributes({ ...argsAttributes, "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": false, error: true, "exception.type": error instanceof Error ? error.constructor.name : "Error", "exception.message": truncatedMessage }); span2.recordException( error instanceof Error ? error : new Error(String(error)) ); handleTailSampling(false, duration, error); span2.end(); void flushIfNeeded(); throw error; }; try { callCounter?.add(1, { operation: spanName, status: "started" }); const result = fn.call(this, ...args); if (result instanceof Promise) { return result.then(onSuccess, onError); } return onSuccess(result); } catch (error) { return onError(error); } }); } ); } wrappedFunction[INSTRUMENTED_SYMBOL] = true; Object.defineProperty(wrappedFunction, "name", { value: tempFn.name || "trace", configurable: true }); return wrappedFunction; } function executeImmediately(fn, options) { const config = getConfig(); const tracer = config.tracer; const meter = config.meter; const sampler = options.sampler || new AlwaysSampler(); const spanName = options.name || "anonymous"; const samplingContext = { operationName: spanName, args: [], metadata: {} }; const shouldSample = sampler.shouldSample(samplingContext); const needsTailSampling = "needsTailSampling" in sampler && typeof sampler.needsTailSampling === "function" ? sampler.needsTailSampling() : false; if (!shouldSample && !needsTailSampling) { return fn(createDummyCtx()); } const startTime = performance.now(); const isRootSpan = options.startNewRoot || trace$1.getActiveSpan() === void 0; const shouldAutoFlush = options.flushOnRootSpanEnd ?? getConfig$1()?.flushOnRootSpanEnd ?? true; const shouldAutoFlushSpans = getConfig$1()?.forceFlushOnShutdown ?? false; const callCounter = options.withMetrics ? meter.createCounter(`${spanName}.calls`, { description: `Call count for ${spanName}`, unit: "1" }) : void 0; const durationHistogram = options.withMetrics ? meter.createHistogram(`${spanName}.duration`, { description: `Duration for ${spanName}`, unit: "ms" }) : void 0; const flushIfNeeded = async () => { if (!shouldAutoFlush || !isRootSpan) return; try { const queue = getEventQueue(); if (queue && queue.size() > 0) { await queue.flush(); } if (shouldAutoFlushSpans) { const sdk = getSdk(); if (sdk) { try { const sdkAny = sdk; if (typeof sdkAny.getTracerProvider === "function") { const tracerProvider = sdkAny.getTracerProvider(); if (tracerProvider && typeof tracerProvider.forceFlush === "function") { await tracerProvider.forceFlush(); } } } catch { } } } } catch (error) { const initConfig = getConfig$1(); const logger = initConfig?.logger; if (logger?.error) { logger.error( { err: error instanceof Error ? error : void 0 }, `[autotel] Auto-flush failed${error instanceof Error ? "" : `: ${String(error)}`}` ); } } }; const spanOptions = {}; if (options.startNewRoot) { spanOptions.root = true; } if (options.spanKind !== void 0) { spanOptions.kind = options.spanKind; } const parentContext = getActiveContextWithBaggage(); return tracer.startActiveSpan( spanName, spanOptions, parentContext, (span2) => { return runInOperationContext(spanName, () => { let shouldKeepSpan = true; setSpanName(span2, spanName); const ctxValue = createTraceContext(span2); const handleTailSampling = (success, duration, error) => { if (needsTailSampling && "shouldKeepTrace" in sampler && typeof sampler.shouldKeepTrace === "function") { shouldKeepSpan = sampler.shouldKeepTrace(samplingContext, { success, duration, error }); span2.setAttribute(AUTOTEL_SAMPLING_TAIL_KEEP, shouldKeepSpan); span2.setAttribute(AUTOTEL_SAMPLING_TAIL_EVALUATED, true); } }; const onSuccessSync = (result) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "success" }); durationHistogram?.record(duration, { operation: spanName, status: "success" }); span2.setStatus({ code: SpanStatusCode.OK }); span2.setAttributes({ "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": true }); handleTailSampling(true, duration); span2.end(); void flushIfNeeded(); return result; }; const onErrorSync = (error) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "error" }); durationHistogram?.record(duration, { operation: spanName, status: "error" }); const errorMessage = error instanceof Error ? error.message : "Unknown error"; const truncatedMessage = truncateErrorMessage(errorMessage); span2.setStatus({ code: SpanStatusCode.ERROR, message: truncatedMessage }); span2.setAttributes({ "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": false, error: true, "exception.type": error instanceof Error ? error.constructor.name : "Error", "exception.message": truncatedMessage }); if (error instanceof Error && error.stack) { span2.setAttribute( "exception.stack", error.stack.slice(0, MAX_ERROR_MESSAGE_LENGTH) ); } span2.recordException( error instanceof Error ? error : new Error(String(error)) ); handleTailSampling(false, duration, error); span2.end(); void flushIfNeeded(); throw error; }; const onSuccessAsync = async (result) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "success" }); durationHistogram?.record(duration, { operation: spanName, status: "success" }); span2.setStatus({ code: SpanStatusCode.OK }); span2.setAttributes({ "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": true }); handleTailSampling(true, duration); span2.end(); await flushIfNeeded(); return result; }; const onErrorAsync = async (error) => { const duration = performance.now() - startTime; callCounter?.add(1, { operation: spanName, status: "error" }); durationHistogram?.record(duration, { operation: spanName, status: "error" }); const errorMessage = error instanceof Error ? error.message : "Unknown error"; const truncatedMessage = truncateErrorMessage(errorMessage); span2.setStatus({ code: SpanStatusCode.ERROR, message: truncatedMessage }); span2.setAttributes({ "operation.name": spanName, "code.function": spanName, "operation.duration": duration, "operation.success": false, error: true, "exception.type": error instanceof Error ? error.constructor.name : "Error", "exception.message": truncatedMessage }); if (error instanceof Error && error.stack) { span2.setAttribute( "exception.stack", error.stack.slice(0, MAX_ERROR_MESSAGE_LENGTH) ); } span2.recordException( error instanceof Error ? error : new Error(String(error)) ); handleTailSampling(false, duration, error); span2.end(); await flushIfNeeded(); throw error; }; try { callCounter?.add(1, { operation: spanName, status: "started" }); const result = fn(ctxValue); if (result instanceof Promise) { return result.then(onSuccessAsync, onErrorAsync); } return onSuccessSync(result); } catch (error) { return onErrorSync(error); } }); } ); } function trace(fnOrNameOrOptions, maybeFn) { if (typeof fnOrNameOrOptions === "function") { if (looksLikeTraceFactory(fnOrNameOrOptions) && !isFactoryReturningFunction( fnOrNameOrOptions )) { return executeImmediately( fnOrNameOrOptions, {} ); } return wrapFactoryWithTracing( fnOrNameOrOptions, {} ); } if (typeof fnOrNameOrOptions === "string") { if (!maybeFn) { throw new Error("trace(name, fn): fn is required"); } if (looksLikeTraceFactory(maybeFn) && !isFactoryReturningFunction(maybeFn)) { return executeImmediately( maybeFn, { name: fnOrNameOrOptions } ); } return wrapFactoryWithTracing( maybeFn, { name: fnOrNameOrOptions } ); } if (!maybeFn) { throw new Error("trace(options, fn): fn is required"); } if (looksLikeTraceFactory(maybeFn) && !isFactoryReturningFunction(maybeFn)) { return executeImmediately( maybeFn, fnOrNameOrOptions ); } return wrapFactoryWithTracing( maybeFn, fnOrNameOrOptions ); } function withTracing(options = {}) { return (fnFactory) => wrapFactoryWithTracing(fnFactory, options); } function instrument(options) { const { functions, ...tracingOptions } = options; const instrumented = {}; for (const key of Object.keys(functions)) { const typedKey = key; const fn = functions[typedKey]; if (!fn || typeof fn !== "function") { instrumented[typedKey] = fn; continue; } if (shouldSkip(key, fn, tracingOptions.skip)) { instrumented[typedKey] = fn; continue; } const fnOptions = { ...tracingOptions, ...tracingOptions.overrides?.[key], // If no explicit name, use key as function name name: tracingOptions.overrides?.[key]?.name }; const boundFn = fn.bind(functions); const fnFactory = (ctx2) => { return boundFn; }; instrumented[typedKey] = wrapFactoryWithTracing( fnFactory, fnOptions, key ); } return instrumented; } function span(nameOrOptions, fn) { const options = typeof nameOrOptions === "string" ? { name: nameOrOptions } : nameOrOptions; const config = getConfig(); const tracer = config.tracer; const { name, attributes } = options; const executeSpan = (span2) => { return runInOperationContext(name, () => { try { if (attributes) { for (const [key, value] of Object.entries(attributes)) { span2.setAttribute(key, value); } } const result2 = fn(span2); if (result2 instanceof Promise) { return result2.then((resolved) => { span2.setStatus({ code: SpanStatusCode.OK }); span2.end(); return resolved; }).catch((error) => { const errorMessage = error instanceof Error ? error.message.slice(0, MAX_ERROR_MESSAGE_LENGTH) : String(error).slice(0, MAX_ERROR_MESSAGE_LENGTH); span2.setAttribute("error.message", errorMessage); span2.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage }); span2.recordException( error instanceof Error ? error : new Error(String(error)) ); span2.end(); throw error; }); } else { span2.setStatus({ code: SpanStatusCode.OK }); span2.end(); return result2; } } catch (error) { const errorMessage = error instanceof Error ? error.message.slice(0, MAX_ERROR_MESSAGE_LENGTH) : String(error).slice(0, MAX_ERROR_MESSAGE_LENGTH); span2.setAttribute("error.message", errorMessage); span2.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage }); span2.recordException( error instanceof Error ? error : new Error(String(error)) ); span2.end(); throw error; } }); }; const parentContext = getActiveContextWithBaggage(); const result = tracer.startActiveSpan(name, {}, parentContext, executeSpan); if (result instanceof Promise) { return result; } return result; } async function withNewContext(options) { const { fn } = options; const config = getConfig(); const tracer = config.tracer; return tracer.startActiveSpan("root", { root: true }, async (span2) => { try { const result = await fn(); span2.setStatus({ code: SpanStatusCode.OK }); return result; } catch (error) { span2.recordException( error instanceof Error ? error : new Error(String(error)) ); span2.setStatus({ code: SpanStatusCode.ERROR }); throw error; } finally { span2.end(); } }); } function withBaggage(options) { const { baggage: baggageEntries, fn } = options; const currentContext = context.active(); let updatedBaggage = propagation.getBaggage(currentContext) ?? propagation.createBaggage(); for (const [key, value] of Object.entries(baggageEntries)) { updatedBaggage = updatedBaggage.setEntry(key, { value }); } const newContext = propagation.setBaggage(currentContext, updatedBaggage); const ctxStorage = getContextStorage(); const previousStored = ctxStorage.getStore(); const baggageEnrichedStored = previousStored ? { value: propagation.setBaggage(previousStored.value, updatedBaggage) } : { value: newContext }; const result = previousStored ? ctxStorage.run(baggageEnrichedStored, () => context.with(newContext, fn)) : context.with(newContext, fn); if (result instanceof Promise) { return result.then( (value) => { if (previousStored) { return ctxStorage.run(previousStored, () => value); } return value; }, (error) => { if (previousStored) { return ctxStorage.run(previousStored, () => { throw error; }); } throw error; } ); } return result; } export { ctx, instrument, span, trace, withBaggage, withNewContext, withTracing }; //# sourceMappingURL=chunk-S4S4AINO.js.map //# sourceMappingURL=chunk-S4S4AINO.js.map