UNPKG

@varia-bly/variably-sdk

Version:

Official JavaScript/TypeScript SDK for Variably feature flags, experimentation, and real-time dynamic configurations

230 lines 6.73 kB
"use strict"; /** * Metrics collection for Variably SDK */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NoOpMetricsCollector = exports.MetricsCollector = void 0; class MetricsCollector { constructor() { this.apiCalls = 0; this.cacheHits = 0; this.cacheMisses = 0; this.errors = 0; this.latencies = []; this.flagsEvaluated = 0; this.gatesEvaluated = 0; this.eventsTracked = 0; this.maxLatencyHistory = 1000; // Keep last 1000 latency measurements this.startTime = new Date(); } /** * Record an API call */ recordApiCall() { this.apiCalls++; } /** * Record a cache hit */ recordCacheHit() { this.cacheHits++; } /** * Record a cache miss */ recordCacheMiss() { this.cacheMisses++; } /** * Record an error */ recordError() { this.errors++; } /** * Record request latency */ recordLatency(latencyMs) { this.latencies.push(latencyMs); // Keep only the most recent latency measurements if (this.latencies.length > this.maxLatencyHistory) { this.latencies = this.latencies.slice(-this.maxLatencyHistory); } } /** * Record a flag evaluation */ recordFlagEvaluation() { this.flagsEvaluated++; } /** * Record a gate evaluation */ recordGateEvaluation() { this.gatesEvaluated++; } /** * Record an event being tracked */ recordEventTracked() { this.eventsTracked++; } /** * Get current metrics snapshot */ getMetrics() { const totalCacheOperations = this.cacheHits + this.cacheMisses; const totalOperations = this.apiCalls + this.flagsEvaluated + this.gatesEvaluated; return { apiCalls: this.apiCalls, cacheHits: this.cacheHits, cacheMisses: this.cacheMisses, errors: this.errors, averageLatency: this.calculateAverageLatency(), cacheHitRate: totalCacheOperations > 0 ? this.cacheHits / totalCacheOperations : 0, errorRate: totalOperations > 0 ? this.errors / totalOperations : 0, flagsEvaluated: this.flagsEvaluated, gatesEvaluated: this.gatesEvaluated, eventsTracked: this.eventsTracked, startTime: this.startTime }; } /** * Get detailed latency statistics */ getLatencyStats() { if (this.latencies.length === 0) { return { min: 0, max: 0, average: 0, median: 0, p95: 0, p99: 0, count: 0 }; } const sorted = [...this.latencies].sort((a, b) => a - b); const count = sorted.length; return { min: sorted[0], max: sorted[count - 1], average: this.calculateAverageLatency(), median: this.calculatePercentile(sorted, 50), p95: this.calculatePercentile(sorted, 95), p99: this.calculatePercentile(sorted, 99), count }; } /** * Reset all metrics */ reset() { this.startTime = new Date(); this.apiCalls = 0; this.cacheHits = 0; this.cacheMisses = 0; this.errors = 0; this.latencies = []; this.flagsEvaluated = 0; this.gatesEvaluated = 0; this.eventsTracked = 0; } /** * Export metrics in a format suitable for external monitoring systems */ exportMetrics() { const metrics = this.getMetrics(); const latencyStats = this.getLatencyStats(); return { 'variably.api_calls.total': metrics.apiCalls, 'variably.cache.hits': metrics.cacheHits, 'variably.cache.misses': metrics.cacheMisses, 'variably.cache.hit_rate': metrics.cacheHitRate, 'variably.errors.total': metrics.errors, 'variably.error_rate': metrics.errorRate, 'variably.flags.evaluated': metrics.flagsEvaluated, 'variably.gates.evaluated': metrics.gatesEvaluated, 'variably.events.tracked': metrics.eventsTracked, 'variably.latency.average': metrics.averageLatency, 'variably.latency.min': latencyStats.min, 'variably.latency.max': latencyStats.max, 'variably.latency.median': latencyStats.median, 'variably.latency.p95': latencyStats.p95, 'variably.latency.p99': latencyStats.p99, 'variably.uptime.seconds': (Date.now() - metrics.startTime.getTime()) / 1000 }; } /** * Calculate average latency */ calculateAverageLatency() { if (this.latencies.length === 0) { return 0; } const sum = this.latencies.reduce((acc, latency) => acc + latency, 0); return sum / this.latencies.length; } /** * Calculate percentile from sorted array */ calculatePercentile(sortedArray, percentile) { if (sortedArray.length === 0) { return 0; } const index = (percentile / 100) * (sortedArray.length - 1); const lower = Math.floor(index); const upper = Math.ceil(index); const weight = index % 1; if (upper >= sortedArray.length) { return sortedArray[sortedArray.length - 1]; } return sortedArray[lower] * (1 - weight) + sortedArray[upper] * weight; } } exports.MetricsCollector = MetricsCollector; /** * No-op metrics collector for when metrics are disabled */ class NoOpMetricsCollector { recordApiCall() { } recordCacheHit() { } recordCacheMiss() { } recordError() { } recordLatency() { } recordFlagEvaluation() { } recordGateEvaluation() { } recordEventTracked() { } getMetrics() { return { apiCalls: 0, cacheHits: 0, cacheMisses: 0, errors: 0, averageLatency: 0, cacheHitRate: 0, errorRate: 0, flagsEvaluated: 0, gatesEvaluated: 0, eventsTracked: 0, startTime: new Date() }; } getLatencyStats() { return { min: 0, max: 0, average: 0, median: 0, p95: 0, p99: 0, count: 0 }; } reset() { } exportMetrics() { return {}; } } exports.NoOpMetricsCollector = NoOpMetricsCollector; //# sourceMappingURL=metrics.js.map