Show route churn as a whole count per minute (closes #160)
check / check (push) Canceled after 0s

The status page showed route churn per second as a one-minute moving
average, so a quiet feed gave a fraction such as 0.1. The average was
correct.

The metrics tracker now also counts the prefixes announced or withdrawn
in each clock minute. /api/v1/stats reports the count for the last full
minute as route_churn_per_min in stream, in place of
route_churn_per_sec. The status page shows it as "Route Churn/min".

The status and home pages round messages and updates per second to
whole numbers.

Model: opus-5-5
This commit is contained in:
2026-10-26 22:51:45 +00:00
parent 087b8de9ae
commit f021cbd7c6
9 changed files with 213 additions and 21 deletions
+8 -7
View File
@@ -34,7 +34,7 @@ type Tracker struct {
// Announcement/withdrawal metrics
announcementCounter metrics.Counter
withdrawalCounter metrics.Counter
churnRate metrics.Meter // combined announcements + withdrawals per second
churnPerMinute minuteCounter // announced and withdrawn prefixes
// BGP peer tracking
bgpPeerCount atomic.Int32
@@ -56,7 +56,7 @@ func New() *Tracker {
ipv6UpdateRate: metrics.NewMeter(),
announcementCounter: metrics.NewCounter(),
withdrawalCounter: metrics.NewCounter(),
churnRate: metrics.NewMeter(),
churnPerMinute: minuteCounter{now: time.Now},
}
}
@@ -156,13 +156,13 @@ func (t *Tracker) RecordIPv6Update() {
// RecordAnnouncement records a route announcement
func (t *Tracker) RecordAnnouncement() {
t.announcementCounter.Inc(1)
t.churnRate.Mark(1)
t.churnPerMinute.add()
}
// RecordWithdrawal records a route withdrawal
func (t *Tracker) RecordWithdrawal() {
t.withdrawalCounter.Inc(1)
t.churnRate.Mark(1)
t.churnPerMinute.add()
}
// SetBGPPeerCount updates the current BGP peer count
@@ -198,9 +198,10 @@ func (t *Tracker) GetWithdrawalCount() uint64 {
return uint64(count)
}
// GetChurnRate returns the route churn rate per second
func (t *Tracker) GetChurnRate() float64 {
return t.churnRate.Rate1()
// GetChurnPerMinute returns the number of prefixes announced or withdrawn in
// the last full minute of the clock.
func (t *Tracker) GetChurnPerMinute() int {
return t.churnPerMinute.lastFullMinute()
}
// GetRouteMetrics returns current route update metrics