page1_handler.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "os"
  7. "os/exec"
  8. "runtime"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. )
  13. var lastCPU struct {
  14. idle, total uint64
  15. mu sync.Mutex
  16. }
  17. func initCPUUsage() {
  18. getCPUUsage()
  19. }
  20. func systemInfoHandler(w http.ResponseWriter, r *http.Request) {
  21. w.Header().Set("Content-Type", "application/json; charset=utf-8")
  22. memPercent, memUsed, memTotal := getMemInfo()
  23. diskPercent, diskUsed, diskTotal := getDiskInfo()
  24. json.NewEncoder(w).Encode(map[string]any{
  25. "cpu_usage": getCPUUsage(),
  26. "cpu_cores": getCPUCore(),
  27. "cpu_freq": getCPUFreq(),
  28. "mem_percent": memPercent,
  29. "mem_used": memUsed,
  30. "mem_total": memTotal,
  31. "disk_percent": diskPercent,
  32. "disk_used": diskUsed,
  33. "disk_total": diskTotal,
  34. })
  35. }
  36. func getCPUUsage() int {
  37. lastCPU.mu.Lock()
  38. defer lastCPU.mu.Unlock()
  39. data, err := os.ReadFile("/proc/stat")
  40. if err != nil {
  41. return 0
  42. }
  43. f := strings.Fields(strings.Split(string(data), "\n")[0])
  44. if len(f) < 5 {
  45. return 0
  46. }
  47. var idle, total uint64
  48. for i := 1; i < len(f); i++ {
  49. v, err := strconv.ParseUint(f[i], 10, 64)
  50. if err != nil {
  51. continue
  52. }
  53. total += v
  54. // idle + iowait
  55. if i == 4 || i == 5 {
  56. idle += v
  57. }
  58. }
  59. if lastCPU.total == 0 {
  60. lastCPU.idle = idle
  61. lastCPU.total = total
  62. return 0
  63. }
  64. dt := total - lastCPU.total
  65. di := idle - lastCPU.idle
  66. lastCPU.idle = idle
  67. lastCPU.total = total
  68. if dt == 0 {
  69. return 0
  70. }
  71. return int((dt - di) * 100 / dt)
  72. }
  73. func getCPUCore() int {
  74. return runtime.NumCPU()
  75. }
  76. func getCPUFreq() string {
  77. var total, count int
  78. for i := 0; ; i++ {
  79. data, err := os.ReadFile(fmt.Sprintf("/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i))
  80. if err != nil {
  81. break
  82. }
  83. freq, err := strconv.Atoi(strings.TrimSpace(string(data)))
  84. if err != nil {
  85. continue
  86. }
  87. total += freq / 1000
  88. count++
  89. }
  90. if count > 0 {
  91. return strconv.Itoa(total / count)
  92. }
  93. data, err := os.ReadFile("/proc/cpuinfo")
  94. if err == nil {
  95. for _, line := range strings.Split(string(data), "\n") {
  96. if strings.HasPrefix(line, "cpu MHz") {
  97. f := strings.Split(line, ":")
  98. if len(f) == 2 {
  99. v, err := strconv.ParseFloat(strings.TrimSpace(f[1]), 64)
  100. if err == nil {
  101. return strconv.Itoa(int(v))
  102. }
  103. }
  104. }
  105. }
  106. }
  107. return noValue
  108. }
  109. func getMemInfo() (int, string, string) {
  110. data, err := os.ReadFile("/proc/meminfo")
  111. if err != nil {
  112. return 0, noValue, noValue
  113. }
  114. var total, avail uint64
  115. for _, line := range strings.Split(string(data), "\n") {
  116. f := strings.Fields(line)
  117. if len(f) < 2 {
  118. continue
  119. }
  120. switch f[0] {
  121. case "MemTotal:":
  122. total, _ = strconv.ParseUint(f[1], 10, 64)
  123. case "MemAvailable:":
  124. avail, _ = strconv.ParseUint(f[1], 10, 64)
  125. }
  126. }
  127. if total == 0 {
  128. return 0, noValue, noValue
  129. }
  130. used := total - avail
  131. return int(used * 100 / total),
  132. formatSize(used * 1024),
  133. formatSize(total * 1024)
  134. }
  135. func getDiskInfo() (int, string, string) {
  136. out, err := exec.Command("df", "-h", "/").Output()
  137. if err != nil {
  138. return 0, noValue, noValue
  139. }
  140. lines := strings.Split(string(out), "\n")
  141. if len(lines) < 2 {
  142. return 0, noValue, noValue
  143. }
  144. f := strings.Fields(lines[1])
  145. if len(f) < 5 {
  146. return 0, noValue, noValue
  147. }
  148. percent, err := strconv.Atoi(strings.TrimSuffix(f[4], "%"))
  149. if err != nil {
  150. percent = 0
  151. }
  152. return percent, f[2], f[1]
  153. }
  154. func formatSize(size uint64) string {
  155. const (
  156. KB = 1024
  157. MB = KB * 1024
  158. GB = MB * 1024
  159. )
  160. switch {
  161. case size >= GB:
  162. return fmt.Sprintf("%.1fGB", float64(size)/GB)
  163. case size >= MB:
  164. return fmt.Sprintf("%.0fMB", float64(size)/MB)
  165. case size >= KB:
  166. return fmt.Sprintf("%.0fKB", float64(size)/KB)
  167. default:
  168. return fmt.Sprintf("%dB", size)
  169. }
  170. }