Give every API value with a unit as a number (closes #199)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
A value with a unit is now a number, and its field name ends in the unit, as the vendored API_POLICIES.md requires. @meta.execution_time becomes execution_time_ms. In the stats answers, uptime, connection_duration, memory_usage and whois_stats.current_interval become uptime_seconds, connection_duration_seconds, memory_usage_bytes and whois_stats.current_interval_seconds. connection_duration_seconds is null while the feed is not connected. The status page formats the numbers itself. REPO_POLICIES.md is re-vendored from the same sneak/prompts commit. Model: opus-5-5
This commit was merged in pull request #207.
This commit is contained in:
+41
-33
@@ -23,7 +23,6 @@ import (
|
||||
"git.eeqj.de/sneak/routewatch/internal/streamer"
|
||||
"git.eeqj.de/sneak/routewatch/internal/templates"
|
||||
asinfo "git.eeqj.de/sneak/routewatch/pkg/asinfo"
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
@@ -226,18 +225,23 @@ type WHOISStatsInfo struct {
|
||||
NeverFetched int `json:"never_fetched"`
|
||||
SuccessesLastHour int `json:"successes_last_hour"`
|
||||
ErrorsLastHour int `json:"errors_last_hour"`
|
||||
CurrentInterval string `json:"current_interval"`
|
||||
ConsecutiveFails int `json:"consecutive_fails"`
|
||||
FreshPercent float64 `json:"fresh_percent"`
|
||||
|
||||
// CurrentIntervalSeconds is the wait between two fetches. It can have a
|
||||
// fractional part, such as 22.5.
|
||||
CurrentIntervalSeconds float64 `json:"current_interval_seconds"`
|
||||
}
|
||||
|
||||
// Stats is the /status.json answer: uptime, message counts, database stats,
|
||||
// and the routing table's figures. OldestRoute and NewestRoute are the times
|
||||
// of the oldest and the newest kept routes.
|
||||
// and the routing table's figures. UptimeSeconds is the time since the stream
|
||||
// last connected, or 0 if it has never connected. MemoryUsageBytes is the Go
|
||||
// heap in use. OldestRoute and NewestRoute are the times of the oldest and the
|
||||
// newest kept routes.
|
||||
//
|
||||
//nolint:tagliatelle // field names are the existing JSON API
|
||||
type Stats struct {
|
||||
Uptime string `json:"uptime"`
|
||||
UptimeSeconds int64 `json:"uptime_seconds"`
|
||||
TotalMessages uint64 `json:"total_messages"`
|
||||
TotalBytes uint64 `json:"total_bytes"`
|
||||
TotalWireBytes uint64 `json:"total_wire_bytes"`
|
||||
@@ -247,7 +251,7 @@ type Stats struct {
|
||||
Connected bool `json:"connected"`
|
||||
GoVersion string `json:"go_version"`
|
||||
Goroutines int `json:"goroutines"`
|
||||
MemoryUsage string `json:"memory_usage"`
|
||||
MemoryUsageBytes uint64 `json:"memory_usage_bytes"`
|
||||
ASNs int `json:"asns"`
|
||||
Prefixes int `json:"prefixes"`
|
||||
IPv4Prefixes int `json:"ipv4_prefixes"`
|
||||
@@ -362,7 +366,7 @@ func (s *Server) statusStats(
|
||||
runtime.ReadMemStats(&memStats)
|
||||
|
||||
return Stats{
|
||||
Uptime: streamUptime(streamMetrics.ConnectedSince),
|
||||
UptimeSeconds: uptimeSeconds(streamMetrics.ConnectedSince),
|
||||
TotalMessages: streamMetrics.TotalMessages,
|
||||
TotalBytes: streamMetrics.TotalBytes,
|
||||
TotalWireBytes: streamMetrics.TotalWireBytes,
|
||||
@@ -372,7 +376,7 @@ func (s *Server) statusStats(
|
||||
Connected: streamMetrics.Connected,
|
||||
GoVersion: runtime.Version(),
|
||||
Goroutines: runtime.NumGoroutine(),
|
||||
MemoryUsage: humanize.Bytes(memStats.Alloc),
|
||||
MemoryUsageBytes: memStats.Alloc,
|
||||
ASNs: dbStats.ASNs,
|
||||
Prefixes: counts.IPv4Prefixes + counts.IPv6Prefixes,
|
||||
IPv4Prefixes: counts.IPv4Prefixes,
|
||||
@@ -439,30 +443,31 @@ func (s *Server) getWHOISStats(ctx context.Context) *WHOISStatsInfo {
|
||||
NeverFetched: dbStats.NeverFetched,
|
||||
SuccessesLastHour: fetcherStats.SuccessesLastHour,
|
||||
ErrorsLastHour: fetcherStats.ErrorsLastHour,
|
||||
CurrentInterval: fetcherStats.CurrentInterval.String(),
|
||||
ConsecutiveFails: fetcherStats.ConsecutiveFails,
|
||||
FreshPercent: freshPercent,
|
||||
|
||||
CurrentIntervalSeconds: fetcherStats.CurrentInterval.Seconds(),
|
||||
}
|
||||
}
|
||||
|
||||
// streamUptime is how long the stream has been connected, to the second, or
|
||||
// "0s" if it has never connected.
|
||||
func streamUptime(connectedSince time.Time) string {
|
||||
// uptimeSeconds is the number of whole seconds since the stream last
|
||||
// connected, or 0 if it has never connected.
|
||||
func uptimeSeconds(connectedSince time.Time) int64 {
|
||||
if connectedSince.IsZero() {
|
||||
return "0s"
|
||||
return 0
|
||||
}
|
||||
|
||||
return time.Since(connectedSince).Truncate(time.Second).String()
|
||||
return int64(time.Since(connectedSince) / time.Second)
|
||||
}
|
||||
|
||||
// connectionDuration is how long the stream has been connected, to the
|
||||
// second, or "disconnected".
|
||||
func connectionDuration(connected bool, connectedSince time.Time) string {
|
||||
// connectionDurationSeconds is the number of whole seconds the stream has
|
||||
// been connected, or nil while it is not connected.
|
||||
func connectionDurationSeconds(connected bool, connectedSince time.Time) *int64 {
|
||||
if !connected || connectedSince.IsZero() {
|
||||
return "disconnected"
|
||||
return nil
|
||||
}
|
||||
|
||||
return time.Since(connectedSince).Truncate(time.Second).String()
|
||||
return new(uptimeSeconds(connectedSince))
|
||||
}
|
||||
|
||||
// whoisStaleThreshold matches the fetcher's threshold for consistency.
|
||||
@@ -512,7 +517,7 @@ type StreamStats struct {
|
||||
//
|
||||
//nolint:tagliatelle // field names are the existing JSON API
|
||||
type StatsResponse struct {
|
||||
Uptime string `json:"uptime"`
|
||||
UptimeSeconds int64 `json:"uptime_seconds"`
|
||||
TotalMessages uint64 `json:"total_messages"`
|
||||
TotalBytes uint64 `json:"total_bytes"`
|
||||
TotalWireBytes uint64 `json:"total_wire_bytes"`
|
||||
@@ -520,11 +525,10 @@ type StatsResponse struct {
|
||||
MbitsPerSec float64 `json:"mbits_per_sec"`
|
||||
WireMbitsPerSec float64 `json:"wire_mbits_per_sec"`
|
||||
Connected bool `json:"connected"`
|
||||
ConnectionDuration string `json:"connection_duration"`
|
||||
ReconnectCount uint64 `json:"reconnect_count"`
|
||||
GoVersion string `json:"go_version"`
|
||||
Goroutines int `json:"goroutines"`
|
||||
MemoryUsage string `json:"memory_usage"`
|
||||
MemoryUsageBytes uint64 `json:"memory_usage_bytes"`
|
||||
GC GCStats `json:"gc"`
|
||||
Stream StreamStats `json:"stream"`
|
||||
ASNs int `json:"asns"`
|
||||
@@ -546,6 +550,9 @@ type StatsResponse struct {
|
||||
IPv6PrefixDistribution []PrefixDistribution `json:"ipv6_prefix_distribution"`
|
||||
WHOISStats *WHOISStatsInfo `json:"whois_stats,omitempty"`
|
||||
|
||||
// ConnectionDurationSeconds is null while the stream is not connected.
|
||||
ConnectionDurationSeconds *int64 `json:"connection_duration_seconds"`
|
||||
|
||||
OriginsWithoutKeptRoute int `json:"origins_without_kept_route"`
|
||||
}
|
||||
|
||||
@@ -684,20 +691,18 @@ func (s *Server) statsResponse(
|
||||
runtime.ReadMemStats(&memStats)
|
||||
|
||||
return StatsResponse{
|
||||
Uptime: streamUptime(streamMetrics.ConnectedSince),
|
||||
TotalMessages: streamMetrics.TotalMessages,
|
||||
TotalBytes: streamMetrics.TotalBytes,
|
||||
TotalWireBytes: streamMetrics.TotalWireBytes,
|
||||
MessagesPerSec: streamMetrics.MessagesPerSec,
|
||||
MbitsPerSec: streamMetrics.BitsPerSec / bitsPerMegabit,
|
||||
WireMbitsPerSec: streamMetrics.WireBitsPerSec / bitsPerMegabit,
|
||||
Connected: streamMetrics.Connected,
|
||||
ConnectionDuration: connectionDuration(
|
||||
streamMetrics.Connected, streamMetrics.ConnectedSince),
|
||||
UptimeSeconds: uptimeSeconds(streamMetrics.ConnectedSince),
|
||||
TotalMessages: streamMetrics.TotalMessages,
|
||||
TotalBytes: streamMetrics.TotalBytes,
|
||||
TotalWireBytes: streamMetrics.TotalWireBytes,
|
||||
MessagesPerSec: streamMetrics.MessagesPerSec,
|
||||
MbitsPerSec: streamMetrics.BitsPerSec / bitsPerMegabit,
|
||||
WireMbitsPerSec: streamMetrics.WireBitsPerSec / bitsPerMegabit,
|
||||
Connected: streamMetrics.Connected,
|
||||
ReconnectCount: streamMetrics.ReconnectCount,
|
||||
GoVersion: runtime.Version(),
|
||||
Goroutines: runtime.NumGoroutine(),
|
||||
MemoryUsage: humanize.Bytes(memStats.Alloc),
|
||||
MemoryUsageBytes: memStats.Alloc,
|
||||
GC: gcStats(&memStats),
|
||||
Stream: s.streamStats(),
|
||||
ASNs: dbStats.ASNs,
|
||||
@@ -719,6 +724,9 @@ func (s *Server) statsResponse(
|
||||
IPv6PrefixDistribution: prefixDistribution(counts.IPv6PrefixesByLength),
|
||||
WHOISStats: whoisStats,
|
||||
|
||||
ConnectionDurationSeconds: connectionDurationSeconds(
|
||||
streamMetrics.Connected, streamMetrics.ConnectedSince),
|
||||
|
||||
OriginsWithoutKeptRoute: counts.OriginsWithoutKeptRoute,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user