UNPKG

mcard-js

Version:

MCard - Content-addressable storage with cryptographic hashing, handle resolution, and vector search for Node.js and browsers

232 lines 7.44 kB
/** * OpenTelemetrySidecar - Universal Observability for PTR Engine * * This module provides OpenTelemetry-based observability for the PTR runtime, * enabling distributed tracing, metrics, and logging across all REPL phases. * * REPL Phase Instrumentation: * - prep: Log V_pre validation status, trace artifact loading * - exec: Metrics (CPU, memory, duration), trace execution path * - post: Log verification results, trace VCard generation * - await: Event for handle_history recording * * Works in both Node.js and Browser environments: * - Node.js: Uses @opentelemetry/sdk-node * - Browser: Uses FaroSidecar (Grafana Faro) * * See Also: * - CLM_MCard_REPL_Implementation.md §11: Grafana LGTM Integration * - PTR_MCard_CLM_Recent_Developments_Jan2026.md §6.2: Universal Observability */ /** * REPL Phase enum for instrumentation */ export var REPLPhase; (function (REPLPhase) { REPLPhase["PREP"] = "prep"; REPLPhase["EXEC"] = "exec"; REPLPhase["POST"] = "post"; REPLPhase["AWAIT"] = "await"; })(REPLPhase || (REPLPhase = {})); /** * OpenTelemetrySidecar - Universal observability for PTR * * Provides instrumentation hooks for each REPL phase: * - prep: Artifact loading, V_pre validation * - exec: CLM execution, sandbox runtime * - post: Balanced verification, VCard generation * - await: Handle history recording, state transition * * Usage: * const sidecar = OpenTelemetrySidecar.getInstance(); * sidecar.initialize({ * endpoint: "http://localhost:4317", * serviceName: "ptr-runtime", * serviceVersion: "1.0.0" * }); * * const span = sidecar.startPhase(REPLPhase.PREP, { pcardHash: "abc123" }); * // ... do prep work * sidecar.endPhase(span); */ export class OpenTelemetrySidecar { static instance = null; _initialized = false; _config = null; _isNode; // Phase timing metrics _phaseDurations = new Map(); _phaseCounts = new Map(); _errorCounts = new Map(); constructor() { // Detect environment this._isNode = typeof window === 'undefined' && typeof process !== 'undefined'; // Initialize metrics maps for (const phase of Object.values(REPLPhase)) { this._phaseDurations.set(phase, []); this._phaseCounts.set(phase, 0); this._errorCounts.set(phase, 0); } } /** * Get the singleton instance */ static getInstance() { if (!OpenTelemetrySidecar.instance) { OpenTelemetrySidecar.instance = new OpenTelemetrySidecar(); } return OpenTelemetrySidecar.instance; } /** * Initialize the OpenTelemetry SDK */ initialize(config) { if (this._initialized) { console.warn('[OpenTelemetrySidecar] Already initialized'); return true; } this._config = config; // In Node.js: Would initialize @opentelemetry/sdk-node // In Browser: Falls back to console logging // Full OTLP integration requires optional dependency if (this._isNode) { console.log(`[OpenTelemetrySidecar] Node.js mode initialized for ` + `${config.serviceName}@${config.serviceVersion} -> ${config.endpoint}`); console.log(`[OpenTelemetrySidecar] Note: Install @opentelemetry/sdk-node for full OTLP export`); } else { console.log(`[OpenTelemetrySidecar] Browser mode - using console fallback. ` + `Use FaroSidecar for browser observability.`); } this._initialized = true; return true; } /** * Start tracing a REPL phase */ startPhase(phase, options = {}) { const context = { phase, pcardHash: options.pcardHash, targetHash: options.targetHash, attributes: options.attributes, startTime: Date.now() }; // Log phase start this.logEvent(phase, `${phase}_start`, { pcardHash: options.pcardHash ?? '', targetHash: options.targetHash ?? '', ...options.attributes }); return context; } /** * End tracing a REPL phase */ endPhase(context, success = true, attributes) { const duration = Date.now() - context.startTime; // Record metrics this._recordPhaseDuration(context.phase, duration); this._recordPhaseCount(context.phase); if (!success) { this._recordError(context.phase); } // Log phase end this.logEvent(context.phase, `${context.phase}_complete`, { duration_ms: duration, success, ...attributes }); } /** * Log an event within a REPL phase */ logEvent(phase, eventName, attributes) { const timestamp = new Date().toISOString(); const namespace = this._config?.namespace ?? 'ptr'; if (this._initialized) { // In production: would use OTLP exporter // For now: structured console logging console.log(JSON.stringify({ timestamp, name: `${namespace}.repl.${eventName}`, phase, attributes: attributes ?? {} })); } } /** * Record phase duration metric */ _recordPhaseDuration(phase, durationMs) { const durations = this._phaseDurations.get(phase) ?? []; durations.push(durationMs); // Keep last 100 samples if (durations.length > 100) { durations.shift(); } this._phaseDurations.set(phase, durations); } /** * Record phase count metric */ _recordPhaseCount(phase) { const count = this._phaseCounts.get(phase) ?? 0; this._phaseCounts.set(phase, count + 1); } /** * Record error count */ _recordError(phase) { const count = this._errorCounts.get(phase) ?? 0; this._errorCounts.set(phase, count + 1); } /** * Get metrics summary */ getMetrics() { const metrics = {}; for (const phase of Object.values(REPLPhase)) { const durations = this._phaseDurations.get(phase) ?? []; const avgDuration = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0; metrics[phase] = { count: this._phaseCounts.get(phase) ?? 0, errors: this._errorCounts.get(phase) ?? 0, avgDurationMs: Math.round(avgDuration * 100) / 100, samples: durations.length }; } return metrics; } /** * Check if initialized */ isInitialized() { return this._initialized; } /** * Check if running in Node.js */ isNode() { return this._isNode; } } /** * Helper function to create a traced phase execution */ export async function tracePhase(phase, fn, options = {}) { const sidecar = OpenTelemetrySidecar.getInstance(); const span = sidecar.startPhase(phase, options); try { const result = await fn(); sidecar.endPhase(span, true); return result; } catch (error) { sidecar.endPhase(span, false, { error: String(error) }); throw error; } } //# sourceMappingURL=OpenTelemetrySidecar.js.map