analytic.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package analytic
  2. import (
  3. "fmt"
  4. "net/http"
  5. "runtime"
  6. "time"
  7. "github.com/0xJacky/Nginx-UI/internal/analytic"
  8. "github.com/0xJacky/Nginx-UI/internal/helper"
  9. "github.com/0xJacky/Nginx-UI/internal/kernel"
  10. "github.com/0xJacky/Nginx-UI/internal/version"
  11. "github.com/shirou/gopsutil/v4/cpu"
  12. "github.com/shirou/gopsutil/v4/host"
  13. "github.com/shirou/gopsutil/v4/load"
  14. "github.com/spf13/cast"
  15. "github.com/uozi-tech/cosy/logger"
  16. "github.com/gin-gonic/gin"
  17. "github.com/gorilla/websocket"
  18. )
  19. func Analytic(c *gin.Context) {
  20. var upGrader = websocket.Upgrader{
  21. CheckOrigin: func(r *http.Request) bool {
  22. return true
  23. },
  24. }
  25. // upgrade http to websocket
  26. ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
  27. if err != nil {
  28. logger.Error(err)
  29. return
  30. }
  31. defer ws.Close()
  32. var stat Stat
  33. for {
  34. stat.Memory, err = analytic.GetMemoryStat()
  35. if err != nil {
  36. logger.Error(err)
  37. continue
  38. }
  39. cpuTimesBefore, _ := cpu.Times(false)
  40. time.Sleep(1000 * time.Millisecond)
  41. cpuTimesAfter, _ := cpu.Times(false)
  42. threadNum := runtime.GOMAXPROCS(0)
  43. cpuUserUsage := (cpuTimesAfter[0].User - cpuTimesBefore[0].User) / (float64(1000*threadNum) / 1000)
  44. cpuSystemUsage := (cpuTimesAfter[0].System - cpuTimesBefore[0].System) / (float64(1000*threadNum) / 1000)
  45. stat.CPU = CPUStat{
  46. User: cast.ToFloat64(fmt.Sprintf("%.2f", cpuUserUsage*100)),
  47. System: cast.ToFloat64(fmt.Sprintf("%.2f", cpuSystemUsage*100)),
  48. Idle: cast.ToFloat64(fmt.Sprintf("%.2f", (1-cpuUserUsage-cpuSystemUsage)*100)),
  49. Total: cast.ToFloat64(fmt.Sprintf("%.2f", (cpuUserUsage+cpuSystemUsage)*100)),
  50. }
  51. stat.Uptime, err = host.Uptime()
  52. if err != nil {
  53. logger.Error(err)
  54. continue
  55. }
  56. stat.LoadAvg, err = load.Avg()
  57. if err != nil {
  58. logger.Error(err)
  59. continue
  60. }
  61. stat.Disk, err = analytic.GetDiskStat()
  62. if err != nil {
  63. logger.Error(err)
  64. continue
  65. }
  66. network, err := analytic.GetNetworkStat()
  67. if err != nil {
  68. logger.Error(err)
  69. continue
  70. }
  71. stat.Network = *network
  72. // write
  73. err = ws.WriteJSON(stat)
  74. if err != nil {
  75. if helper.IsUnexpectedWebsocketError(err) {
  76. logger.Error(err)
  77. }
  78. break
  79. }
  80. select {
  81. case <-kernel.Context.Done():
  82. logger.Debug("Analytic: Context cancelled, closing WebSocket")
  83. return
  84. case <-time.After(1 * time.Second):
  85. }
  86. }
  87. }
  88. func GetAnalyticInit(c *gin.Context) {
  89. cpuInfo, err := cpu.Info()
  90. if err != nil {
  91. logger.Error(err)
  92. }
  93. network, err := analytic.GetNetworkStat()
  94. if err != nil {
  95. logger.Error(err)
  96. }
  97. memory, err := analytic.GetMemoryStat()
  98. if err != nil {
  99. logger.Error(err)
  100. }
  101. diskStat, err := analytic.GetDiskStat()
  102. if err != nil {
  103. logger.Error(err)
  104. }
  105. hostInfo, err := host.Info()
  106. if err != nil {
  107. logger.Error(err)
  108. hostInfo = &host.InfoStat{}
  109. }
  110. switch hostInfo.Platform {
  111. case "ubuntu":
  112. hostInfo.Platform = "Ubuntu"
  113. case "centos":
  114. hostInfo.Platform = "CentOS"
  115. }
  116. loadAvg, err := load.Avg()
  117. if err != nil {
  118. logger.Error(err)
  119. loadAvg = &load.AvgStat{}
  120. }
  121. c.JSON(http.StatusOK, InitResp{
  122. Host: hostInfo,
  123. CPU: CPURecords{
  124. Info: cpuInfo,
  125. User: analytic.CpuUserRecord,
  126. Total: analytic.CpuTotalRecord,
  127. },
  128. Network: NetworkRecords{
  129. Init: *network,
  130. BytesRecv: analytic.NetRecvRecord,
  131. BytesSent: analytic.NetSentRecord,
  132. },
  133. DiskIO: DiskIORecords{
  134. Writes: analytic.DiskWriteRecord,
  135. Reads: analytic.DiskReadRecord,
  136. },
  137. Memory: memory,
  138. Disk: diskStat,
  139. LoadAvg: loadAvg,
  140. })
  141. }
  142. func GetNode(c *gin.Context) {
  143. cpuInfo, err := cpu.Info()
  144. if err != nil {
  145. logger.Error(err)
  146. }
  147. memory, err := analytic.GetMemoryStat()
  148. if err != nil {
  149. logger.Error(err)
  150. }
  151. diskStat, err := analytic.GetDiskStat()
  152. if err != nil {
  153. logger.Error(err)
  154. }
  155. hostInfo, err := host.Info()
  156. if err != nil {
  157. logger.Error(err)
  158. hostInfo = &host.InfoStat{}
  159. }
  160. switch hostInfo.Platform {
  161. case "ubuntu":
  162. hostInfo.Platform = "Ubuntu"
  163. case "centos":
  164. hostInfo.Platform = "CentOS"
  165. }
  166. runtimeInfo, err := version.GetRuntimeInfo()
  167. if err != nil {
  168. logger.Error("Failed to get runtime info:", err)
  169. runtimeInfo = version.RuntimeInfo{
  170. OS: fmt.Sprintf("%s %s", hostInfo.Platform, hostInfo.PlatformVersion),
  171. Arch: runtime.GOARCH,
  172. }
  173. }
  174. ver := version.GetVersionInfo()
  175. nodeInfo := analytic.NodeInfo{
  176. NodeRuntimeInfo: runtimeInfo,
  177. Version: ver.Version,
  178. CPUNum: len(cpuInfo),
  179. MemoryTotal: memory.Total,
  180. DiskTotal: diskStat.Total,
  181. }
  182. c.JSON(http.StatusOK, nodeInfo)
  183. }