Add ASN info lookup and periodic routing table statistics

- Add handle and description columns to asns table
- Look up ASN info using asinfo package when creating new ASNs
- Remove noisy debug logging for individual route updates
- Add IPv4/IPv6 route counters and update rate tracking
- Log routing table statistics every 15 seconds with IPv4/IPv6 breakdown
- Track updates per second for both IPv4 and IPv6 routes separately
This commit is contained in:
2025-07-27 23:25:23 +02:00
parent a555a1dee2
commit 76ec9f68b7
6 changed files with 178 additions and 43 deletions

View File

@@ -4,6 +4,7 @@ package routewatch
import (
"context"
"fmt"
"log/slog"
"os"
"strings"
@@ -23,6 +24,11 @@ type Config struct {
MaxRuntime time.Duration // Maximum runtime (0 = run forever)
}
const (
// routingTableStatsInterval is how often we log routing table statistics
routingTableStatsInterval = 15 * time.Second
)
// NewConfig provides default configuration
func NewConfig() Config {
return Config{
@@ -88,6 +94,9 @@ func (rw *RouteWatch) Run(ctx context.Context) error {
peerHandler := NewPeerHandler(rw.db, rw.logger)
rw.streamer.RegisterHandler(peerHandler)
// Start periodic routing table stats logging
go rw.logRoutingTableStats(ctx)
// Start streaming
if err := rw.streamer.Start(); err != nil {
return err
@@ -125,6 +134,32 @@ func (rw *RouteWatch) Run(ctx context.Context) error {
return nil
}
// logRoutingTableStats periodically logs routing table statistics
func (rw *RouteWatch) logRoutingTableStats(ctx context.Context) {
// Log stats periodically
ticker := time.NewTicker(routingTableStatsInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
stats := rw.routingTable.GetDetailedStats()
rw.logger.Info("Routing table statistics",
"ipv4_routes", stats.IPv4Routes,
"ipv6_routes", stats.IPv6Routes,
"ipv4_updates_per_sec", fmt.Sprintf("%.2f", stats.IPv4UpdatesRate),
"ipv6_updates_per_sec", fmt.Sprintf("%.2f", stats.IPv6UpdatesRate),
"total_routes", stats.TotalRoutes,
"unique_prefixes", stats.UniquePrefixes,
"unique_origins", stats.UniqueOrigins,
"unique_peers", stats.UniquePeers,
)
}
}
}
// NewLogger creates a structured logger
func NewLogger() *slog.Logger {
level := slog.LevelInfo

View File

@@ -70,13 +70,6 @@ func (h *RoutingTableHandler) HandleMessage(msg *ristypes.RISMessage) {
// Add route to routing table
h.rt.AddRoute(route)
h.logger.Debug("Added route to routing table",
"prefix", prefix,
"origin_asn", originASN,
"peer_asn", peerASN,
"path", msg.Path,
)
}
}
@@ -86,13 +79,7 @@ func (h *RoutingTableHandler) HandleMessage(msg *ristypes.RISMessage) {
prefixID := uuid.NewSHA1(uuid.NameSpaceURL, []byte(prefix))
// Withdraw all routes for this prefix from this peer
count := h.rt.WithdrawRoutesByPrefixAndPeer(prefixID, peerASN)
h.logger.Debug("Withdrew routes from routing table",
"prefix", prefix,
"peer_asn", peerASN,
"routes_removed", count,
)
h.rt.WithdrawRoutesByPrefixAndPeer(prefixID, peerASN)
}
}