From cb1f4d9052bc8d3b88f1f09afb94a6757766a17a Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 28 Jul 2025 02:55:27 +0200 Subject: [PATCH] Add route update metrics tracking to PrefixHandler - Add RecordIPv4Update and RecordIPv6Update to metrics package - Add SetMetricsTracker method to PrefixHandler - Track IPv4/IPv6 route updates when processing announcements - Add GetMetricsTracker method to Streamer to expose metrics --- internal/metrics/metrics.go | 30 ++++++++++++++++++++++++++++ internal/routewatch/app.go | 1 + internal/routewatch/prefixhandler.go | 20 +++++++++++++++++-- internal/streamer/streamer.go | 5 +++++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 03f0f56..64398d7 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -21,6 +21,10 @@ type Tracker struct { byteCounter metrics.Counter messageRate metrics.Meter byteRate metrics.Meter + + // Route update metrics + ipv4UpdateRate metrics.Meter + ipv6UpdateRate metrics.Meter } // New creates a new metrics tracker @@ -33,6 +37,8 @@ func New() *Tracker { byteCounter: metrics.NewCounter(), messageRate: metrics.NewMeter(), byteRate: metrics.NewMeter(), + ipv4UpdateRate: metrics.NewMeter(), + ipv6UpdateRate: metrics.NewMeter(), } } @@ -89,6 +95,24 @@ func (t *Tracker) GetStreamMetrics() StreamMetrics { } } +// 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 @@ -98,3 +122,9 @@ type StreamMetrics struct { MessagesPerSec float64 BitsPerSec float64 } + +// RouteMetrics contains route update statistics +type RouteMetrics struct { + IPv4UpdatesPerSec float64 + IPv6UpdatesPerSec float64 +} diff --git a/internal/routewatch/app.go b/internal/routewatch/app.go index 27ff8d6..1e4974f 100644 --- a/internal/routewatch/app.go +++ b/internal/routewatch/app.go @@ -118,6 +118,7 @@ func (rw *RouteWatch) Run(ctx context.Context) error { // PrefixHandler maintains the prefixes and live_routes tables rw.prefixHandler = NewPrefixHandler(rw.db, rw.logger) + rw.prefixHandler.SetMetricsTracker(rw.streamer.GetMetricsTracker()) rw.streamer.RegisterHandler(rw.prefixHandler) // PeeringHandler maintains the asn_peerings table diff --git a/internal/routewatch/prefixhandler.go b/internal/routewatch/prefixhandler.go index f539475..40d3b91 100644 --- a/internal/routewatch/prefixhandler.go +++ b/internal/routewatch/prefixhandler.go @@ -8,6 +8,7 @@ import ( "git.eeqj.de/sneak/routewatch/internal/database" "git.eeqj.de/sneak/routewatch/internal/logger" + "git.eeqj.de/sneak/routewatch/internal/metrics" "git.eeqj.de/sneak/routewatch/internal/ristypes" "github.com/google/uuid" ) @@ -30,8 +31,9 @@ const ( // PrefixHandler tracks BGP prefixes and maintains a live routing table in the database. // Routes are added on announcement and deleted on withdrawal. type PrefixHandler struct { - db database.Store - logger *logger.Logger + db database.Store + logger *logger.Logger + metrics *metrics.Tracker // Batching mu sync.Mutex @@ -67,6 +69,11 @@ func NewPrefixHandler(db database.Store, logger *logger.Logger) *PrefixHandler { return h } +// SetMetricsTracker sets the metrics tracker for recording route updates +func (h *PrefixHandler) SetMetricsTracker(metrics *metrics.Tracker) { + h.metrics = metrics +} + // WantsMessage returns true if this handler wants to process messages of the given type func (h *PrefixHandler) WantsMessage(messageType string) bool { // We only care about UPDATE messages for the routing table @@ -220,6 +227,15 @@ func (h *PrefixHandler) processAnnouncement(_ *database.Prefix, update prefixUpd return } + // Track route update metrics + if h.metrics != nil { + if ipVersion == ipv4Version { + h.metrics.RecordIPv4Update() + } else { + h.metrics.RecordIPv6Update() + } + } + // Create live route record liveRoute := &database.LiveRoute{ ID: uuid.New(), diff --git a/internal/streamer/streamer.go b/internal/streamer/streamer.go index 962c665..aa0221c 100644 --- a/internal/streamer/streamer.go +++ b/internal/streamer/streamer.go @@ -195,6 +195,11 @@ func (s *Streamer) GetMetrics() metrics.StreamMetrics { return s.metrics.GetStreamMetrics() } +// GetMetricsTracker returns the metrics tracker instance +func (s *Streamer) GetMetricsTracker() *metrics.Tracker { + return s.metrics +} + // HandlerStats represents metrics for a single handler type HandlerStats struct { Name string