feat(cron): include top 3 processes in CPU/RAM alert Telegram messages

When CPU or RAM exceeds the threshold, the alert now lists the top 3
processes sorted by the relevant metric (CPU% or RAM MB).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-25 10:53:43 -05:00
co-authored by Claude Sonnet 4.6
parent 73fe73b04f
commit 4b98161070
+34 -7
View File
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"log"
"sort"
"strconv"
"time"
@@ -11,6 +12,12 @@ import (
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
)
type cronProcInfo struct {
Nombre string `json:"nombre"`
CPU float64 `json:"cpu"`
RAMMB float64 `json:"ram_mb"`
}
var cronScheduler *cron.Cron
// IniciarCron arranca el scheduler de tareas. Llamar desde app.go o main.go.
@@ -257,16 +264,17 @@ func VerificarSaludServidores() {
Porcentaje float64 `json:"porcentaje"`
Ruta string `json:"ruta"`
} `json:"discos"`
TopProcs []cronProcInfo `json:"top_procs"`
}
if jsonErr := json.Unmarshal([]byte(srv.MetricasJson), &m); jsonErr == nil {
checkRecurso(srv.Nombre, "CPU", m.CPU.Porcentaje, cfg.UmbralCPU)
checkRecurso(srv.Nombre, "RAM", m.RAM.Porcentaje, cfg.UmbralRAM)
checkRecurso(srv.Nombre, "CPU", m.CPU.Porcentaje, cfg.UmbralCPU, m.TopProcs, "cpu")
checkRecurso(srv.Nombre, "RAM", m.RAM.Porcentaje, cfg.UmbralRAM, m.TopProcs, "ram")
for _, d := range m.Discos {
label := "Disco"
if d.Ruta != "" && d.Ruta != "/" {
label = "Disco " + d.Ruta
}
checkRecurso(srv.Nombre, label, d.Porcentaje, cfg.UmbralDisco)
checkRecurso(srv.Nombre, label, d.Porcentaje, cfg.UmbralDisco, nil, "")
}
}
}
@@ -292,15 +300,34 @@ func VerificarSaludServidores() {
}
}
func checkRecurso(nombre, recurso string, valor float64, umbral int) {
func checkRecurso(nombre, recurso string, valor float64, umbral int, procs []cronProcInfo, ordenar string) {
if valor < float64(umbral) {
return
}
titulo := fmt.Sprintf("⚠️ %s alto en %s (%.0f%%)", recurso, nombre, valor)
if !models.YaExisteAlertaServidor(titulo, 1) {
crearNotifServidor(titulo,
fmt.Sprintf("%s al %.0f%% (umbral: %d%%)", recurso, valor, umbral),
"servidor_recurso_alto")
cuerpo := fmt.Sprintf("%s al %.0f%% (umbral: %d%%)", recurso, valor, umbral)
if len(procs) > 0 {
cp := make([]cronProcInfo, len(procs))
copy(cp, procs)
if ordenar == "cpu" {
sort.Slice(cp, func(i, j int) bool { return cp[i].CPU > cp[j].CPU })
} else {
sort.Slice(cp, func(i, j int) bool { return cp[i].RAMMB > cp[j].RAMMB })
}
if len(cp) > 3 {
cp = cp[:3]
}
cuerpo += "\n\nTop procesos:"
for i, p := range cp {
if ordenar == "cpu" {
cuerpo += fmt.Sprintf("\n%d. %s — CPU: %.1f%%, RAM: %.0f MB", i+1, p.Nombre, p.CPU, p.RAMMB)
} else {
cuerpo += fmt.Sprintf("\n%d. %s — RAM: %.0f MB, CPU: %.1f%%", i+1, p.Nombre, p.RAMMB, p.CPU)
}
}
}
crearNotifServidor(titulo, cuerpo, "servidor_recurso_alto")
}
}