diff --git a/VERSION b/VERSION index d388d61..a8646df 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.47 +1.1.48 diff --git a/internal/handlers/haproxy_stats.go b/internal/handlers/haproxy_stats.go index 1c1a3a1..8b6dcef 100644 --- a/internal/handlers/haproxy_stats.go +++ b/internal/handlers/haproxy_stats.go @@ -32,14 +32,16 @@ const haproxyAdminSock = "/run/haproxy/admin.sock" // 'show stat' CSV. We only emit the fields the dashboard cares // about — full CSV is ~80 columns of which 90% are noise here. type backendStat struct { - Backend string `json:"backend"` // pxname - Server string `json:"server"` // svname - Status string `json:"status"` // UP|DOWN|MAINT|... - Sessions int64 `json:"sessions"` // current sessions (scur) - BIn int64 `json:"bytes_in"` - BOut int64 `json:"bytes_out"` - LastChg int64 `json:"last_change_sec"` // seconds since last status change - Health string `json:"health,omitempty"` // check_status (e.g. L7OK) + Backend string `json:"backend"` // pxname + Server string `json:"server"` // svname + Status string `json:"status"` // UP|DOWN|MAINT|... + Sessions int64 `json:"sessions"` // current sessions (scur) + BIn int64 `json:"bytes_in"` + BOut int64 `json:"bytes_out"` + ReqTot int64 `json:"req_tot"` // total requests since start (req_tot) + ReqRate int64 `json:"req_rate"` // requests/s last second (req_rate, server-level) + LastChg int64 `json:"last_change_sec"` // seconds since last status change + Health string `json:"health,omitempty"` // check_status (e.g. L7OK) } func (h *HAProxyStatsHandler) Stats(c *gin.Context) { @@ -97,6 +99,8 @@ func (h *HAProxyStatsHandler) Stats(c *gin.Context) { Sessions: parseInt64(safeAt(fields, colIdx["scur"])), BIn: parseInt64(safeAt(fields, colIdx["bin"])), BOut: parseInt64(safeAt(fields, colIdx["bout"])), + ReqTot: parseInt64(safeAt(fields, colIdx["req_tot"])), + ReqRate: parseInt64(safeAt(fields, colIdx["req_rate"])), LastChg: parseInt64(safeAt(fields, colIdx["lastchg"])), Health: safeAt(fields, colIdx["check_status"]), } diff --git a/management-ui/src/pages/Backends/Detail.tsx b/management-ui/src/pages/Backends/Detail.tsx index 21270c3..a8b3530 100644 --- a/management-ui/src/pages/Backends/Detail.tsx +++ b/management-ui/src/pages/Backends/Detail.tsx @@ -59,6 +59,7 @@ async function listDomains(): Promise { interface HAProxyStat { backend: string; server: string; status: string sessions: number; bytes_in: number; bytes_out: number + req_tot: number; req_rate: number last_change_sec: number; health: string } async function listHAProxyStats(): Promise { @@ -289,9 +290,11 @@ function ServerPanel({ backendID, haproxyStats }: { backendID: number; haproxySt if (!stat) return const color = stat.status === 'UP' ? 'green' : stat.status === 'no check' ? 'default' : 'red' return ( - + {stat.status} - {stat.sessions} sess + + {stat.sessions} sess{stat.req_rate > 0 ? ` · ${stat.req_rate}/s` : ''} + ) }, diff --git a/management-ui/src/pages/Dashboard/index.tsx b/management-ui/src/pages/Dashboard/index.tsx index ff28a1e..bab3ebe 100644 --- a/management-ui/src/pages/Dashboard/index.tsx +++ b/management-ui/src/pages/Dashboard/index.tsx @@ -101,6 +101,7 @@ interface AuditEntry { interface HAProxyBackend { backend: string; server: string; status: string sessions: number; bytes_in: number; bytes_out: number + req_tot: number; req_rate: number last_change_sec: number; health?: string } @@ -407,7 +408,7 @@ export default function DashboardPage() { style={{ margin: 0, fontSize: 10 }} >{b.status} - {b.sessions} sess · ↓{formatBytes(b.bytes_in)} ↑{formatBytes(b.bytes_out)} + {b.sessions} sess{b.req_rate > 0 ? ` · ${b.req_rate}/s` : ''} · ↓{formatBytes(b.bytes_in)} ↑{formatBytes(b.bytes_out)} {formatUptime(b.last_change_sec)}