UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

167 lines 6.2 kB
/** * Sentry Exporter * Exports spans to Sentry error tracking and performance platform */ import { logger } from "../../utils/logger.js"; import { SpanStatus } from "../../types/index.js"; import { BaseExporter } from "./baseExporter.js"; // Sentry types - optional dependency /** * Sentry exporter for error tracking and performance monitoring * Captures AI errors as exceptions and traces as transactions */ export class SentryExporter extends BaseExporter { dsn; tracesSampleRate; release; sentryHub = null; constructor(config) { super("sentry", config); this.dsn = config.dsn; this.tracesSampleRate = config.tracesSampleRate ?? 1.0; this.release = config.release; } async initialize() { if (this.initialized) { return; } // Dynamically import Sentry to avoid bundling issues // @sentry/node is an optional peer dependency const sentry = await this.loadSentry(); if (sentry) { sentry.init({ dsn: this.dsn, tracesSampleRate: this.tracesSampleRate, release: this.release, environment: this.config.environment ?? "production", }); this.sentryHub = sentry; } this.initialized = true; } /** * Load Sentry SDK dynamically as an optional dependency * @returns Sentry module or null if not installed */ async loadSentry() { try { // Use standard dynamic import for optional peer dependency // @ts-expect-error - @sentry/node is an optional peer dependency const sentry = await import("@sentry/node"); return sentry; } catch { logger.warn("[Sentry] Sentry SDK not installed. Install @sentry/node to use SentryExporter."); return null; } } async exportSpan(span) { const startTime = Date.now(); if (!this.sentryHub) { // Sentry not available, just succeed silently return this.createSuccessResult(0, Date.now() - startTime); } try { const Sentry = this.sentryHub; // For errors, capture as Sentry exception if (span.status === SpanStatus.ERROR) { Sentry.withScope((scope) => { scope.setTags({ "ai.provider": span.attributes["ai.provider"] ?? "", "ai.model": span.attributes["ai.model"] ?? "", "span.type": span.type, }); scope.setContext("ai", { tokens: { input: span.attributes["ai.tokens.input"], output: span.attributes["ai.tokens.output"], total: span.attributes["ai.tokens.total"], }, cost: span.attributes["ai.cost.total"], duration_ms: span.durationMs, }); if (span.attributes["user.id"]) { scope.setUser({ id: span.attributes["user.id"], }); } Sentry.captureException(new Error(span.statusMessage ?? "AI operation failed")); }); } // Create Sentry transaction for performance tracking const transaction = Sentry.startInactiveSpan({ name: span.name, op: span.type, startTime: new Date(span.startTime).getTime() / 1000, attributes: { "ai.provider": span.attributes["ai.provider"], "ai.model": span.attributes["ai.model"], "ai.tokens.total": span.attributes["ai.tokens.total"], "ai.cost.total": span.attributes["ai.cost.total"], }, }); // End the transaction if (span.endTime) { transaction.end(new Date(span.endTime).getTime() / 1000); } else { transaction.end(); } return this.createSuccessResult(1, Date.now() - startTime); } catch (error) { return this.createFailureResult([span.spanId], error instanceof Error ? error.message : String(error), Date.now() - startTime, false); } } async exportBatch(spans) { const results = await Promise.all(spans.map((s) => this.exportSpan(s))); const successful = results.filter((r) => r.success).length; const failed = spans.length - successful; return { success: failed === 0, exportedCount: successful, failedCount: failed, errors: results.flatMap((r) => r.errors ?? []), durationMs: results.reduce((sum, r) => sum + r.durationMs, 0), }; } async flush() { if (this.buffer.length > 0) { const spans = [...this.buffer]; this.buffer = []; await this.exportBatch(spans); } // Flush Sentry's internal buffer if (this.sentryHub) { await this.sentryHub.flush(2000); } } async shutdown() { await this.flush(); // Close Sentry SDK if (this.sentryHub) { await this.sentryHub.close(2000); } this.initialized = false; } async healthCheck() { try { await this.withRetry(() => this.ping(), "health check"); return this.createHealthStatus(true); } catch { return this.createHealthStatus(false, ["Health check failed"]); } } /** * Verify Sentry SDK is functional */ async ping() { if (!this.sentryHub) { throw new Error("Sentry SDK not initialized"); } // Sentry SDK is available, consider it healthy // Note: Sentry doesn't have a simple ping endpoint, but the SDK initialization verifies DSN } } //# sourceMappingURL=sentryExporter.js.map