up
This commit is contained in:
+33
-5
@@ -53,7 +53,7 @@ type Metricas struct {
|
|||||||
UptimeStr string `json:"uptime"`
|
UptimeStr string `json:"uptime"`
|
||||||
RAM RAMInfo `json:"ram"`
|
RAM RAMInfo `json:"ram"`
|
||||||
CPU CPUInfo `json:"cpu"`
|
CPU CPUInfo `json:"cpu"`
|
||||||
Disco DiscoInfo `json:"disco"`
|
Discos []DiscoInfo `json:"discos"`
|
||||||
LoadAvg LoadInfo `json:"load_avg"`
|
LoadAvg LoadInfo `json:"load_avg"`
|
||||||
ReportadoEn string `json:"reportado_en"`
|
ReportadoEn string `json:"reportado_en"`
|
||||||
}
|
}
|
||||||
@@ -136,19 +136,47 @@ func collectMetrics() (*Metricas, error) {
|
|||||||
m.CPU.Porcentaje = round2(pcts[0])
|
m.CPU.Porcentaje = round2(pcts[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disco (raíz /)
|
// Discos: todas las particiones físicas/reales
|
||||||
|
if parts, err := disk.Partitions(false); err == nil {
|
||||||
|
gb := 1024.0 * 1024 * 1024
|
||||||
|
skipFSTypes := map[string]bool{
|
||||||
|
"proc": true, "sysfs": true, "tmpfs": true, "devtmpfs": true,
|
||||||
|
"devpts": true, "cgroup": true, "cgroup2": true, "overlay": true,
|
||||||
|
"hugetlbfs": true, "mqueue": true, "pstore": true, "securityfs": true,
|
||||||
|
"debugfs": true, "tracefs": true, "autofs": true, "fusectl": true,
|
||||||
|
"configfs": true, "efivarfs": true, "bpf": true, "rpc_pipefs": true,
|
||||||
|
"squashfs": true, "ramfs": true, "nsfs": true, "none": true,
|
||||||
|
}
|
||||||
|
for _, p := range parts {
|
||||||
|
if skipFSTypes[p.Fstype] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d, err := disk.Usage(p.Mountpoint); err == nil {
|
||||||
|
m.Discos = append(m.Discos, DiscoInfo{
|
||||||
|
TotalGB: round2(float64(d.Total) / gb),
|
||||||
|
UsadoGB: round2(float64(d.Used) / gb),
|
||||||
|
LibreGB: round2(float64(d.Free) / gb),
|
||||||
|
Porcentaje: round2(d.UsedPercent),
|
||||||
|
Ruta: p.Mountpoint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback: si no se encontraron particiones, usar raíz
|
||||||
|
if len(m.Discos) == 0 {
|
||||||
root := "/"
|
root := "/"
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
root = "C:\\"
|
root = "C:\\"
|
||||||
}
|
}
|
||||||
if d, err := disk.Usage(root); err == nil {
|
if d, err := disk.Usage(root); err == nil {
|
||||||
gb := 1024.0 * 1024 * 1024
|
gb := 1024.0 * 1024 * 1024
|
||||||
m.Disco = DiscoInfo{
|
m.Discos = []DiscoInfo{{
|
||||||
TotalGB: round2(float64(d.Total) / gb),
|
TotalGB: round2(float64(d.Total) / gb),
|
||||||
UsadoGB: round2(float64(d.Used) / gb),
|
UsadoGB: round2(float64(d.Used) / gb),
|
||||||
LibreGB: round2(float64(d.Free) / gb),
|
LibreGB: round2(float64(d.Free) / gb),
|
||||||
Porcentaje: round2(d.UsedPercent),
|
Porcentaje: round2(d.UsedPercent),
|
||||||
Ruta: root,
|
Ruta: root,
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,8 +276,8 @@ func main() {
|
|||||||
if err := sendHeartbeat(cfg, m); err != nil {
|
if err := sendHeartbeat(cfg, m); err != nil {
|
||||||
log.Printf("⚠️ Error enviando heartbeat: %v", err)
|
log.Printf("⚠️ Error enviando heartbeat: %v", err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("✅ Heartbeat enviado | RAM: %.1f%% | CPU: %.1f%% | Disco: %.1f%%",
|
log.Printf("✅ Heartbeat enviado | RAM: %.1f%% | CPU: %.1f%% | Discos: %d",
|
||||||
m.RAM.Porcentaje, m.CPU.Porcentaje, m.Disco.Porcentaje)
|
m.RAM.Porcentaje, m.CPU.Porcentaje, len(m.Discos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,18 +85,29 @@
|
|||||||
:style="'width:' + Math.min(m.cpu?.porcentaje, 100) + '%'"></div>
|
:style="'width:' + Math.min(m.cpu?.porcentaje, 100) + '%'"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Disco -->
|
<!-- Discos -->
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between text-xs mb-1">
|
<div class="flex justify-between text-xs mb-1">
|
||||||
<span class="text-slate-500 font-medium">💾 Disco</span>
|
<span class="text-slate-500 font-medium">💾 Discos</span>
|
||||||
<span class="font-mono font-bold text-slate-700"
|
<span class="font-mono font-bold text-slate-700" x-text="(m.discos || []).length"></span>
|
||||||
x-text="m.disco?.usado_gb + ' / ' + m.disco?.total_gb + ' GB (' + m.disco?.porcentaje + '%)'"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-slate-100 rounded-full h-1.5">
|
<template x-for="d in (m.discos || []).slice(0, 3)" :key="d.ruta">
|
||||||
<div class="h-1.5 rounded-full transition-all"
|
<div class="mb-1.5">
|
||||||
:class="m.disco?.porcentaje > 85 ? 'bg-red-500' : m.disco?.porcentaje > 65 ? 'bg-amber-400' : 'bg-indigo-500'"
|
<div class="flex justify-between text-xs mb-0.5">
|
||||||
:style="'width:' + Math.min(m.disco?.porcentaje, 100) + '%'"></div>
|
<span class="text-slate-400 font-mono text-[10px]" x-text="d.ruta"></span>
|
||||||
|
<span class="font-mono font-bold text-slate-700 text-[10px]"
|
||||||
|
x-text="d.usado_gb + ' / ' + d.total_gb + ' GB (' + d.porcentaje + '%)'"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="w-full bg-slate-100 rounded-full h-1">
|
||||||
|
<div class="h-1 rounded-full transition-all"
|
||||||
|
:class="d.porcentaje > 85 ? 'bg-red-500' : d.porcentaje > 65 ? 'bg-amber-400' : 'bg-indigo-500'"
|
||||||
|
:style="'width:' + Math.min(d.porcentaje, 100) + '%'"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template x-if="(m.discos || []).length > 3">
|
||||||
|
<p class="text-[10px] text-slate-400 mt-0.5" x-text="'+' + (m.discos.length - 3) + ' más'"></p>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<!-- Uptime + OS -->
|
<!-- Uptime + OS -->
|
||||||
<div class="flex justify-between text-xs text-slate-400 pt-1 border-t border-slate-100">
|
<div class="flex justify-between text-xs text-slate-400 pt-1 border-t border-slate-100">
|
||||||
@@ -428,9 +439,9 @@
|
|||||||
<p class="text-slate-500" x-text="m.cpu?.nucleos + ' núcleos'"></p>
|
<p class="text-slate-500" x-text="m.cpu?.nucleos + ' núcleos'"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white rounded-lg p-2 text-center border">
|
<div class="bg-white rounded-lg p-2 text-center border">
|
||||||
<p class="text-slate-400">Disco</p>
|
<p class="text-slate-400">Discos</p>
|
||||||
<p class="font-bold text-slate-800" x-text="m.disco?.porcentaje + '%'"></p>
|
<p class="font-bold text-slate-800" x-text="(m.discos || []).length"></p>
|
||||||
<p class="text-slate-500" x-text="m.disco?.usado_gb + '/' + m.disco?.total_gb + 'GB'"></p>
|
<p class="text-slate-500 text-[10px] leading-tight" x-text="(m.discos || []).map(d => d.ruta + ' ' + d.porcentaje + '%').join(' | ')"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -48,28 +48,39 @@ func AgentHeartbeat(c *fiber.Ctx) error {
|
|||||||
type agentCPU struct {
|
type agentCPU struct {
|
||||||
Nucleos int `json:"nucleos"`
|
Nucleos int `json:"nucleos"`
|
||||||
}
|
}
|
||||||
type agentDisco struct {
|
var rawMap map[string]any
|
||||||
TotalGB float64 `json:"total_gb"`
|
if jsonErr := json.Unmarshal([]byte(req.Metricas), &rawMap); jsonErr == nil {
|
||||||
|
if os, _ := rawMap["os"].(string); os != "" {
|
||||||
|
updates["so"] = os
|
||||||
}
|
}
|
||||||
type agentPayload struct {
|
if ram, _ := rawMap["ram"].(map[string]any); ram != nil {
|
||||||
OS string `json:"os"`
|
if total, _ := ram["total_gb"].(float64); total > 0 {
|
||||||
RAM agentRAM `json:"ram"`
|
updates["ram"] = fmt.Sprintf("%.0f GB", total)
|
||||||
CPU agentCPU `json:"cpu"`
|
|
||||||
Disco agentDisco `json:"disco"`
|
|
||||||
}
|
}
|
||||||
var m agentPayload
|
|
||||||
if jsonErr := json.Unmarshal([]byte(req.Metricas), &m); jsonErr == nil {
|
|
||||||
if m.OS != "" {
|
|
||||||
updates["so"] = m.OS
|
|
||||||
}
|
}
|
||||||
if m.RAM.TotalGB > 0 {
|
if cpu, _ := rawMap["cpu"].(map[string]any); cpu != nil {
|
||||||
updates["ram"] = fmt.Sprintf("%.0f GB", m.RAM.TotalGB)
|
if n, _ := cpu["nucleos"].(float64); n > 0 {
|
||||||
|
updates["nucleos"] = fmt.Sprintf("%d", int(n))
|
||||||
}
|
}
|
||||||
if m.CPU.Nucleos > 0 {
|
|
||||||
updates["nucleos"] = fmt.Sprintf("%d", m.CPU.Nucleos)
|
|
||||||
}
|
}
|
||||||
if m.Disco.TotalGB > 0 {
|
// Compatibilidad: nuevo formato (discos array) y viejo (disco objeto)
|
||||||
updates["disco"] = fmt.Sprintf("%.0f GB", m.Disco.TotalGB)
|
discos, hasArray := rawMap["discos"].([]any)
|
||||||
|
if hasArray {
|
||||||
|
var maxTotal float64
|
||||||
|
for _, item := range discos {
|
||||||
|
if d, _ := item.(map[string]any); d != nil {
|
||||||
|
if t, _ := d["total_gb"].(float64); t > maxTotal {
|
||||||
|
maxTotal = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if maxTotal > 0 {
|
||||||
|
updates["disco"] = fmt.Sprintf("%.0f GB", maxTotal)
|
||||||
|
}
|
||||||
|
} else if disco, _ := rawMap["disco"].(map[string]any); disco != nil {
|
||||||
|
if total, _ := disco["total_gb"].(float64); total > 0 {
|
||||||
|
updates["disco"] = fmt.Sprintf("%.0f GB", total)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user