No One Can Stop Me Now
This commit is contained in:
126
services/setec-manager/internal/handlers/monitor.go
Normal file
126
services/setec-manager/internal/handlers/monitor.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"setec-manager/internal/deploy"
|
||||
"setec-manager/internal/system"
|
||||
)
|
||||
|
||||
func (h *Handler) MonitorPage(w http.ResponseWriter, r *http.Request) {
|
||||
h.render(w, "monitor.html", nil)
|
||||
}
|
||||
|
||||
func (h *Handler) MonitorCPU(w http.ResponseWriter, r *http.Request) {
|
||||
cpu, err := system.GetCPUUsage()
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusOK, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Build a summary line matching the previous top-style format.
|
||||
sysPct := 0.0
|
||||
userPct := cpu.Overall
|
||||
if len(cpu.Cores) > 0 {
|
||||
// Use aggregate core data for a more accurate breakdown
|
||||
var totalUser, totalSys float64
|
||||
for _, c := range cpu.Cores {
|
||||
totalUser += c.User
|
||||
totalSys += c.System
|
||||
}
|
||||
userPct = totalUser / float64(len(cpu.Cores))
|
||||
sysPct = totalSys / float64(len(cpu.Cores))
|
||||
}
|
||||
cpuLine := fmt.Sprintf("%%Cpu(s): %.1f us, %.1f sy, %.1f id",
|
||||
userPct, sysPct, cpu.Idle)
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"cpu": cpuLine,
|
||||
"overall": cpu.Overall,
|
||||
"idle": cpu.Idle,
|
||||
"cores": cpu.Cores,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) MonitorMemory(w http.ResponseWriter, r *http.Request) {
|
||||
mem, err := system.GetMemory()
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusOK, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"total": mem.Total,
|
||||
"used": mem.Used,
|
||||
"free": mem.Free,
|
||||
"available": mem.Available,
|
||||
"swap_total": mem.SwapTotal,
|
||||
"swap_used": mem.SwapUsed,
|
||||
"swap_free": mem.SwapFree,
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (h *Handler) MonitorDisk(w http.ResponseWriter, r *http.Request) {
|
||||
disks, err := system.GetDisk()
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusOK, []interface{}{})
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, disks)
|
||||
}
|
||||
|
||||
func (h *Handler) MonitorServices(w http.ResponseWriter, r *http.Request) {
|
||||
services := []string{"nginx", "autarch-web", "autarch-dns", "setec-manager", "ufw"}
|
||||
|
||||
type svcStatus struct {
|
||||
Name string `json:"name"`
|
||||
Active string `json:"active"`
|
||||
Running bool `json:"running"`
|
||||
Memory string `json:"memory"`
|
||||
}
|
||||
|
||||
var statuses []svcStatus
|
||||
for _, svc := range services {
|
||||
ss := svcStatus{Name: svc}
|
||||
active, err := deploy.IsActive(svc)
|
||||
if err == nil && active {
|
||||
ss.Active = "active"
|
||||
ss.Running = true
|
||||
} else {
|
||||
ss.Active = "inactive"
|
||||
ss.Running = false
|
||||
}
|
||||
|
||||
// Get memory usage — no wrapper exists for this property, so use exec
|
||||
if ss.Running {
|
||||
out, err := exec.Command("systemctl", "show", svc, "--property=MemoryCurrent").Output()
|
||||
if err == nil {
|
||||
parts := strings.SplitN(string(out), "=", 2)
|
||||
if len(parts) == 2 {
|
||||
val := strings.TrimSpace(parts[1])
|
||||
if val != "[not set]" && val != "" {
|
||||
bytes := parseUint64(val)
|
||||
ss.Memory = formatBytes(float64(bytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statuses = append(statuses, ss)
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, statuses)
|
||||
}
|
||||
|
||||
// parseUint64 is a helper that returns 0 on failure.
|
||||
func parseUint64(s string) uint64 {
|
||||
var n uint64
|
||||
fmt.Sscanf(s, "%d", &n)
|
||||
return n
|
||||
}
|
||||
Reference in New Issue
Block a user