mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 12:46:57 +00:00
148 lines
4.6 KiB
Go
148 lines
4.6 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/DeBrosOfficial/network/pkg/cli/monitor"
|
|
)
|
|
|
|
// renderNodes renders the Nodes tab with detailed per-node information.
|
|
func renderNodes(snap *monitor.ClusterSnapshot, width int) string {
|
|
if snap == nil {
|
|
return styleMuted.Render("Collecting cluster data...")
|
|
}
|
|
|
|
var b strings.Builder
|
|
|
|
for i, cs := range snap.Nodes {
|
|
if i > 0 {
|
|
b.WriteString("\n")
|
|
}
|
|
|
|
host := cs.Node.Host
|
|
role := cs.Node.Role
|
|
if role == "" {
|
|
role = "node"
|
|
}
|
|
|
|
if cs.Error != nil {
|
|
b.WriteString(styleBold.Render(fmt.Sprintf("Node: %s", host)))
|
|
b.WriteString(fmt.Sprintf(" (%s)", role))
|
|
b.WriteString("\n")
|
|
b.WriteString(separator(width))
|
|
b.WriteString("\n")
|
|
b.WriteString(fmt.Sprintf(" Status: %s\n", styleCritical.Render("UNREACHABLE")))
|
|
b.WriteString(fmt.Sprintf(" Error: %s\n", styleCritical.Render(cs.Error.Error())))
|
|
b.WriteString(fmt.Sprintf(" Took: %s\n", styleMuted.Render(cs.Duration.Truncate(time.Millisecond).String())))
|
|
if cs.Retries > 0 {
|
|
b.WriteString(fmt.Sprintf(" Retries: %d\n", cs.Retries))
|
|
}
|
|
continue
|
|
}
|
|
|
|
r := cs.Report
|
|
if r == nil {
|
|
continue
|
|
}
|
|
|
|
b.WriteString(styleBold.Render(fmt.Sprintf("Node: %s", host)))
|
|
b.WriteString(fmt.Sprintf(" (%s) ", role))
|
|
b.WriteString(styleHealthy.Render("ONLINE"))
|
|
if r.Version != "" {
|
|
b.WriteString(fmt.Sprintf(" v%s", r.Version))
|
|
}
|
|
b.WriteString("\n")
|
|
b.WriteString(separator(width))
|
|
b.WriteString("\n")
|
|
|
|
// System Resources
|
|
if r.System != nil {
|
|
sys := r.System
|
|
b.WriteString(styleBold.Render(" System"))
|
|
b.WriteString("\n")
|
|
b.WriteString(fmt.Sprintf(" CPU: %d cores, load %.1f / %.1f / %.1f\n",
|
|
sys.CPUCount, sys.LoadAvg1, sys.LoadAvg5, sys.LoadAvg15))
|
|
b.WriteString(fmt.Sprintf(" Memory: %s (%d / %d MB, %d MB avail)\n",
|
|
colorPct(sys.MemUsePct), sys.MemUsedMB, sys.MemTotalMB, sys.MemAvailMB))
|
|
b.WriteString(fmt.Sprintf(" Disk: %s (%s / %s, %s avail)\n",
|
|
colorPct(sys.DiskUsePct), sys.DiskUsedGB, sys.DiskTotalGB, sys.DiskAvailGB))
|
|
if sys.SwapTotalMB > 0 {
|
|
b.WriteString(fmt.Sprintf(" Swap: %d / %d MB\n", sys.SwapUsedMB, sys.SwapTotalMB))
|
|
}
|
|
b.WriteString(fmt.Sprintf(" Uptime: %s\n", sys.UptimeSince))
|
|
if sys.OOMKills > 0 {
|
|
b.WriteString(fmt.Sprintf(" OOM: %s\n", styleCritical.Render(fmt.Sprintf("%d kills", sys.OOMKills))))
|
|
}
|
|
}
|
|
|
|
// Services
|
|
if r.Services != nil && len(r.Services.Services) > 0 {
|
|
b.WriteString(styleBold.Render(" Services"))
|
|
b.WriteString("\n")
|
|
for _, svc := range r.Services.Services {
|
|
stateStr := styleHealthy.Render(svc.ActiveState)
|
|
if svc.ActiveState == "failed" {
|
|
stateStr = styleCritical.Render("FAILED")
|
|
} else if svc.ActiveState != "active" {
|
|
stateStr = styleWarning.Render(svc.ActiveState)
|
|
}
|
|
extra := ""
|
|
if svc.MemoryCurrentMB > 0 {
|
|
extra += fmt.Sprintf(" mem=%dMB", svc.MemoryCurrentMB)
|
|
}
|
|
if svc.NRestarts > 0 {
|
|
extra += fmt.Sprintf(" restarts=%d", svc.NRestarts)
|
|
}
|
|
if svc.RestartLoopRisk {
|
|
extra += styleCritical.Render(" RESTART-LOOP")
|
|
}
|
|
b.WriteString(fmt.Sprintf(" %-28s %s%s\n", svc.Name, stateStr, extra))
|
|
}
|
|
if len(r.Services.FailedUnits) > 0 {
|
|
b.WriteString(fmt.Sprintf(" Failed units: %s\n",
|
|
styleCritical.Render(strings.Join(r.Services.FailedUnits, ", "))))
|
|
}
|
|
}
|
|
|
|
// RQLite
|
|
if r.RQLite != nil {
|
|
rq := r.RQLite
|
|
b.WriteString(styleBold.Render(" RQLite"))
|
|
b.WriteString("\n")
|
|
b.WriteString(fmt.Sprintf(" Responsive: %s Ready: %s Strong Read: %s\n",
|
|
statusStr(rq.Responsive), statusStr(rq.Ready), statusStr(rq.StrongRead)))
|
|
if rq.Responsive {
|
|
b.WriteString(fmt.Sprintf(" Raft: %s Leader: %s Term: %d Applied: %d\n",
|
|
styleBold.Render(rq.RaftState), rq.LeaderAddr, rq.Term, rq.Applied))
|
|
if rq.DBSize != "" {
|
|
b.WriteString(fmt.Sprintf(" DB size: %s Peers: %d Goroutines: %d Heap: %dMB\n",
|
|
rq.DBSize, rq.NumPeers, rq.Goroutines, rq.HeapMB))
|
|
}
|
|
}
|
|
}
|
|
|
|
// WireGuard
|
|
if r.WireGuard != nil {
|
|
wg := r.WireGuard
|
|
b.WriteString(styleBold.Render(" WireGuard"))
|
|
b.WriteString("\n")
|
|
b.WriteString(fmt.Sprintf(" Interface: %s IP: %s Peers: %d\n",
|
|
statusStr(wg.InterfaceUp), wg.WgIP, wg.PeerCount))
|
|
}
|
|
|
|
// Network
|
|
if r.Network != nil {
|
|
net := r.Network
|
|
b.WriteString(styleBold.Render(" Network"))
|
|
b.WriteString("\n")
|
|
b.WriteString(fmt.Sprintf(" Internet: %s UFW: %s TCP est: %d retrans: %.1f%%\n",
|
|
statusStr(net.InternetReachable), statusStr(net.UFWActive),
|
|
net.TCPEstablished, net.TCPRetransRate))
|
|
}
|
|
}
|
|
|
|
return b.String()
|
|
}
|