Add handler queue metrics to status page
- Add GetHandlerStats() method to streamer to expose handler metrics - Include queue length/capacity, processed/dropped counts, timing stats - Update API to include handler_stats in response - Add dynamic handler stats display to status page HTML - Shows separate status box for each handler with all metrics
This commit is contained in:
parent
6593a7be76
commit
1a0622efaa
@ -232,25 +232,38 @@ func (s *Server) handleStatusJSON() http.HandlerFunc {
|
||||
|
||||
// handleStats returns a handler that serves API v1 statistics
|
||||
func (s *Server) handleStats() http.HandlerFunc {
|
||||
// HandlerStatsInfo represents handler statistics in the API response
|
||||
type HandlerStatsInfo struct {
|
||||
Name string `json:"name"`
|
||||
QueueLength int `json:"queue_length"`
|
||||
QueueCapacity int `json:"queue_capacity"`
|
||||
ProcessedCount uint64 `json:"processed_count"`
|
||||
DroppedCount uint64 `json:"dropped_count"`
|
||||
AvgProcessTimeMs float64 `json:"avg_process_time_ms"`
|
||||
MinProcessTimeMs float64 `json:"min_process_time_ms"`
|
||||
MaxProcessTimeMs float64 `json:"max_process_time_ms"`
|
||||
}
|
||||
|
||||
// StatsResponse represents the API statistics response
|
||||
type StatsResponse struct {
|
||||
Uptime string `json:"uptime"`
|
||||
TotalMessages uint64 `json:"total_messages"`
|
||||
TotalBytes uint64 `json:"total_bytes"`
|
||||
MessagesPerSec float64 `json:"messages_per_sec"`
|
||||
MbitsPerSec float64 `json:"mbits_per_sec"`
|
||||
Connected bool `json:"connected"`
|
||||
ASNs int `json:"asns"`
|
||||
Prefixes int `json:"prefixes"`
|
||||
IPv4Prefixes int `json:"ipv4_prefixes"`
|
||||
IPv6Prefixes int `json:"ipv6_prefixes"`
|
||||
Peerings int `json:"peerings"`
|
||||
DatabaseSizeBytes int64 `json:"database_size_bytes"`
|
||||
LiveRoutes int `json:"live_routes"`
|
||||
IPv4Routes int `json:"ipv4_routes"`
|
||||
IPv6Routes int `json:"ipv6_routes"`
|
||||
IPv4UpdatesPerSec float64 `json:"ipv4_updates_per_sec"`
|
||||
IPv6UpdatesPerSec float64 `json:"ipv6_updates_per_sec"`
|
||||
Uptime string `json:"uptime"`
|
||||
TotalMessages uint64 `json:"total_messages"`
|
||||
TotalBytes uint64 `json:"total_bytes"`
|
||||
MessagesPerSec float64 `json:"messages_per_sec"`
|
||||
MbitsPerSec float64 `json:"mbits_per_sec"`
|
||||
Connected bool `json:"connected"`
|
||||
ASNs int `json:"asns"`
|
||||
Prefixes int `json:"prefixes"`
|
||||
IPv4Prefixes int `json:"ipv4_prefixes"`
|
||||
IPv6Prefixes int `json:"ipv6_prefixes"`
|
||||
Peerings int `json:"peerings"`
|
||||
DatabaseSizeBytes int64 `json:"database_size_bytes"`
|
||||
LiveRoutes int `json:"live_routes"`
|
||||
IPv4Routes int `json:"ipv4_routes"`
|
||||
IPv6Routes int `json:"ipv6_routes"`
|
||||
IPv4UpdatesPerSec float64 `json:"ipv4_updates_per_sec"`
|
||||
IPv6UpdatesPerSec float64 `json:"ipv6_updates_per_sec"`
|
||||
HandlerStats []HandlerStatsInfo `json:"handler_stats"`
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
@ -312,6 +325,23 @@ func (s *Server) handleStats() http.HandlerFunc {
|
||||
// Get detailed routing table stats
|
||||
rtStats := s.routingTable.GetDetailedStats()
|
||||
|
||||
// Get handler stats
|
||||
handlerStats := s.streamer.GetHandlerStats()
|
||||
handlerStatsInfo := make([]HandlerStatsInfo, 0, len(handlerStats))
|
||||
const microsecondsPerMillisecond = 1000.0
|
||||
for _, hs := range handlerStats {
|
||||
handlerStatsInfo = append(handlerStatsInfo, HandlerStatsInfo{
|
||||
Name: hs.Name,
|
||||
QueueLength: hs.QueueLength,
|
||||
QueueCapacity: hs.QueueCapacity,
|
||||
ProcessedCount: hs.ProcessedCount,
|
||||
DroppedCount: hs.DroppedCount,
|
||||
AvgProcessTimeMs: float64(hs.AvgProcessTime.Microseconds()) / microsecondsPerMillisecond,
|
||||
MinProcessTimeMs: float64(hs.MinProcessTime.Microseconds()) / microsecondsPerMillisecond,
|
||||
MaxProcessTimeMs: float64(hs.MaxProcessTime.Microseconds()) / microsecondsPerMillisecond,
|
||||
})
|
||||
}
|
||||
|
||||
stats := StatsResponse{
|
||||
Uptime: uptime,
|
||||
TotalMessages: metrics.TotalMessages,
|
||||
@ -330,6 +360,7 @@ func (s *Server) handleStats() http.HandlerFunc {
|
||||
IPv6Routes: rtStats.IPv6Routes,
|
||||
IPv4UpdatesPerSec: rtStats.IPv4UpdatesRate,
|
||||
IPv6UpdatesPerSec: rtStats.IPv6UpdatesRate,
|
||||
HandlerStats: handlerStatsInfo,
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
@ -195,6 +195,57 @@ func (s *Streamer) GetMetrics() metrics.StreamMetrics {
|
||||
return s.metrics.GetStreamMetrics()
|
||||
}
|
||||
|
||||
// HandlerStats represents metrics for a single handler
|
||||
type HandlerStats struct {
|
||||
Name string
|
||||
QueueLength int
|
||||
QueueCapacity int
|
||||
ProcessedCount uint64
|
||||
DroppedCount uint64
|
||||
AvgProcessTime time.Duration
|
||||
MinProcessTime time.Duration
|
||||
MaxProcessTime time.Duration
|
||||
}
|
||||
|
||||
// GetHandlerStats returns current handler statistics
|
||||
func (s *Streamer) GetHandlerStats() []HandlerStats {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
stats := make([]HandlerStats, 0, len(s.handlers))
|
||||
|
||||
for _, info := range s.handlers {
|
||||
info.metrics.mu.Lock()
|
||||
|
||||
hs := HandlerStats{
|
||||
Name: fmt.Sprintf("%T", info.handler),
|
||||
QueueLength: len(info.queue),
|
||||
QueueCapacity: cap(info.queue),
|
||||
ProcessedCount: info.metrics.processedCount,
|
||||
DroppedCount: info.metrics.droppedCount,
|
||||
MinProcessTime: info.metrics.minTime,
|
||||
MaxProcessTime: info.metrics.maxTime,
|
||||
}
|
||||
|
||||
// Calculate average time
|
||||
if info.metrics.processedCount > 0 {
|
||||
processedCount := info.metrics.processedCount
|
||||
const maxInt64 = 1<<63 - 1
|
||||
if processedCount > maxInt64 {
|
||||
processedCount = maxInt64
|
||||
}
|
||||
//nolint:gosec // processedCount is explicitly bounded above
|
||||
hs.AvgProcessTime = info.metrics.totalTime / time.Duration(processedCount)
|
||||
}
|
||||
|
||||
info.metrics.mu.Unlock()
|
||||
|
||||
stats = append(stats, hs)
|
||||
}
|
||||
|
||||
return stats
|
||||
}
|
||||
|
||||
// GetDroppedMessages returns the total number of dropped messages
|
||||
func (s *Streamer) GetDroppedMessages() uint64 {
|
||||
return atomic.LoadUint64(&s.totalDropped)
|
||||
|
@ -153,6 +153,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="handler-stats-container" class="status-grid">
|
||||
<!-- Handler stats will be dynamically added here -->
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function formatBytes(bytes) {
|
||||
if (bytes === 0) return '0 B';
|
||||
@ -166,6 +170,45 @@
|
||||
return num.toLocaleString();
|
||||
}
|
||||
|
||||
function updateHandlerStats(handlerStats) {
|
||||
const container = document.getElementById('handler-stats-container');
|
||||
container.innerHTML = '';
|
||||
|
||||
handlerStats.forEach(handler => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'status-card';
|
||||
|
||||
// Extract handler name (remove package prefix)
|
||||
const handlerName = handler.name.split('.').pop();
|
||||
|
||||
card.innerHTML = `
|
||||
<h2>${handlerName}</h2>
|
||||
<div class="metric">
|
||||
<span class="metric-label">Queue</span>
|
||||
<span class="metric-value">${handler.queue_length}/${handler.queue_capacity}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-label">Processed</span>
|
||||
<span class="metric-value">${formatNumber(handler.processed_count)}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-label">Dropped</span>
|
||||
<span class="metric-value ${handler.dropped_count > 0 ? 'disconnected' : ''}">${formatNumber(handler.dropped_count)}</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-label">Avg Time</span>
|
||||
<span class="metric-value">${handler.avg_process_time_ms.toFixed(2)} ms</span>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<span class="metric-label">Min/Max Time</span>
|
||||
<span class="metric-value">${handler.min_process_time_ms.toFixed(2)} / ${handler.max_process_time_ms.toFixed(2)} ms</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
function updateStatus() {
|
||||
fetch('/api/v1/stats')
|
||||
.then(response => response.json())
|
||||
@ -203,6 +246,9 @@
|
||||
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);
|
||||
|
||||
// Update handler stats
|
||||
updateHandlerStats(data.handler_stats || []);
|
||||
|
||||
// Clear any errors
|
||||
document.getElementById('error').style.display = 'none';
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user