Files

204 lines
4.4 KiB
Go
Raw Permalink Normal View History

package dashboard
import (
"fmt"
"sort"
"sync"
"time"
)
// MetricSnapshot represents a point-in-time metric value
type MetricSnapshot struct {
Timestamp time.Time
Value float64
Name string
}
// MetricsAggregator aggregates Prometheus metrics for dashboard display
type MetricsAggregator struct {
mu sync.RWMutex
metrics map[string][]MetricSnapshot
ttl time.Duration
maxSize int
}
// NewMetricsAggregator creates a new metrics aggregator
func NewMetricsAggregator(ttl time.Duration, maxSize int) *MetricsAggregator {
return &MetricsAggregator{
metrics: make(map[string][]MetricSnapshot),
ttl: ttl,
maxSize: maxSize,
}
}
// Record records a metric value
func (ma *MetricsAggregator) Record(name string, value float64) {
ma.mu.Lock()
defer ma.mu.Unlock()
snapshot := MetricSnapshot{
Timestamp: time.Now(),
Value: value,
Name: name,
}
ma.metrics[name] = append(ma.metrics[name], snapshot)
// Trim old entries
if len(ma.metrics[name]) > ma.maxSize {
ma.metrics[name] = ma.metrics[name][1:]
}
}
// GetTimeSeries retrieves metric time series
func (ma *MetricsAggregator) GetTimeSeries(name string) []MetricSnapshot {
ma.mu.RLock()
defer ma.mu.RUnlock()
snapshots, exists := ma.metrics[name]
if !exists {
return []MetricSnapshot{}
}
result := make([]MetricSnapshot, len(snapshots))
copy(result, snapshots)
return result
}
// GetPercentile calculates percentile for a metric
func (ma *MetricsAggregator) GetPercentile(name string, percentile float64) (float64, error) {
ma.mu.RLock()
defer ma.mu.RUnlock()
snapshots, exists := ma.metrics[name]
if !exists || len(snapshots) == 0 {
return 0, fmt.Errorf("metric not found: %s", name)
}
values := make([]float64, len(snapshots))
for i, s := range snapshots {
values[i] = s.Value
}
sort.Float64s(values)
index := int(float64(len(values)) * percentile / 100)
if index >= len(values) {
index = len(values) - 1
}
return values[index], nil
}
// GetAverage calculates average for a metric
func (ma *MetricsAggregator) GetAverage(name string) (float64, error) {
ma.mu.RLock()
defer ma.mu.RUnlock()
snapshots, exists := ma.metrics[name]
if !exists || len(snapshots) == 0 {
return 0, fmt.Errorf("metric not found: %s", name)
}
sum := 0.0
for _, s := range snapshots {
sum += s.Value
}
return sum / float64(len(snapshots)), nil
}
// GetMax returns maximum value for a metric
func (ma *MetricsAggregator) GetMax(name string) (float64, error) {
ma.mu.RLock()
defer ma.mu.RUnlock()
snapshots, exists := ma.metrics[name]
if !exists || len(snapshots) == 0 {
return 0, fmt.Errorf("metric not found: %s", name)
}
max := snapshots[0].Value
for _, s := range snapshots {
if s.Value > max {
max = s.Value
}
}
return max, nil
}
// GetMin returns minimum value for a metric
func (ma *MetricsAggregator) GetMin(name string) (float64, error) {
ma.mu.RLock()
defer ma.mu.RUnlock()
snapshots, exists := ma.metrics[name]
if !exists || len(snapshots) == 0 {
return 0, fmt.Errorf("metric not found: %s", name)
}
min := snapshots[0].Value
for _, s := range snapshots {
if s.Value < min {
min = s.Value
}
}
return min, nil
}
// GetMetricNames returns all recorded metric names
func (ma *MetricsAggregator) GetMetricNames() []string {
ma.mu.RLock()
defer ma.mu.RUnlock()
names := make([]string, 0, len(ma.metrics))
for name := range ma.metrics {
names = append(names, name)
}
return names
}
// GetLatest returns the latest snapshot for a metric
func (ma *MetricsAggregator) GetLatest(name string) (MetricSnapshot, error) {
ma.mu.RLock()
defer ma.mu.RUnlock()
snapshots, exists := ma.metrics[name]
if !exists || len(snapshots) == 0 {
return MetricSnapshot{}, fmt.Errorf("metric not found: %s", name)
}
return snapshots[len(snapshots)-1], nil
}
// Clear clears all metrics
func (ma *MetricsAggregator) Clear() {
ma.mu.Lock()
defer ma.mu.Unlock()
ma.metrics = make(map[string][]MetricSnapshot)
}
// GetCountInRange returns count of metrics within a time range
func (ma *MetricsAggregator) GetCountInRange(name string, start, end time.Time) (int, error) {
ma.mu.RLock()
defer ma.mu.RUnlock()
snapshots, exists := ma.metrics[name]
if !exists {
return 0, fmt.Errorf("metric not found: %s", name)
}
count := 0
for _, s := range snapshots {
if s.Timestamp.After(start) && s.Timestamp.Before(end) {
count++
}
}
return count, nil
}