- Backend: Enroll-Upsert via MAC-Adresse (kein Duplikat bei Neustart) HeartbeatInterval auf 30s reduziert - Go collector: IPv4 bevorzugen, Loopback/Teredo/ISATAP überspringen, Link-Local IPv6 ignorieren - Go main.go: Enrollment nimmt beste IPv4-Schnittstelle statt Networks[0]
129 lines
2.7 KiB
Go
129 lines
2.7 KiB
Go
package collector
|
|
|
|
import (
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/shirou/gopsutil/v3/cpu"
|
|
"github.com/shirou/gopsutil/v3/disk"
|
|
"github.com/shirou/gopsutil/v3/host"
|
|
"github.com/shirou/gopsutil/v3/mem"
|
|
psnet "github.com/shirou/gopsutil/v3/net"
|
|
)
|
|
|
|
type Metrics struct {
|
|
CPUPercent float64
|
|
MemoryPercent float64
|
|
MemoryTotal uint64
|
|
MemoryAvailable uint64
|
|
Disks []DiskInfo
|
|
Networks []NetInfo
|
|
UptimeSeconds float64
|
|
}
|
|
|
|
type DiskInfo struct {
|
|
MountPoint string
|
|
Total uint64
|
|
Free uint64
|
|
Filesystem string
|
|
}
|
|
|
|
type NetInfo struct {
|
|
Name string
|
|
IPAddress string
|
|
MAC string
|
|
BytesSent uint64
|
|
BytesRecv uint64
|
|
}
|
|
|
|
func Collect() (*Metrics, error) {
|
|
cpuPercent, err := cpu.Percent(time.Second, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
memInfo, err := mem.VirtualMemory()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
uptime, _ := host.Uptime()
|
|
|
|
m := &Metrics{
|
|
CPUPercent: cpuPercent[0],
|
|
MemoryPercent: memInfo.UsedPercent,
|
|
MemoryTotal: memInfo.Total,
|
|
MemoryAvailable: memInfo.Available,
|
|
UptimeSeconds: float64(uptime),
|
|
}
|
|
|
|
// Disks
|
|
partitions, _ := disk.Partitions(false)
|
|
for _, p := range partitions {
|
|
usage, err := disk.Usage(p.Mountpoint)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
m.Disks = append(m.Disks, DiskInfo{
|
|
MountPoint: p.Mountpoint,
|
|
Total: usage.Total,
|
|
Free: usage.Free,
|
|
Filesystem: p.Fstype,
|
|
})
|
|
}
|
|
|
|
// Network
|
|
interfaces, _ := psnet.Interfaces()
|
|
counters, _ := psnet.IOCounters(true)
|
|
counterMap := make(map[string]psnet.IOCountersStat)
|
|
for _, c := range counters {
|
|
counterMap[c.Name] = c
|
|
}
|
|
for _, iface := range interfaces {
|
|
if len(iface.Addrs) == 0 || iface.HardwareAddr == "" {
|
|
continue
|
|
}
|
|
// Loopback und virtuelle Adapter überspringen
|
|
nameLower := strings.ToLower(iface.Name)
|
|
if strings.Contains(nameLower, "loopback") || strings.Contains(nameLower, "teredo") ||
|
|
strings.Contains(nameLower, "isatap") || strings.Contains(nameLower, "6to4") {
|
|
continue
|
|
}
|
|
ni := NetInfo{
|
|
Name: iface.Name,
|
|
MAC: iface.HardwareAddr,
|
|
}
|
|
// IPv4 bevorzugen, IPv6 als Fallback
|
|
for _, addr := range iface.Addrs {
|
|
ip, _, err := net.ParseCIDR(addr.Addr)
|
|
if err != nil {
|
|
// Versuche direkte IP-Adresse (ohne CIDR)
|
|
ip = net.ParseIP(addr.Addr)
|
|
}
|
|
if ip == nil || ip.IsLoopback() || ip.IsLinkLocalUnicast() {
|
|
continue
|
|
}
|
|
if ip.To4() != nil {
|
|
// IPv4 gefunden — nehmen und abbrechen
|
|
ni.IPAddress = addr.Addr
|
|
break
|
|
}
|
|
if ni.IPAddress == "" {
|
|
// IPv6 als vorläufiger Fallback
|
|
ni.IPAddress = addr.Addr
|
|
}
|
|
}
|
|
if ni.IPAddress == "" {
|
|
continue
|
|
}
|
|
if c, ok := counterMap[iface.Name]; ok {
|
|
ni.BytesSent = c.BytesSent
|
|
ni.BytesRecv = c.BytesRecv
|
|
}
|
|
m.Networks = append(m.Networks, ni)
|
|
}
|
|
|
|
return m, nil
|
|
}
|