Spaces:
Paused
Paused
File size: 3,767 Bytes
529090e fbb1eb0 529090e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | /**
* MetricsService - Dashboard & Monitoring Integration
*
* Tracks system health metrics for:
* - Self-healing events
* - Database connections
* - API performance
* - Error rates
*/
interface MetricLabels {
[key: string]: string;
}
interface Metric {
name: string;
value: number;
labels: MetricLabels;
timestamp: number;
}
export class MetricsService {
private counters: Map<string, number> = new Map();
private gauges: Map<string, number> = new Map();
private historyBuffer: Metric[] = [];
private maxHistorySize = 1000;
/**
* Increment a counter metric
*/
async incrementCounter(name: string, labels: MetricLabels = {}): Promise<void> {
const key = this.buildKey(name, labels);
const current = this.counters.get(key) || 0;
this.counters.set(key, current + 1);
this.recordToHistory({
name,
value: current + 1,
labels,
timestamp: Date.now()
});
// Log for debugging
console.log(`📊 [Metrics] ${name}: ${current + 1}`, labels);
}
/**
* Set a gauge metric (point-in-time value)
*/
async setGauge(name: string, value: number, labels: MetricLabels = {}): Promise<void> {
const key = this.buildKey(name, labels);
this.gauges.set(key, value);
this.recordToHistory({
name,
value,
labels,
timestamp: Date.now()
});
}
/**
* Record a histogram metric (for latency/duration tracking)
*/
async recordHistogram(name: string, value: number, labels: MetricLabels = {}): Promise<void> {
const key = this.buildKey(`${name}_histogram`, labels);
// Store histogram as a gauge with the latest value
// For proper histogram, you'd want buckets - this is a simplified version
this.gauges.set(key, value);
this.recordToHistory({
name: `${name}_histogram`,
value,
labels,
timestamp: Date.now()
});
console.log(`📊 [Metrics] ${name} histogram: ${value}ms`, labels);
}
/**
* Get current value of a counter
*/
getCounter(name: string, labels: MetricLabels = {}): number {
const key = this.buildKey(name, labels);
return this.counters.get(key) || 0;
}
/**
* Get current value of a gauge
*/
getGauge(name: string, labels: MetricLabels = {}): number {
const key = this.buildKey(name, labels);
return this.gauges.get(key) || 0;
}
/**
* Get all metrics for dashboard
*/
getAllMetrics(): { counters: Record<string, number>; gauges: Record<string, number> } {
return {
counters: Object.fromEntries(this.counters),
gauges: Object.fromEntries(this.gauges)
};
}
/**
* Get recent metric history
*/
getHistory(limit: number = 100): Metric[] {
return this.historyBuffer.slice(-limit);
}
/**
* Export metrics in Prometheus format (for Grafana)
*/
toPrometheusFormat(): string {
const lines: string[] = [];
for (const [key, value] of this.counters) {
lines.push(`widgetdc_${key.replace(/[^a-zA-Z0-9_]/g, '_')} ${value}`);
}
for (const [key, value] of this.gauges) {
lines.push(`widgetdc_${key.replace(/[^a-zA-Z0-9_]/g, '_')} ${value}`);
}
return lines.join('\n');
}
private buildKey(name: string, labels: MetricLabels): string {
const labelStr = Object.entries(labels)
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}="${v}"`)
.join(',');
return labelStr ? `${name}{${labelStr}}` : name;
}
private recordToHistory(metric: Metric): void {
this.historyBuffer.push(metric);
if (this.historyBuffer.length > this.maxHistorySize) {
this.historyBuffer.shift();
}
}
}
// Singleton for global access
export const metricsService = new MetricsService();
|