heroagent/pkg/system/stats/system.go
2025-04-23 04:18:28 +02:00

242 lines
6.6 KiB
Go

package stats
import (
"fmt"
"math"
"runtime"
"time"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
)
// SystemInfo contains information about the system's CPU and memory
type SystemInfo struct {
CPU CPUInfo `json:"cpu"`
Memory MemoryInfo `json:"memory"`
Network NetworkInfo `json:"network"`
}
// CPUInfo contains information about the CPU
type CPUInfo struct {
Cores int `json:"cores"`
ModelName string `json:"model_name"`
UsagePercent float64 `json:"usage_percent"`
}
// MemoryInfo contains information about the system memory
type MemoryInfo struct {
Total float64 `json:"total_gb"`
Used float64 `json:"used_gb"`
Free float64 `json:"free_gb"`
UsedPercent float64 `json:"used_percent"`
}
// NetworkInfo contains information about network usage
type NetworkInfo struct {
UploadSpeed string `json:"upload_speed"`
DownloadSpeed string `json:"download_speed"`
BytesSent uint64 `json:"bytes_sent"`
BytesReceived uint64 `json:"bytes_received"`
}
// NetworkSpeedResult contains the upload and download speeds
type NetworkSpeedResult struct {
UploadSpeed string `json:"upload_speed"`
DownloadSpeed string `json:"download_speed"`
}
// UptimeProvider defines an interface for getting system uptime
type UptimeProvider interface {
GetUptime() string
}
// GetSystemInfo returns information about the system's CPU and memory
func GetSystemInfo() (*SystemInfo, error) {
// Get CPU info
cpuInfo := CPUInfo{
Cores: runtime.NumCPU(),
ModelName: "Unknown",
}
// Try to get detailed CPU info
info, err := cpu.Info()
if err == nil && len(info) > 0 {
cpuInfo.ModelName = info[0].ModelName
}
// Get CPU usage
cpuPercent, err := cpu.Percent(time.Second, false)
if err == nil && len(cpuPercent) > 0 {
cpuInfo.UsagePercent = math.Round(cpuPercent[0]*10) / 10
}
// Get memory info
memInfo := MemoryInfo{}
virtualMem, err := mem.VirtualMemory()
if err == nil {
memInfo.Total = float64(virtualMem.Total) / (1024 * 1024 * 1024) // Convert to GB
memInfo.Used = float64(virtualMem.Used) / (1024 * 1024 * 1024)
memInfo.Free = float64(virtualMem.Free) / (1024 * 1024 * 1024)
memInfo.UsedPercent = math.Round(virtualMem.UsedPercent*10) / 10
}
// Get network speed
uploadSpeed, downloadSpeed := GetNetworkSpeed()
// Create and return the system info
return &SystemInfo{
CPU: cpuInfo,
Memory: memInfo,
Network: NetworkInfo{
UploadSpeed: uploadSpeed,
DownloadSpeed: downloadSpeed,
},
}, nil
}
// GetNetworkSpeed returns the current network speed in Mbps
func GetNetworkSpeed() (string, string) {
networkUpSpeed := "Unknown"
networkDownSpeed := "Unknown"
// Get initial network counters
countersStart, err := net.IOCounters(false)
if err != nil || len(countersStart) == 0 {
return networkUpSpeed, networkDownSpeed
}
// Wait a short time to measure the difference
time.Sleep(500 * time.Millisecond)
// Get updated network counters
countersEnd, err := net.IOCounters(false)
if err != nil || len(countersEnd) == 0 {
return networkUpSpeed, networkDownSpeed
}
// Calculate the difference in bytes
bytesSent := countersEnd[0].BytesSent - countersStart[0].BytesSent
bytesRecv := countersEnd[0].BytesRecv - countersStart[0].BytesRecv
// Convert to Mbps (megabits per second)
// 500ms = 0.5s, so multiply by 2 to get per second
// Then convert bytes to bits (*8) and to megabits (/1024/1024)
mbpsSent := float64(bytesSent) * 2 * 8 / 1024 / 1024
mbpsRecv := float64(bytesRecv) * 2 * 8 / 1024 / 1024
// Format the speeds with appropriate units
if mbpsSent < 1 {
networkUpSpeed = fmt.Sprintf("%.1f Kbps", mbpsSent*1024)
} else {
networkUpSpeed = fmt.Sprintf("%.1f Mbps", mbpsSent)
}
if mbpsRecv < 1 {
networkDownSpeed = fmt.Sprintf("%.1f Kbps", mbpsRecv*1024)
} else {
networkDownSpeed = fmt.Sprintf("%.1f Mbps", mbpsRecv)
}
return networkUpSpeed, networkDownSpeed
}
// GetNetworkSpeedResult returns the network speed as a struct
func GetNetworkSpeedResult() NetworkSpeedResult {
uploadSpeed, downloadSpeed := GetNetworkSpeed()
return NetworkSpeedResult{
UploadSpeed: uploadSpeed,
DownloadSpeed: downloadSpeed,
}
}
// GetFormattedCPUInfo returns a formatted string with CPU information
func GetFormattedCPUInfo() string {
sysInfo, err := GetSystemInfo()
if err != nil {
return "Unknown"
}
return fmt.Sprintf("%d cores (%s)", sysInfo.CPU.Cores, sysInfo.CPU.ModelName)
}
// GetFormattedMemoryInfo returns a formatted string with memory information
func GetFormattedMemoryInfo() string {
sysInfo, err := GetSystemInfo()
if err != nil {
return "Unknown"
}
return fmt.Sprintf("%.1fGB (%.1fGB used)", sysInfo.Memory.Total, sysInfo.Memory.Used)
}
// GetFormattedNetworkInfo returns a formatted string with network information
func GetFormattedNetworkInfo() string {
sysInfo, err := GetSystemInfo()
if err != nil {
return "Unknown"
}
return fmt.Sprintf("Up: %s\nDown: %s", sysInfo.Network.UploadSpeed, sysInfo.Network.DownloadSpeed)
}
// GetHardwareStats returns a map with hardware statistics
func GetHardwareStats() map[string]interface{} {
// Create the hardware stats map
hardwareStats := map[string]interface{}{
"cpu": GetFormattedCPUInfo(),
"memory": GetFormattedMemoryInfo(),
"disk": GetFormattedDiskInfo(),
"network": GetFormattedNetworkInfo(),
}
return hardwareStats
}
// GetHardwareStatsJSON returns hardware statistics in a format suitable for JSON responses
func GetHardwareStatsJSON() map[string]interface{} {
// Get system information
sysInfo, err := GetSystemInfo()
if err != nil {
return map[string]interface{}{
"error": "Failed to get system info: " + err.Error(),
}
}
// Get disk information
diskInfo, err := GetRootDiskInfo()
if err != nil {
return map[string]interface{}{
"error": "Failed to get disk info: " + err.Error(),
}
}
// Create the hardware stats map
hardwareStats := map[string]interface{}{
"cpu": map[string]interface{}{
"cores": sysInfo.CPU.Cores,
"model": sysInfo.CPU.ModelName,
"usage_percent": sysInfo.CPU.UsagePercent,
},
"memory": map[string]interface{}{
"total_gb": sysInfo.Memory.Total,
"used_gb": sysInfo.Memory.Used,
"free_gb": sysInfo.Memory.Free,
"used_percent": sysInfo.Memory.UsedPercent,
},
"disk": map[string]interface{}{
"total_gb": diskInfo.Total,
"free_gb": diskInfo.Free,
"used_gb": diskInfo.Used,
"used_percent": diskInfo.UsedPercent,
},
"network": map[string]interface{}{
"upload_speed": sysInfo.Network.UploadSpeed,
"download_speed": sysInfo.Network.DownloadSpeed,
},
}
return hardwareStats
}