Files
lingniu-vehicle-ingest/go/vehicle-gateway/internal/metrics/recent_latency.go

80 lines
1.7 KiB
Go

package metrics
import (
"math"
"sort"
"strings"
"sync"
)
// RecentLatencyByKey tracks a bounded in-memory latency window per logical key.
// It is intentionally small and process-local; Prometheus histograms keep the
// lifetime view, while this gives capacity-check a recent-window signal.
type RecentLatencyByKey struct {
mu sync.Mutex
size int
windows map[string]*recentLatencyWindow
}
type recentLatencyWindow struct {
values []float64
next int
count int
}
func NewRecentLatencyByKey(size int) *RecentLatencyByKey {
if size <= 0 {
size = 1
}
return &RecentLatencyByKey{
size: size,
windows: map[string]*recentLatencyWindow{},
}
}
func (r *RecentLatencyByKey) Observe(key string, value float64) (p99 float64, samples int) {
if r == nil {
return 0, 0
}
key = strings.TrimSpace(key)
if key == "" {
key = "unknown"
}
if value < 0 || math.IsNaN(value) {
value = 0
}
if math.IsInf(value, 1) {
value = math.MaxFloat64
}
r.mu.Lock()
defer r.mu.Unlock()
window := r.windows[key]
if window == nil {
window = &recentLatencyWindow{values: make([]float64, r.size)}
r.windows[key] = window
}
window.values[window.next] = value
window.next = (window.next + 1) % len(window.values)
if window.count < len(window.values) {
window.count++
}
return window.quantileLocked(0.99), window.count
}
func (w *recentLatencyWindow) quantileLocked(q float64) float64 {
if w == nil || w.count == 0 {
return 0
}
snapshot := append([]float64(nil), w.values[:w.count]...)
sort.Float64s(snapshot)
index := int(math.Ceil(q*float64(len(snapshot)))) - 1
if index < 0 {
index = 0
}
if index >= len(snapshot) {
index = len(snapshot) - 1
}
return snapshot[index]
}