UNPKG

@mastra/core

Version:

The core foundation of the Mastra framework, providing essential components and interfaces for building AI-powered applications.

450 lines (445 loc) 15.4 kB
'use strict'; var chunk6KB5CPBV_cjs = require('./chunk-6KB5CPBV.cjs'); var api = require('@opentelemetry/api'); var core = require('@opentelemetry/core'); var otlpTransformer = require('@opentelemetry/otlp-transformer'); function hasActiveTelemetry(tracerName = "default-tracer") { try { return !!api.trace.getTracer(tracerName); } catch { return false; } } // src/telemetry/telemetry.decorators.ts function withSpan(options) { return function(_target, propertyKey, descriptor) { if (!descriptor || typeof descriptor === "number") return; const originalMethod = descriptor.value; const methodName = String(propertyKey); descriptor.value = function(...args) { if (options?.skipIfNoTelemetry && !hasActiveTelemetry(options?.tracerName)) { return originalMethod.apply(this, args); } const tracer = api.trace.getTracer(options?.tracerName ?? "default-tracer"); let spanName; let spanKind; if (typeof options === "string") { spanName = options; } else if (options) { spanName = options.spanName || methodName; spanKind = options.spanKind; } else { spanName = methodName; } const span = tracer.startSpan(spanName, { kind: spanKind }); let ctx = api.trace.setSpan(api.context.active(), span); args.forEach((arg, index) => { try { span.setAttribute(`${spanName}.argument.${index}`, JSON.stringify(arg)); } catch { span.setAttribute(`${spanName}.argument.${index}`, "[Not Serializable]"); } }); const currentBaggage = api.propagation.getBaggage(ctx); if (currentBaggage?.["http.request_id"]) { span.setAttribute("http.request_id", currentBaggage?.["http.request_id"]); } if (currentBaggage?.componentName) { span.setAttribute("componentName", currentBaggage?.componentName); span.setAttribute("runId", currentBaggage?.runId); } else if (this && this.name) { span.setAttribute("componentName", this.name); span.setAttribute("runId", this.runId); ctx = api.propagation.setBaggage(ctx, { // @ts-ignore componentName: this.name, // @ts-ignore runId: this.runId, // @ts-ignore "http.request_id": currentBaggage?.["http.request_id"] }); } let result; try { result = api.context.with(ctx, () => originalMethod.apply(this, args)); if (result instanceof Promise) { return result.then((resolvedValue) => { try { span.setAttribute(`${spanName}.result`, JSON.stringify(resolvedValue)); } catch { span.setAttribute(`${spanName}.result`, "[Not Serializable]"); } return resolvedValue; }).finally(() => span.end()); } try { span.setAttribute(`${spanName}.result`, JSON.stringify(result)); } catch { span.setAttribute(`${spanName}.result`, "[Not Serializable]"); } return result; } catch (error) { span.setStatus({ code: api.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : "Unknown error" }); if (error instanceof Error) { span.recordException(error); } throw error; } finally { if (!(result instanceof Promise)) { span.end(); } } }; return descriptor; }; } function InstrumentClass(options) { return function(target) { const methods = Object.getOwnPropertyNames(target.prototype); methods.forEach((method) => { if (options?.excludeMethods?.includes(method) || method === "constructor") return; if (options?.methodFilter && !options.methodFilter(method)) return; const descriptor = Object.getOwnPropertyDescriptor(target.prototype, method); if (descriptor && typeof descriptor.value === "function") { Object.defineProperty( target.prototype, method, withSpan({ spanName: options?.prefix ? `${options.prefix}.${method}` : method, skipIfNoTelemetry: true, spanKind: options?.spanKind || api.SpanKind.INTERNAL, tracerName: options?.tracerName })(target, method, descriptor) ); } }); return target; }; } var OTLPTraceExporter = class { storage; queue = []; serializer; logger; activeFlush = void 0; constructor({ logger, storage }) { this.storage = storage; this.serializer = otlpTransformer.JsonTraceSerializer; this.logger = logger; } export(internalRepresentation, resultCallback) { const serializedRequest = this.serializer.serializeRequest(internalRepresentation); const payload = JSON.parse(Buffer.from(serializedRequest.buffer, "utf8")); const items = payload?.resourceSpans?.[0]?.scopeSpans; this.logger.debug(`Exporting telemetry: ${items.length} scope spans to be processed [trace batch]`); this.queue.push({ data: items, resultCallback }); if (!this.activeFlush) { this.activeFlush = this.flush(); } } shutdown() { return this.forceFlush(); } flush() { const now = /* @__PURE__ */ new Date(); const items = this.queue.shift(); if (!items) return Promise.resolve(); const allSpans = items.data.reduce((acc, scopedSpans) => { const { scope, spans } = scopedSpans; for (const span of spans) { const { spanId, parentSpanId, traceId, name, kind, attributes, status, events, links, startTimeUnixNano, endTimeUnixNano, ...rest } = span; const startTime = Number(BigInt(startTimeUnixNano) / 1000n); const endTime = Number(BigInt(endTimeUnixNano) / 1000n); acc.push({ id: spanId, parentSpanId, traceId, name, scope: scope.name, kind, status: JSON.stringify(status), events: JSON.stringify(events), links: JSON.stringify(links), attributes: JSON.stringify( attributes.reduce((acc2, attr) => { const valueKey = Object.keys(attr.value)[0]; if (valueKey) { acc2[attr.key] = attr.value[valueKey]; } return acc2; }, {}) ), startTime, endTime, other: JSON.stringify(rest), createdAt: now }); } return acc; }, []); return this.storage.batchInsert({ tableName: chunk6KB5CPBV_cjs.TABLE_TRACES, records: allSpans }).then(() => { items.resultCallback({ code: core.ExportResultCode.SUCCESS }); }).catch((e) => { this.logger.error("span err:" + e?.message); items.resultCallback({ code: core.ExportResultCode.FAILED, error: e }); }).finally(() => { this.activeFlush = void 0; }); } async forceFlush() { if (!this.queue.length) { return; } await this.activeFlush; while (this.queue.length) { await this.flush(); } } __setLogger(logger) { this.logger = logger; } }; var Telemetry = class _Telemetry { tracer = api.trace.getTracer("default"); name = "default-service"; constructor(config) { this.name = config.serviceName ?? "default-service"; this.tracer = api.trace.getTracer(this.name); } /** * @deprecated This method does not do anything */ async shutdown() { } /** * Initialize telemetry with the given configuration * @param config - Optional telemetry configuration object * @returns Telemetry instance that can be used for tracing */ static init(config = {}) { try { if (!global.__TELEMETRY__) { global.__TELEMETRY__ = new _Telemetry(config); } return global.__TELEMETRY__; } catch (error) { console.error("Failed to initialize telemetry:", error); throw error; } } static getActiveSpan() { const span = api.trace.getActiveSpan(); return span; } /** * Get the global telemetry instance * @throws {Error} If telemetry has not been initialized * @returns {Telemetry} The global telemetry instance */ static get() { if (!global.__TELEMETRY__) { throw new Error("Telemetry not initialized"); } return global.__TELEMETRY__; } /** * Wraps a class instance with telemetry tracing * @param instance The class instance to wrap * @param options Optional configuration for tracing * @returns Wrapped instance with all methods traced */ traceClass(instance, options = {}) { const { skipIfNoTelemetry = true } = options; if (skipIfNoTelemetry && !hasActiveTelemetry()) { return instance; } const { spanNamePrefix = instance.constructor.name.toLowerCase(), attributes = {}, excludeMethods = [] } = options; return new Proxy(instance, { get: (target, prop) => { const value = target[prop]; if (typeof value === "function" && prop !== "constructor" && !prop.toString().startsWith("_") && !excludeMethods.includes(prop.toString())) { return this.traceMethod(value.bind(target), { spanName: `${spanNamePrefix}.${prop.toString()}`, attributes: { ...attributes, [`${spanNamePrefix}.name`]: target.constructor.name, [`${spanNamePrefix}.method.name`]: prop.toString() } }); } return value; } }); } static setBaggage(baggage, ctx = api.context.active()) { const currentBaggage = api.propagation.getBaggage(ctx); const newCtx = api.propagation.setBaggage(ctx, { ...currentBaggage, ...baggage }); return newCtx; } static withContext(ctx, fn) { return api.context.with(ctx, fn); } /** * method to trace individual methods with proper context * @param method The method to trace * @param context Additional context for the trace * @returns Wrapped method with tracing */ traceMethod(method, context3) { let ctx = api.context.active(); const { skipIfNoTelemetry = true } = context3; if (skipIfNoTelemetry && !hasActiveTelemetry()) { return method; } return (...args) => { const span = this.tracer.startSpan(context3.spanName); function handleError(error) { span.recordException(error); span.setStatus({ code: api.SpanStatusCode.ERROR, message: error.message }); span.end(); throw error; } try { let recordResult2 = function(res) { try { span.setAttribute(`${context3.spanName}.result`, JSON.stringify(res)); } catch { span.setAttribute(`${context3.spanName}.result`, "[Not Serializable]"); } span.end(); return res; }; const currentBaggage = api.propagation.getBaggage(ctx); if (context3.attributes) { span.setAttributes(context3.attributes); } if (currentBaggage?.["http.request_id"]) { span.setAttribute("http.request_id", currentBaggage?.["http.request_id"]); } if (context3.attributes?.componentName) { ctx = api.propagation.setBaggage(ctx, { // @ts-ignore componentName: context3.attributes.componentName, runId: context3.attributes.runId, // @ts-ignore "http.request_id": currentBaggage?.["http.request_id"] }); } else { if (currentBaggage?.componentName) { span.setAttribute("componentName", currentBaggage?.componentName); span.setAttribute("runId", currentBaggage?.runId); } else if (this && this.name) { span.setAttribute("componentName", this.name); span.setAttribute("runId", this.runId); ctx = api.propagation.setBaggage(ctx, { // @ts-ignore componentName: this.name, // @ts-ignore runId: this.runId, // @ts-ignore "http.request_id": currentBaggage?.["http.request_id"] }); } } args.forEach((arg, index) => { try { span.setAttribute(`${context3.spanName}.argument.${index}`, JSON.stringify(arg)); } catch { span.setAttribute(`${context3.spanName}.argument.${index}`, "[Not Serializable]"); } }); let result; api.context.with(api.trace.setSpan(ctx, span), () => { result = method(...args); }); if (result instanceof Promise) { return result.then(recordResult2).catch(handleError); } else { return recordResult2(result); } } catch (error) { handleError(error); } }; } getBaggageTracer() { return new BaggageTracer(this.tracer); } }; var BaggageTracer = class { _tracer; constructor(tracer) { this._tracer = tracer; } startSpan(name, options = {}, ctx) { ctx = ctx ?? api.context.active(); const span = this._tracer.startSpan(name, options, ctx); const currentBaggage = api.propagation.getBaggage(ctx); span.setAttribute("componentName", currentBaggage?.componentName); span.setAttribute("runId", currentBaggage?.runId); span.setAttribute("http.request_id", currentBaggage?.["http.request_id"]); return span; } startActiveSpan(name, optionsOrFn, ctxOrFn, fn) { if (typeof optionsOrFn === "function") { const wrappedFn2 = (span) => { const currentBaggage = api.propagation.getBaggage(api.context.active()); span.setAttribute("componentName", currentBaggage?.componentName); span.setAttribute("runId", currentBaggage?.runId); span.setAttribute("http.request_id", currentBaggage?.["http.request_id"]); return optionsOrFn(span); }; return this._tracer.startActiveSpan(name, {}, api.context.active(), wrappedFn2); } if (typeof ctxOrFn === "function") { const wrappedFn2 = (span) => { const currentBaggage = api.propagation.getBaggage(api.context.active()); span.setAttribute("componentName", currentBaggage?.componentName); span.setAttribute("runId", currentBaggage?.runId); span.setAttribute("http.request_id", currentBaggage?.["http.request_id"]); return ctxOrFn(span); }; return this._tracer.startActiveSpan(name, optionsOrFn, api.context.active(), wrappedFn2); } const wrappedFn = (span) => { const currentBaggage = api.propagation.getBaggage(ctxOrFn ?? api.context.active()); span.setAttribute("componentName", currentBaggage?.componentName); span.setAttribute("runId", currentBaggage?.runId); span.setAttribute("http.request_id", currentBaggage?.["http.request_id"]); return fn(span); }; return this._tracer.startActiveSpan(name, optionsOrFn, ctxOrFn, wrappedFn); } }; exports.InstrumentClass = InstrumentClass; exports.OTLPTraceExporter = OTLPTraceExporter; exports.Telemetry = Telemetry; exports.hasActiveTelemetry = hasActiveTelemetry; exports.withSpan = withSpan;