UNPKG

@gati-framework/runtime

Version:

Gati runtime execution engine for running handler-based applications

172 lines 4.7 kB
/** * @module runtime/trace-collector * @description Collects request traces through the pipeline */ /** * Collects request traces through pipeline stages */ export class TraceCollector { activeTraces = new Map(); config; constructor(config = {}) { this.config = { enabled: config.enabled ?? false, maxTraces: config.maxTraces ?? 1000, retentionMs: config.retentionMs ?? 300000, // 5 minutes }; } /** * Start collecting a trace for a request */ startTrace(request, traceId) { if (!this.config.enabled) return; const trace = { id: traceId, timestamp: Date.now(), request, stages: [], snapshots: {}, duration: 0, status: 'pending', }; this.activeTraces.set(traceId, { trace, stageStack: [], }); this.enforceMemoryLimits(); } /** * Capture a pipeline stage */ captureStage(traceId, stage, metadata = {}) { if (!this.config.enabled) return; const active = this.activeTraces.get(traceId); if (!active) return; const traceStage = { name: stage, startTime: Date.now(), snapshotId: `${traceId}_${stage}_${Date.now()}`, metadata, }; // Add to parent stage if exists, otherwise to root const parent = active.stageStack[active.stageStack.length - 1]; if (parent) { parent.children = parent.children || []; parent.children.push(traceStage); } else { active.trace.stages.push(traceStage); } active.stageStack.push(traceStage); } /** * Capture a snapshot at current stage */ captureSnapshot(traceId, lctx) { if (!this.config.enabled) return; const active = this.activeTraces.get(traceId); if (!active) return; const currentStage = active.stageStack[active.stageStack.length - 1]; if (!currentStage) return; const snapshot = lctx.snapshot.create(); active.trace.snapshots[currentStage.snapshotId] = snapshot; } /** * Complete current stage */ completeStage(traceId) { if (!this.config.enabled) return; const active = this.activeTraces.get(traceId); if (!active || active.stageStack.length === 0) return; const stage = active.stageStack.pop(); stage.endTime = Date.now(); } /** * End trace collection */ endTrace(traceId, response, error) { if (!this.config.enabled) return null; const active = this.activeTraces.get(traceId); if (!active) return null; const trace = active.trace; trace.duration = Date.now() - trace.timestamp; trace.response = response; trace.status = error ? 'error' : 'success'; if (error) { trace.error = { message: error.message, stack: error.stack, code: error.code, }; } this.activeTraces.delete(traceId); return trace; } /** * Get active trace */ getActiveTrace(traceId) { const active = this.activeTraces.get(traceId); return active ? active.trace : null; } /** * Enable trace collection */ enable() { this.config.enabled = true; } /** * Disable trace collection */ disable() { this.config.enabled = false; } /** * Check if enabled */ isEnabled() { return this.config.enabled; } /** * Clear all active traces */ clear() { this.activeTraces.clear(); } /** * Get active trace count */ getActiveCount() { return this.activeTraces.size; } /** * Enforce memory limits */ enforceMemoryLimits() { if (this.activeTraces.size <= this.config.maxTraces) return; // Remove oldest traces const entries = Array.from(this.activeTraces.entries()); const toRemove = entries .sort((a, b) => a[1].trace.timestamp - b[1].trace.timestamp) .slice(0, entries.length - this.config.maxTraces); toRemove.forEach(([id]) => this.activeTraces.delete(id)); } } /** * Create a trace collector instance */ export function createTraceCollector(config) { return new TraceCollector(config); } //# sourceMappingURL=trace-collector.js.map