mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-12-28 02:16:35 +08:00
feat: 新增机器状态查看&机器状态等
This commit is contained in:
@@ -3,8 +3,6 @@ package machine
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -23,19 +21,6 @@ type NetIntfInfo struct {
|
||||
Tx uint64
|
||||
}
|
||||
|
||||
type cpuRaw struct {
|
||||
User uint64 // time spent in user mode
|
||||
Nice uint64 // time spent in user mode with low priority (nice)
|
||||
System uint64 // time spent in system mode
|
||||
Idle uint64 // time spent in the idle task
|
||||
Iowait uint64 // time spent waiting for I/O to complete (since Linux 2.5.41)
|
||||
Irq uint64 // time spent servicing interrupts (since 2.6.0-test4)
|
||||
SoftIrq uint64 // time spent servicing softirqs (since 2.6.0-test4)
|
||||
Steal uint64 // time spent in other OSes when running in a virtualized environment
|
||||
Guest uint64 // time spent running a virtual CPU for guest operating systems under the control of the Linux kernel.
|
||||
Total uint64 // total of all time fields
|
||||
}
|
||||
|
||||
type CPUInfo struct {
|
||||
User float32
|
||||
Nice float32
|
||||
@@ -49,7 +34,7 @@ type CPUInfo struct {
|
||||
}
|
||||
|
||||
type Stats struct {
|
||||
Uptime time.Duration
|
||||
Uptime string
|
||||
Hostname string
|
||||
Load1 string
|
||||
Load5 string
|
||||
@@ -59,6 +44,7 @@ type Stats struct {
|
||||
MemTotal uint64
|
||||
MemFree uint64
|
||||
MemBuffers uint64
|
||||
MemAvailable uint64
|
||||
MemCached uint64
|
||||
SwapTotal uint64
|
||||
SwapFree uint64
|
||||
@@ -90,12 +76,32 @@ func getUptime(uptime string, stats *Stats) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
stats.Uptime = time.Duration(upsecs * 1e9)
|
||||
stats.Uptime = fmtUptime(time.Duration(upsecs * 1e9))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func fmtUptime(dur time.Duration) string {
|
||||
dur = dur - (dur % time.Second)
|
||||
var days int
|
||||
for dur.Hours() > 24.0 {
|
||||
days++
|
||||
dur -= 24 * time.Hour
|
||||
}
|
||||
s1 := dur.String()
|
||||
s2 := ""
|
||||
if days > 0 {
|
||||
s2 = fmt.Sprintf("%dd ", days)
|
||||
}
|
||||
for _, ch := range s1 {
|
||||
s2 += string(ch)
|
||||
if ch == 'h' || ch == 'm' {
|
||||
s2 += " "
|
||||
}
|
||||
}
|
||||
return s2
|
||||
}
|
||||
|
||||
func getHostname(hostname string, stats *Stats) (err error) {
|
||||
stats.Hostname = strings.TrimSpace(hostname)
|
||||
return
|
||||
@@ -143,6 +149,8 @@ func getMemInfo(memInfo string, stats *Stats) (err error) {
|
||||
stats.SwapTotal = val
|
||||
case "SwapFree:":
|
||||
stats.SwapFree = val
|
||||
case "MemAvailable:":
|
||||
stats.MemAvailable = val
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,190 +256,22 @@ func getInterfaceInfo(iInfo string, stats *Stats) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func parseCPUFields(fields []string, stat *cpuRaw) {
|
||||
numFields := len(fields)
|
||||
for i := 1; i < numFields; i++ {
|
||||
val, err := strconv.ParseUint(fields[i], 10, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
stat.Total += val
|
||||
switch i {
|
||||
case 1:
|
||||
stat.User = val
|
||||
case 2:
|
||||
stat.Nice = val
|
||||
case 3:
|
||||
stat.System = val
|
||||
case 4:
|
||||
stat.Idle = val
|
||||
case 5:
|
||||
stat.Iowait = val
|
||||
case 6:
|
||||
stat.Irq = val
|
||||
case 7:
|
||||
stat.SoftIrq = val
|
||||
case 8:
|
||||
stat.Steal = val
|
||||
case 9:
|
||||
stat.Guest = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the CPU stats that were fetched last time round
|
||||
var preCPU cpuRaw
|
||||
|
||||
func getCPU(cpuInfo string, stats *Stats) (err error) {
|
||||
var (
|
||||
nowCPU cpuRaw
|
||||
total float32
|
||||
)
|
||||
// %Cpu(s): 6.1 us, 3.0 sy, 0.0 ni, 90.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
value := strings.Split(cpuInfo, ":")[1]
|
||||
values := strings.Split(value, ",")
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(cpuInfo))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) > 0 && fields[0] == "cpu" { // changing here if want to get every cpu-core's stats
|
||||
parseCPUFields(fields, &nowCPU)
|
||||
break
|
||||
}
|
||||
}
|
||||
if preCPU.Total == 0 { // having no pre raw cpu data
|
||||
goto END
|
||||
}
|
||||
us, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[0]), " ")[0], 32)
|
||||
stats.CPU.User = float32(us)
|
||||
|
||||
total = float32(nowCPU.Total - preCPU.Total)
|
||||
stats.CPU.User = float32(nowCPU.User-preCPU.User) / total * 100
|
||||
stats.CPU.Nice = float32(nowCPU.Nice-preCPU.Nice) / total * 100
|
||||
stats.CPU.System = float32(nowCPU.System-preCPU.System) / total * 100
|
||||
stats.CPU.Idle = float32(nowCPU.Idle-preCPU.Idle) / total * 100
|
||||
stats.CPU.Iowait = float32(nowCPU.Iowait-preCPU.Iowait) / total * 100
|
||||
stats.CPU.Irq = float32(nowCPU.Irq-preCPU.Irq) / total * 100
|
||||
stats.CPU.SoftIrq = float32(nowCPU.SoftIrq-preCPU.SoftIrq) / total * 100
|
||||
stats.CPU.Guest = float32(nowCPU.Guest-preCPU.Guest) / total * 100
|
||||
END:
|
||||
preCPU = nowCPU
|
||||
return
|
||||
sy, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[1]), " ")[0], 32)
|
||||
stats.CPU.System = float32(sy)
|
||||
|
||||
id, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[3]), " ")[0], 32)
|
||||
stats.CPU.Idle = float32(id)
|
||||
|
||||
wa, _ := strconv.ParseFloat(strings.Split(strings.TrimSpace(values[4]), " ")[0], 32)
|
||||
stats.CPU.Iowait = float32(wa)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fmtUptime(stats *Stats) string {
|
||||
dur := stats.Uptime
|
||||
dur = dur - (dur % time.Second)
|
||||
var days int
|
||||
for dur.Hours() > 24.0 {
|
||||
days++
|
||||
dur -= 24 * time.Hour
|
||||
}
|
||||
s1 := dur.String()
|
||||
s2 := ""
|
||||
if days > 0 {
|
||||
s2 = fmt.Sprintf("%dd ", days)
|
||||
}
|
||||
for _, ch := range s1 {
|
||||
s2 += string(ch)
|
||||
if ch == 'h' || ch == 'm' {
|
||||
s2 += " "
|
||||
}
|
||||
}
|
||||
return s2
|
||||
}
|
||||
|
||||
func fmtBytes(val uint64) string {
|
||||
if val < 1024 {
|
||||
return fmt.Sprintf("%d bytes", val)
|
||||
} else if val < 1024*1024 {
|
||||
return fmt.Sprintf("%6.2f KiB", float64(val)/1024.0)
|
||||
} else if val < 1024*1024*1024 {
|
||||
return fmt.Sprintf("%6.2f MiB", float64(val)/1024.0/1024.0)
|
||||
} else {
|
||||
return fmt.Sprintf("%6.2f GiB", float64(val)/1024.0/1024.0/1024.0)
|
||||
}
|
||||
}
|
||||
|
||||
func ShowStats(output io.Writer, stats *Stats) {
|
||||
used := stats.MemTotal - stats.MemFree - stats.MemBuffers - stats.MemCached
|
||||
fmt.Fprintf(output,
|
||||
`%s%s%s%s up %s%s%s
|
||||
Load:
|
||||
%s%s %s %s%s
|
||||
CPU:
|
||||
%s%.2f%s%% user, %s%.2f%s%% sys, %s%.2f%s%% nice, %s%.2f%s%% idle, %s%.2f%s%% iowait, %s%.2f%s%% hardirq, %s%.2f%s%% softirq, %s%.2f%s%% guest
|
||||
Processes:
|
||||
%s%s%s running of %s%s%s total
|
||||
Memory:
|
||||
free = %s%s%s
|
||||
used = %s%s%s
|
||||
buffers = %s%s%s
|
||||
cached = %s%s%s
|
||||
swap = %s%s%s free of %s%s%s
|
||||
`,
|
||||
escClear,
|
||||
escBrightWhite, stats.Hostname, escReset,
|
||||
escBrightWhite, fmtUptime(stats), escReset,
|
||||
escBrightWhite, stats.Load1, stats.Load5, stats.Load10, escReset,
|
||||
escBrightWhite, stats.CPU.User, escReset,
|
||||
escBrightWhite, stats.CPU.System, escReset,
|
||||
escBrightWhite, stats.CPU.Nice, escReset,
|
||||
escBrightWhite, stats.CPU.Idle, escReset,
|
||||
escBrightWhite, stats.CPU.Iowait, escReset,
|
||||
escBrightWhite, stats.CPU.Irq, escReset,
|
||||
escBrightWhite, stats.CPU.SoftIrq, escReset,
|
||||
escBrightWhite, stats.CPU.Guest, escReset,
|
||||
escBrightWhite, stats.RunningProcs, escReset,
|
||||
escBrightWhite, stats.TotalProcs, escReset,
|
||||
escBrightWhite, fmtBytes(stats.MemFree), escReset,
|
||||
escBrightWhite, fmtBytes(used), escReset,
|
||||
escBrightWhite, fmtBytes(stats.MemBuffers), escReset,
|
||||
escBrightWhite, fmtBytes(stats.MemCached), escReset,
|
||||
escBrightWhite, fmtBytes(stats.SwapFree), escReset,
|
||||
escBrightWhite, fmtBytes(stats.SwapTotal), escReset,
|
||||
)
|
||||
if len(stats.FSInfos) > 0 {
|
||||
fmt.Println("Filesystems:")
|
||||
for _, fs := range stats.FSInfos {
|
||||
fmt.Fprintf(output, " %s%8s%s: %s%s%s free of %s%s%s\n",
|
||||
escBrightWhite, fs.MountPoint, escReset,
|
||||
escBrightWhite, fmtBytes(fs.Free), escReset,
|
||||
escBrightWhite, fmtBytes(fs.Used+fs.Free), escReset,
|
||||
)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
if len(stats.NetIntf) > 0 {
|
||||
fmt.Println("Network Interfaces:")
|
||||
keys := make([]string, 0, len(stats.NetIntf))
|
||||
for intf := range stats.NetIntf {
|
||||
keys = append(keys, intf)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, intf := range keys {
|
||||
info := stats.NetIntf[intf]
|
||||
fmt.Fprintf(output, " %s%s%s - %s%s%s",
|
||||
escBrightWhite, intf, escReset,
|
||||
escBrightWhite, info.IPv4, escReset,
|
||||
)
|
||||
if len(info.IPv6) > 0 {
|
||||
fmt.Fprintf(output, ", %s%s%s\n",
|
||||
escBrightWhite, info.IPv6, escReset,
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(output, "\n")
|
||||
}
|
||||
fmt.Fprintf(output, " rx = %s%s%s, tx = %s%s%s\n",
|
||||
escBrightWhite, fmtBytes(info.Rx), escReset,
|
||||
escBrightWhite, fmtBytes(info.Tx), escReset,
|
||||
)
|
||||
fmt.Println()
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
escClear = ""
|
||||
escRed = ""
|
||||
escReset = ""
|
||||
escBrightWhite = ""
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user