Show route churn as a whole count per minute (closes #160)
check / check (push) Canceled after 0s
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 prefix announcements and withdrawals, from all peers, 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 was merged in pull request #169.
This commit is contained in:
@@ -441,10 +441,10 @@ type GCStats struct {
|
||||
//
|
||||
//nolint:tagliatelle // field names are the existing JSON API
|
||||
type StreamStats struct {
|
||||
Announcements uint64 `json:"announcements"`
|
||||
Withdrawals uint64 `json:"withdrawals"`
|
||||
RouteChurnPerSec float64 `json:"route_churn_per_sec"`
|
||||
BGPPeerCount int `json:"bgp_peer_count"`
|
||||
Announcements uint64 `json:"announcements"`
|
||||
Withdrawals uint64 `json:"withdrawals"`
|
||||
RouteChurnPerMin int `json:"route_churn_per_min"`
|
||||
BGPPeerCount int `json:"bgp_peer_count"`
|
||||
}
|
||||
|
||||
// StatsResponse represents the API statistics response
|
||||
@@ -545,7 +545,7 @@ func (s *Server) streamStats() StreamStats {
|
||||
return StreamStats{
|
||||
Announcements: metricsTracker.GetAnnouncementCount(),
|
||||
Withdrawals: metricsTracker.GetWithdrawalCount(),
|
||||
RouteChurnPerSec: metricsTracker.GetChurnRate(),
|
||||
RouteChurnPerMin: metricsTracker.GetChurnPerMinute(),
|
||||
BGPPeerCount: metricsTracker.GetBGPPeerCount(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,51 @@ func TestStatsHandlersAnswerFromMemory(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStatsAnswerCarriesChurnPerMinute checks that the stream object of the
|
||||
// /api/v1/stats answer holds route_churn_per_min as a whole number, and no
|
||||
// longer route_churn_per_sec, the moving average it replaces
|
||||
// (https://git.eeqj.de/sneak/routewatch/issues/160).
|
||||
func TestStatsAnswerCarriesChurnPerMinute(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := newServerWithTestRoutes(t)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
s.handleStats()(rec,
|
||||
httptest.NewRequestWithContext(t.Context(), http.MethodGet, statsPath, nil))
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status %d, want %d; body %s", rec.Code, http.StatusOK, rec.Body)
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Data struct {
|
||||
Stream map[string]json.RawMessage `json:"stream"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &body)
|
||||
if err != nil {
|
||||
t.Fatalf("decoding the answer: %v", err)
|
||||
}
|
||||
|
||||
churn, ok := body.Data.Stream["route_churn_per_min"]
|
||||
if !ok {
|
||||
t.Fatalf("stream has no route_churn_per_min: %s", rec.Body)
|
||||
}
|
||||
|
||||
var count int
|
||||
|
||||
err = json.Unmarshal(churn, &count)
|
||||
if err != nil {
|
||||
t.Errorf("route_churn_per_min = %s, want a whole number: %v", churn, err)
|
||||
}
|
||||
|
||||
if _, ok := body.Data.Stream["route_churn_per_sec"]; ok {
|
||||
t.Errorf("stream still has route_churn_per_sec: %s", rec.Body)
|
||||
}
|
||||
}
|
||||
|
||||
// newServerWithTestRoutes returns a server on a new database that holds a
|
||||
// route for testPrefixV4 and one for testPrefixV6.
|
||||
func newServerWithTestRoutes(t *testing.T) *Server {
|
||||
|
||||
Reference in New Issue
Block a user