diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 791df47..4a8a32e 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -15,6 +15,7 @@ type Tracker struct { registry metrics.Registry connectedSince time.Time isConnected atomic.Bool + reconnectCount atomic.Uint64 // Stream metrics (decompressed data) messageCounter metrics.Counter @@ -50,14 +51,23 @@ func New() *Tracker { // SetConnected updates the connection status func (t *Tracker) SetConnected(connected bool) { - t.isConnected.Store(connected) + wasConnected := t.isConnected.Swap(connected) if connected { t.mu.Lock() t.connectedSince = time.Now() t.mu.Unlock() + // Increment reconnect count (but not for the initial connection) + if wasConnected || t.reconnectCount.Load() > 0 { + t.reconnectCount.Add(1) + } } } +// GetReconnectCount returns the number of reconnections since startup +func (t *Tracker) GetReconnectCount() uint64 { + return t.reconnectCount.Load() +} + // IsConnected returns the current connection status func (t *Tracker) IsConnected() bool { return t.isConnected.Load() @@ -110,6 +120,7 @@ func (t *Tracker) GetStreamMetrics() StreamMetrics { MessagesPerSec: t.messageRate.Rate1(), BitsPerSec: t.byteRate.Rate1() * bitsPerByte, WireBitsPerSec: t.wireByteRate.Rate1() * bitsPerByte, + ReconnectCount: t.reconnectCount.Load(), } } @@ -149,6 +160,8 @@ type StreamMetrics struct { BitsPerSec float64 // WireBitsPerSec is the rate of bits received on the wire per second (1-minute average) WireBitsPerSec float64 + // ReconnectCount is the number of reconnections since startup + ReconnectCount uint64 } // RouteMetrics contains route update statistics diff --git a/internal/server/handlers.go b/internal/server/handlers.go index 61b0208..c502996 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -330,6 +330,8 @@ func (s *Server) handleStats() http.HandlerFunc { 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"` @@ -442,6 +444,12 @@ func (s *Server) handleStats() http.HandlerFunc { whoisStats = s.getWHOISStats(ctx) } + // Calculate connection duration + connectionDuration := "disconnected" + if metrics.Connected && !metrics.ConnectedSince.IsZero() { + connectionDuration = time.Since(metrics.ConnectedSince).Truncate(time.Second).String() + } + stats := StatsResponse{ Uptime: uptime, TotalMessages: metrics.TotalMessages, @@ -451,6 +459,8 @@ func (s *Server) handleStats() http.HandlerFunc { MbitsPerSec: metrics.BitsPerSec / bitsPerMegabit, WireMbitsPerSec: metrics.WireBitsPerSec / bitsPerMegabit, Connected: metrics.Connected, + ConnectionDuration: connectionDuration, + ReconnectCount: metrics.ReconnectCount, GoVersion: runtime.Version(), Goroutines: runtime.NumGoroutine(), MemoryUsage: humanize.Bytes(memStats.Alloc), diff --git a/internal/templates/status.html b/internal/templates/status.html index 578bb67..5225c90 100644 --- a/internal/templates/status.html +++ b/internal/templates/status.html @@ -104,6 +104,14 @@

Stream Statistics

+
+ Connection Duration + - +
+
+ Reconnections + - +
Total Messages - @@ -334,6 +342,8 @@ document.getElementById('go_version').textContent = '-'; document.getElementById('goroutines').textContent = '-'; document.getElementById('memory_usage').textContent = '-'; + document.getElementById('connection_duration').textContent = '-'; + document.getElementById('reconnect_count').textContent = '-'; document.getElementById('total_messages').textContent = '-'; document.getElementById('messages_per_sec').textContent = '-'; document.getElementById('total_wire_bytes').textContent = '-'; @@ -392,6 +402,8 @@ document.getElementById('go_version').textContent = data.go_version; document.getElementById('goroutines').textContent = formatNumber(data.goroutines); document.getElementById('memory_usage').textContent = data.memory_usage; + document.getElementById('connection_duration').textContent = data.connection_duration; + document.getElementById('reconnect_count').textContent = formatNumber(data.reconnect_count); document.getElementById('total_messages').textContent = formatNumber(data.total_messages); document.getElementById('messages_per_sec').textContent = data.messages_per_sec.toFixed(1); document.getElementById('total_wire_bytes').textContent = formatBytes(data.total_wire_bytes);