Add oldest and newest route timestamps to status page
Display oldest and newest route timestamps in the Routing Table card on the /status page. Timestamps are shown as relative times (e.g., "5m ago", "2h 30m ago"). Changes: - Add OldestRoute and NewestRoute fields to database.Stats - Query MIN/MAX of last_updated across live_routes_v4 and v6 tables - Include timestamps in both /status.json and /api/v1/stats responses - Add formatRelativeTime JavaScript function for display
This commit is contained in:
parent
8fc10ae98d
commit
aebdd1b23e
@ -946,6 +946,23 @@ func (d *Database) GetStatsContext(ctx context.Context) (Stats, error) {
|
|||||||
}
|
}
|
||||||
stats.LiveRoutes = v4Count + v6Count
|
stats.LiveRoutes = v4Count + v6Count
|
||||||
|
|
||||||
|
// Get oldest and newest route timestamps
|
||||||
|
routeTimestampQuery := `
|
||||||
|
SELECT MIN(last_updated), MAX(last_updated) FROM (
|
||||||
|
SELECT last_updated FROM live_routes_v4
|
||||||
|
UNION ALL
|
||||||
|
SELECT last_updated FROM live_routes_v6
|
||||||
|
)
|
||||||
|
`
|
||||||
|
var oldestRoute, newestRoute *time.Time
|
||||||
|
err = d.db.QueryRowContext(ctx, routeTimestampQuery).Scan(&oldestRoute, &newestRoute)
|
||||||
|
if err != nil {
|
||||||
|
d.logger.Warn("Failed to get route timestamps", "error", err)
|
||||||
|
} else {
|
||||||
|
stats.OldestRoute = oldestRoute
|
||||||
|
stats.NewestRoute = newestRoute
|
||||||
|
}
|
||||||
|
|
||||||
// Get prefix distribution
|
// Get prefix distribution
|
||||||
stats.IPv4PrefixDistribution, stats.IPv6PrefixDistribution, err = d.GetPrefixDistributionContext(ctx)
|
stats.IPv4PrefixDistribution, stats.IPv6PrefixDistribution, err = d.GetPrefixDistributionContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -18,6 +18,8 @@ type Stats struct {
|
|||||||
Peers int
|
Peers int
|
||||||
FileSizeBytes int64
|
FileSizeBytes int64
|
||||||
LiveRoutes int
|
LiveRoutes int
|
||||||
|
OldestRoute *time.Time
|
||||||
|
NewestRoute *time.Time
|
||||||
IPv4PrefixDistribution []PrefixDistribution
|
IPv4PrefixDistribution []PrefixDistribution
|
||||||
IPv6PrefixDistribution []PrefixDistribution
|
IPv6PrefixDistribution []PrefixDistribution
|
||||||
}
|
}
|
||||||
|
|||||||
@ -164,6 +164,8 @@ func (s *Server) handleStatusJSON() http.HandlerFunc {
|
|||||||
LiveRoutes int `json:"live_routes"`
|
LiveRoutes int `json:"live_routes"`
|
||||||
IPv4Routes int `json:"ipv4_routes"`
|
IPv4Routes int `json:"ipv4_routes"`
|
||||||
IPv6Routes int `json:"ipv6_routes"`
|
IPv6Routes int `json:"ipv6_routes"`
|
||||||
|
OldestRoute *time.Time `json:"oldest_route,omitempty"`
|
||||||
|
NewestRoute *time.Time `json:"newest_route,omitempty"`
|
||||||
IPv4UpdatesPerSec float64 `json:"ipv4_updates_per_sec"`
|
IPv4UpdatesPerSec float64 `json:"ipv4_updates_per_sec"`
|
||||||
IPv6UpdatesPerSec float64 `json:"ipv6_updates_per_sec"`
|
IPv6UpdatesPerSec float64 `json:"ipv6_updates_per_sec"`
|
||||||
IPv4PrefixDistribution []database.PrefixDistribution `json:"ipv4_prefix_distribution"`
|
IPv4PrefixDistribution []database.PrefixDistribution `json:"ipv4_prefix_distribution"`
|
||||||
@ -258,6 +260,8 @@ func (s *Server) handleStatusJSON() http.HandlerFunc {
|
|||||||
LiveRoutes: dbStats.LiveRoutes,
|
LiveRoutes: dbStats.LiveRoutes,
|
||||||
IPv4Routes: ipv4Routes,
|
IPv4Routes: ipv4Routes,
|
||||||
IPv6Routes: ipv6Routes,
|
IPv6Routes: ipv6Routes,
|
||||||
|
OldestRoute: dbStats.OldestRoute,
|
||||||
|
NewestRoute: dbStats.NewestRoute,
|
||||||
IPv4UpdatesPerSec: routeMetrics.IPv4UpdatesPerSec,
|
IPv4UpdatesPerSec: routeMetrics.IPv4UpdatesPerSec,
|
||||||
IPv6UpdatesPerSec: routeMetrics.IPv6UpdatesPerSec,
|
IPv6UpdatesPerSec: routeMetrics.IPv6UpdatesPerSec,
|
||||||
IPv4PrefixDistribution: dbStats.IPv4PrefixDistribution,
|
IPv4PrefixDistribution: dbStats.IPv4PrefixDistribution,
|
||||||
@ -369,6 +373,8 @@ func (s *Server) handleStats() http.HandlerFunc {
|
|||||||
LiveRoutes int `json:"live_routes"`
|
LiveRoutes int `json:"live_routes"`
|
||||||
IPv4Routes int `json:"ipv4_routes"`
|
IPv4Routes int `json:"ipv4_routes"`
|
||||||
IPv6Routes int `json:"ipv6_routes"`
|
IPv6Routes int `json:"ipv6_routes"`
|
||||||
|
OldestRoute *time.Time `json:"oldest_route,omitempty"`
|
||||||
|
NewestRoute *time.Time `json:"newest_route,omitempty"`
|
||||||
IPv4UpdatesPerSec float64 `json:"ipv4_updates_per_sec"`
|
IPv4UpdatesPerSec float64 `json:"ipv4_updates_per_sec"`
|
||||||
IPv6UpdatesPerSec float64 `json:"ipv6_updates_per_sec"`
|
IPv6UpdatesPerSec float64 `json:"ipv6_updates_per_sec"`
|
||||||
HandlerStats []HandlerStatsInfo `json:"handler_stats"`
|
HandlerStats []HandlerStatsInfo `json:"handler_stats"`
|
||||||
@ -530,6 +536,8 @@ func (s *Server) handleStats() http.HandlerFunc {
|
|||||||
LiveRoutes: dbStats.LiveRoutes,
|
LiveRoutes: dbStats.LiveRoutes,
|
||||||
IPv4Routes: ipv4Routes,
|
IPv4Routes: ipv4Routes,
|
||||||
IPv6Routes: ipv6Routes,
|
IPv6Routes: ipv6Routes,
|
||||||
|
OldestRoute: dbStats.OldestRoute,
|
||||||
|
NewestRoute: dbStats.NewestRoute,
|
||||||
IPv4UpdatesPerSec: routeMetrics.IPv4UpdatesPerSec,
|
IPv4UpdatesPerSec: routeMetrics.IPv4UpdatesPerSec,
|
||||||
IPv6UpdatesPerSec: routeMetrics.IPv6UpdatesPerSec,
|
IPv6UpdatesPerSec: routeMetrics.IPv6UpdatesPerSec,
|
||||||
HandlerStats: handlerStatsInfo,
|
HandlerStats: handlerStatsInfo,
|
||||||
|
|||||||
@ -321,6 +321,14 @@
|
|||||||
<span class="metric-label">IPv6 Updates/sec</span>
|
<span class="metric-label">IPv6 Updates/sec</span>
|
||||||
<span class="metric-value" id="ipv6_updates_per_sec">-</span>
|
<span class="metric-value" id="ipv6_updates_per_sec">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="metric">
|
||||||
|
<span class="metric-label">Oldest Route</span>
|
||||||
|
<span class="metric-value" id="oldest_route">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric">
|
||||||
|
<span class="metric-label">Newest Route</span>
|
||||||
|
<span class="metric-value" id="newest_route">-</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-card">
|
<div class="status-card">
|
||||||
@ -400,7 +408,23 @@
|
|||||||
return ms.toFixed(2) + ' ms';
|
return ms.toFixed(2) + ' ms';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatRelativeTime(isoString) {
|
||||||
|
if (!isoString) return '-';
|
||||||
|
const date = new Date(isoString);
|
||||||
|
const now = new Date();
|
||||||
|
const diffMs = now - date;
|
||||||
|
const diffSec = Math.floor(diffMs / 1000);
|
||||||
|
const diffMin = Math.floor(diffSec / 60);
|
||||||
|
const diffHour = Math.floor(diffMin / 60);
|
||||||
|
const diffDay = Math.floor(diffHour / 24);
|
||||||
|
|
||||||
|
if (diffSec < 60) return diffSec + 's ago';
|
||||||
|
if (diffMin < 60) return diffMin + 'm ago';
|
||||||
|
if (diffHour < 24) return diffHour + 'h ' + (diffMin % 60) + 'm ago';
|
||||||
|
return diffDay + 'd ' + (diffHour % 24) + 'h ago';
|
||||||
|
}
|
||||||
|
|
||||||
function updatePrefixDistribution(elementId, distribution) {
|
function updatePrefixDistribution(elementId, distribution) {
|
||||||
const container = document.getElementById(elementId);
|
const container = document.getElementById(elementId);
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
@ -506,6 +530,8 @@
|
|||||||
document.getElementById('ipv6_routes').textContent = '-';
|
document.getElementById('ipv6_routes').textContent = '-';
|
||||||
document.getElementById('ipv4_updates_per_sec').textContent = '-';
|
document.getElementById('ipv4_updates_per_sec').textContent = '-';
|
||||||
document.getElementById('ipv6_updates_per_sec').textContent = '-';
|
document.getElementById('ipv6_updates_per_sec').textContent = '-';
|
||||||
|
document.getElementById('oldest_route').textContent = '-';
|
||||||
|
document.getElementById('newest_route').textContent = '-';
|
||||||
document.getElementById('whois_fresh').textContent = '-';
|
document.getElementById('whois_fresh').textContent = '-';
|
||||||
document.getElementById('whois_stale').textContent = '-';
|
document.getElementById('whois_stale').textContent = '-';
|
||||||
document.getElementById('whois_never').textContent = '-';
|
document.getElementById('whois_never').textContent = '-';
|
||||||
@ -566,6 +592,8 @@
|
|||||||
document.getElementById('ipv6_routes').textContent = formatNumber(data.ipv6_routes);
|
document.getElementById('ipv6_routes').textContent = formatNumber(data.ipv6_routes);
|
||||||
document.getElementById('ipv4_updates_per_sec').textContent = data.ipv4_updates_per_sec.toFixed(1);
|
document.getElementById('ipv4_updates_per_sec').textContent = data.ipv4_updates_per_sec.toFixed(1);
|
||||||
document.getElementById('ipv6_updates_per_sec').textContent = data.ipv6_updates_per_sec.toFixed(1);
|
document.getElementById('ipv6_updates_per_sec').textContent = data.ipv6_updates_per_sec.toFixed(1);
|
||||||
|
document.getElementById('oldest_route').textContent = formatRelativeTime(data.oldest_route);
|
||||||
|
document.getElementById('newest_route').textContent = formatRelativeTime(data.newest_route);
|
||||||
|
|
||||||
// Update stream stats
|
// Update stream stats
|
||||||
if (data.stream) {
|
if (data.stream) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user