// Package metrics provides centralized metrics tracking for the RouteWatch application package metrics import ( "sync" "sync/atomic" "time" "github.com/rcrowley/go-metrics" ) // Tracker provides centralized metrics tracking type Tracker struct { mu sync.RWMutex registry metrics.Registry connectedSince time.Time isConnected atomic.Bool // Stream metrics messageCounter metrics.Counter byteCounter metrics.Counter messageRate metrics.Meter byteRate metrics.Meter // Route update metrics ipv4UpdateRate metrics.Meter ipv6UpdateRate metrics.Meter } // New creates a new metrics tracker func New() *Tracker { registry := metrics.NewRegistry() return &Tracker{ registry: registry, messageCounter: metrics.NewCounter(), byteCounter: metrics.NewCounter(), messageRate: metrics.NewMeter(), byteRate: metrics.NewMeter(), ipv4UpdateRate: metrics.NewMeter(), ipv6UpdateRate: metrics.NewMeter(), } } // SetConnected updates the connection status func (t *Tracker) SetConnected(connected bool) { t.isConnected.Store(connected) if connected { t.mu.Lock() t.connectedSince = time.Now() t.mu.Unlock() } } // IsConnected returns the current connection status func (t *Tracker) IsConnected() bool { return t.isConnected.Load() } // RecordMessage records a received message and its size func (t *Tracker) RecordMessage(bytes int64) { t.messageCounter.Inc(1) t.byteCounter.Inc(bytes) t.messageRate.Mark(1) t.byteRate.Mark(bytes) } // GetStreamMetrics returns current streaming metrics func (t *Tracker) GetStreamMetrics() StreamMetrics { t.mu.RLock() connectedSince := t.connectedSince t.mu.RUnlock() const bitsPerByte = 8 // Safely convert counters to uint64 msgCount := t.messageCounter.Count() byteCount := t.byteCounter.Count() var totalMessages, totalBytes uint64 if msgCount >= 0 { totalMessages = uint64(msgCount) } if byteCount >= 0 { totalBytes = uint64(byteCount) } return StreamMetrics{ TotalMessages: totalMessages, TotalBytes: totalBytes, ConnectedSince: connectedSince, Connected: t.isConnected.Load(), MessagesPerSec: t.messageRate.Rate1(), BitsPerSec: t.byteRate.Rate1() * bitsPerByte, } } // RecordIPv4Update records an IPv4 route update func (t *Tracker) RecordIPv4Update() { t.ipv4UpdateRate.Mark(1) } // RecordIPv6Update records an IPv6 route update func (t *Tracker) RecordIPv6Update() { t.ipv6UpdateRate.Mark(1) } // GetRouteMetrics returns current route update metrics func (t *Tracker) GetRouteMetrics() RouteMetrics { return RouteMetrics{ IPv4UpdatesPerSec: t.ipv4UpdateRate.Rate1(), IPv6UpdatesPerSec: t.ipv6UpdateRate.Rate1(), } } // StreamMetrics contains streaming statistics type StreamMetrics struct { TotalMessages uint64 TotalBytes uint64 ConnectedSince time.Time Connected bool MessagesPerSec float64 BitsPerSec float64 } // RouteMetrics contains route update statistics type RouteMetrics struct { IPv4UpdatesPerSec float64 IPv6UpdatesPerSec float64 }