autotel
Version:
Write Once, Observe Anywhere
388 lines (383 loc) • 13.7 kB
JavaScript
export { createDrainPipeline } from './chunk-KFOHQK7X.js';
export { getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './chunk-RXFZKLRQ.js';
export { attrs, autoRedactPII, dbClient, httpClient, httpServer, identify, mergeAttrs, mergeServiceResource, request, safeSetAttributes, setDevice, setError, setException, setSession, setUser, validateAttribute } from './chunk-M4US3P4K.js';
export { httpRequestHeaderAttribute, httpResponseHeaderAttribute } from './chunk-7552UTQW.js';
export { HTTPAttributes, ServiceAttributes, URLAttributes } from './chunk-4A53YIAX.js';
export { parseError } from './chunk-J7VGRIAJ.js';
export { traceConsumer, traceProducer } from './chunk-GTD3NXOS.js';
export { BusinessBaggage, createSafeBaggageSchema } from './chunk-4IFSYQVX.js';
import { resetMetrics } from './chunk-7SAWIN74.js';
export { Metric, getMetrics, resetMetrics } from './chunk-7SAWIN74.js';
import './chunk-5ZN622AO.js';
export { createCounter, createHistogram, createObservableGauge, createUpDownCounter, getMeter } from './chunk-TQ5UWA7S.js';
export { traceDB, traceHTTP, traceLLM, traceMessaging } from './chunk-DGPUZ6TE.js';
import { getEventQueue, resetEventQueue } from './chunk-4PTCDOZY.js';
export { ctx, getEventQueue, instrument, span, trace, track, withBaggage, withNewContext, withTracing } from './chunk-4PTCDOZY.js';
export { createDeterministicTraceId, enrichWithTraceContext, finalizeSpan, flattenMetadata, getActiveContext, getActiveSpan, getTraceContext, getTracer, isTracing, resolveTraceUrl, runWithSpan } from './chunk-B3ZHLLMP.js';
import { resetEvents } from './chunk-WAB4CHBU.js';
export { Event, getEvents, resetEvents } from './chunk-WAB4CHBU.js';
import './chunk-LITNXTTT.js';
import './chunk-BZHG5IZ4.js';
export { getOperationContext, runInOperationContext } from './chunk-WD4RP6IV.js';
export { CORRELATION_ID_BAGGAGE_KEY, generateCorrelationId, getCorrelationId, getOrCreateCorrelationId, runWithCorrelationId, setCorrelationId, setCorrelationIdInBaggage } from './chunk-S4OFEXLA.js';
import { createTraceContext } from './chunk-BBBWDIYQ.js';
export { defineBaggageSchema } from './chunk-BBBWDIYQ.js';
import { getLogger, getSdk, _closeEmbeddedDevtools } from './chunk-EXOXDI5A.js';
export { BaggageSpanProcessor, createStringRedactor, init } from './chunk-EXOXDI5A.js';
import './chunk-RUD7KS4R.js';
import './chunk-XDKK53OL.js';
export { FilteringSpanProcessor } from './chunk-WGWSHJ2N.js';
export { NORMALIZER_PATTERNS, NORMALIZER_PRESETS, SpanNameNormalizingProcessor } from './chunk-GYR5K654.js';
export { AttributeRedactingProcessor, REDACTOR_PATTERNS, REDACTOR_PRESETS, createAttributeRedactor, createRedactedSpan } from './chunk-SNINLBEE.js';
import './chunk-6UQRVUN3.js';
export { formatDuration } from './chunk-3QXBFGKP.js';
import './chunk-33WTKH7X.js';
export { AUTOTEL_SAMPLING_TAIL_EVALUATED, AUTOTEL_SAMPLING_TAIL_KEEP, AdaptiveSampler, AlwaysSampler, NeverSampler, RandomSampler, UserIdSampler, createLinkFromHeaders, extractLinksFromBatch, resolveSamplingPreset, samplingPresets } from './chunk-VYA6QDNA.js';
import './chunk-B33XPEKY.js';
import './chunk-J5QENANM.js';
export { getAutotelTracer, getAutotelTracerProvider, setAutotelTracerProvider } from './chunk-HA2WBOGQ.js';
import './chunk-DGUM43GV.js';
import { AsyncLocalStorage } from 'async_hooks';
import { SpanStatusCode, trace } from '@opentelemetry/api';
export { ROOT_CONTEXT, SpanKind, SpanStatusCode, context, trace as otelTrace, propagation } from '@opentelemetry/api';
// src/shutdown.ts
async function flush(options) {
const timeout = options?.timeout ?? 2e3;
const forShutdown = options?.forShutdown ?? false;
const doFlush = async () => {
const eventsQueue = getEventQueue();
if (eventsQueue) {
if (forShutdown) {
await eventsQueue.shutdown();
} else {
await eventsQueue.flush();
}
}
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 {
}
}
};
let timeoutHandle;
try {
await Promise.race([
doFlush().finally(() => {
if (timeoutHandle) {
clearTimeout(timeoutHandle);
}
}),
new Promise((_, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error("Flush timeout")),
timeout
);
timeoutHandle.unref();
})
]);
} catch (error) {
if (timeoutHandle) {
clearTimeout(timeoutHandle);
}
const logger = getLogger();
logger.error(
{
err: error instanceof Error ? error : new Error(String(error))
},
"[autotel] Flush error"
);
throw error;
}
}
async function shutdown() {
const logger = getLogger();
let shutdownError = null;
try {
await flush({ forShutdown: true });
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
shutdownError = err;
logger.error(
{
err
},
"[autotel] Flush failed during shutdown, continuing cleanup"
);
}
try {
const sdk = getSdk();
if (sdk) {
await sdk.shutdown();
}
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
const isConnectionRefused = typeof error === "object" && error !== null && "code" in error && error.code === "ECONNREFUSED";
if (!isConnectionRefused) {
if (!shutdownError) {
shutdownError = err;
}
logger.error({ err }, "[autotel] SDK shutdown failed");
}
} finally {
await _closeEmbeddedDevtools();
const eventsQueue = getEventQueue();
if (eventsQueue && typeof eventsQueue.cleanup === "function") {
eventsQueue.cleanup();
}
resetEvents();
resetMetrics();
resetEventQueue();
}
if (shutdownError) {
throw shutdownError;
}
}
function registerShutdownHooks() {
if (typeof process === "undefined") return;
const signals = ["SIGTERM", "SIGINT"];
let shuttingDown = false;
for (const signal of signals) {
process.on(signal, async () => {
if (shuttingDown) return;
shuttingDown = true;
if (process.env.NODE_ENV !== "test") {
getLogger().info(
{},
`[autotel] Received ${signal}, flushing telemetry...`
);
}
try {
await shutdown();
} catch (error) {
getLogger().error(
{
err: error instanceof Error ? error : void 0
},
"[autotel] Error during shutdown"
);
} finally {
process.exit(0);
}
});
}
}
registerShutdownHooks();
// src/flatten-attributes.ts
function toAttributeValue(value) {
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
return value;
}
if (Array.isArray(value)) {
if (value.every((v) => typeof v === "string") || value.every((v) => typeof v === "number") || value.every((v) => typeof v === "boolean")) {
return value;
}
try {
return JSON.stringify(value);
} catch {
return "<serialization-failed>";
}
}
if (value instanceof Date) {
return value.toISOString();
}
if (value instanceof Error) {
return value.message;
}
return void 0;
}
function flattenToAttributes(fields, prefix = "") {
const out = {};
const seen = /* @__PURE__ */ new WeakSet();
function flatten(obj, currentPrefix) {
for (const [key, value] of Object.entries(obj)) {
if (value == null) continue;
const nextKey = currentPrefix ? `${currentPrefix}.${key}` : key;
const attr = toAttributeValue(value);
if (attr !== void 0) {
out[nextKey] = attr;
continue;
}
if (typeof value === "object" && value.constructor === Object) {
if (seen.has(value)) {
out[nextKey] = "<circular-reference>";
continue;
}
seen.add(value);
flatten(value, nextKey);
continue;
}
try {
out[nextKey] = JSON.stringify(value);
} catch {
out[nextKey] = "<serialization-failed>";
}
}
}
flatten(fields, prefix);
return out;
}
// src/structured-error.ts
function createStructuredError(input) {
const error = new Error(input.message, {
cause: input.cause
});
error.name = input.name ?? "StructuredError";
if (input.why !== void 0) error.why = input.why;
if (input.fix !== void 0) error.fix = input.fix;
if (input.link !== void 0) error.link = input.link;
if (input.code !== void 0) error.code = input.code;
if (input.status !== void 0) error.status = input.status;
if (input.details !== void 0) error.details = input.details;
error.toString = () => {
const lines = [`${error.name}: ${error.message}`];
if (error.why) lines.push(` Why: ${error.why}`);
if (error.fix) lines.push(` Fix: ${error.fix}`);
if (error.link) lines.push(` Link: ${error.link}`);
if (error.code !== void 0) lines.push(` Code: ${error.code}`);
if (error.status !== void 0) lines.push(` Status: ${error.status}`);
if (error.cause) lines.push(` Caused by: ${error.cause}`);
return lines.join("\n");
};
return error;
}
function getStructuredErrorAttributes(error) {
const structured = error;
const attributes = {
"error.type": error.name || "Error",
"error.message": error.message
};
if (error.stack) attributes["error.stack"] = error.stack;
if (structured.why) attributes["error.why"] = structured.why;
if (structured.fix) attributes["error.fix"] = structured.fix;
if (structured.link) attributes["error.link"] = structured.link;
if (structured.code !== void 0) {
attributes["error.code"] = typeof structured.code === "string" ? structured.code : String(structured.code);
}
if (structured.status !== void 0) {
attributes["error.status"] = structured.status;
}
if (structured.details) {
Object.assign(
attributes,
flattenToAttributes(structured.details, "error.details")
);
}
return attributes;
}
function recordStructuredError(ctx2, error) {
ctx2.recordException(error);
ctx2.setStatus({
code: SpanStatusCode.ERROR,
message: error.message
});
ctx2.setAttributes(getStructuredErrorAttributes(error));
}
// src/request-logger.ts
var requestContextStore = new AsyncLocalStorage();
function runWithRequestContext(ctx2, fn) {
return requestContextStore.run(ctx2, fn);
}
function resolveContext(ctx2) {
if (ctx2) return ctx2;
const stored = requestContextStore.getStore();
if (stored) return stored;
const span2 = trace.getActiveSpan();
if (!span2) {
throw new Error(
"[autotel] getRequestLogger() requires an active span or runWithRequestContext(). Wrap your handler with trace() or use runWithRequestContext()."
);
}
return createTraceContext(span2);
}
function getRequestLogger(ctx2, options) {
const activeContext = resolveContext(ctx2);
let contextState = {};
const addLogEvent = (level, message, fields) => {
const attrs2 = fields ? flattenToAttributes(fields) : void 0;
activeContext.addEvent(`log.${level}`, {
message,
...attrs2
});
};
return {
set(fields) {
contextState = {
...contextState,
...fields
};
activeContext.setAttributes(flattenToAttributes(fields));
},
info(message, fields) {
addLogEvent("info", message, fields);
if (fields) {
contextState = {
...contextState,
...fields
};
activeContext.setAttributes(flattenToAttributes(fields));
}
},
warn(message, fields) {
addLogEvent("warn", message, fields);
activeContext.setAttribute("autotel.log.level", "warn");
if (fields) {
contextState = {
...contextState,
...fields
};
activeContext.setAttributes(flattenToAttributes(fields));
}
},
error(error, fields) {
const err = typeof error === "string" ? new Error(error) : error;
recordStructuredError(activeContext, err);
addLogEvent("error", err.message, fields);
if (fields) {
contextState = {
...contextState,
...fields
};
activeContext.setAttributes(flattenToAttributes(fields));
}
activeContext.setAttribute("autotel.log.level", "error");
},
getContext() {
return { ...contextState };
},
emitNow(overrides) {
const mergedContext = {
...contextState,
...overrides ?? {}
};
const flattened = flattenToAttributes(mergedContext);
activeContext.setAttributes(flattened);
const snapshot = {
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
traceId: activeContext.traceId,
spanId: activeContext.spanId,
correlationId: activeContext.correlationId,
context: mergedContext
};
activeContext.addEvent("log.emit.manual", {
...flattened
});
if (options?.onEmit) {
Promise.resolve(options.onEmit(snapshot)).catch((error) => {
console.warn("[autotel] request logger onEmit failed:", error);
});
}
return snapshot;
}
};
}
export { createStructuredError, flattenToAttributes, flush, getRequestLogger, getStructuredErrorAttributes, recordStructuredError, runWithRequestContext, shutdown, toAttributeValue };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map