UNPKG

@axarai/axar

Version:

TypeScript-based agent framework for building agentic applications powered by LLMs

133 lines (132 loc) 4.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Telemetry = void 0; const api_1 = require("@opentelemetry/api"); const zod_to_json_schema_1 = require("zod-to-json-schema"); const zod_1 = require("zod"); /** * Telemetry class that provides a wrapper around OpenTelemetry functionality * for tracking and monitoring application behavior. * * @template T - The type of object being monitored. Must extend Object. */ class Telemetry { /** * Creates a new Telemetry instance * @param object - The object to monitor. Used to generate span names based on the constructor name. */ constructor(object) { this.object = object; this.tracer = api_1.trace.getTracer(`${this.object.constructor.name}`); } /** * Starts a new span with the given method name * @param method - The method name to use for the span * @throws Error if span creation fails */ startSpan(method) { try { this.span = this.tracer.startSpan(`${this.object.constructor.name}.${method}`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Failed to start span: ${errorMessage}`); } } /** * Ends the current span if it exists and cleans up resources */ endSpan() { this.span?.end(); this.span = undefined; } /** * Adds an attribute to the current span if telemetry is enabled * @param key - The attribute key to be added to the span * @param value - The attribute value. Can be: * - string: Added directly as an attribute * - ZodSchema: Converted to JSON schema before adding * - string[]: Stringified before adding * - Object: Stringified with indentation before adding * - undefined/null: Ignored * @example * ```typescript * telemetry.addAttribute('userId', '12345'); * telemetry.addAttribute('requestBody', userSchema); * telemetry.addAttribute('tags', ['important', 'urgent']); * ``` */ addAttribute(key, value) { if (!this.span || value === undefined || value === null) { return; } if (typeof value === 'string') { this.span.setAttribute(key, value); return; } if (Array.isArray(value)) { this.span.setAttribute(key, JSON.stringify(value)); return; } if (value instanceof zod_1.ZodSchema) { const jsonSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(value, { $refStrategy: 'none', errorMessages: false, }); this.span.setAttribute(key, JSON.stringify(jsonSchema)); return; } this.span.setAttribute(key, JSON.stringify(value)); } /** * Executes an operation within a new span, providing automatic error handling * and context management. * * @param method - The method name for the span. Must not be empty. * @param operation - The async operation to execute within the span * @returns The result of the operation * @throws Any error from the operation, after recording it in the span * * @example * ```typescript * const result = await telemetry.withSpan('processUser', async () => { * const user = await processUserData(); * return user; * }); * ``` */ async withSpan(method, operation) { this.startSpan(method); try { return await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), this.span), operation); } catch (error) { if (this.span) { const errorObject = error instanceof Error ? error : new Error(String(error)); this.span.recordException(errorObject); this.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: errorObject.message, }); } throw error; } finally { this.endSpan(); } } /** * Gets the current context with the active span * @returns The current context with the active span if one exists, * otherwise returns the active context */ getContext() { return this.span ? api_1.trace.setSpan(api_1.context.active(), this.span) : api_1.context.active(); } isRecording() { return this.span !== undefined && this.span.isRecording(); } } exports.Telemetry = Telemetry;