process_info.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package nginx
  2. import (
  3. "fmt"
  4. "math"
  5. "runtime"
  6. "strings"
  7. "time"
  8. "github.com/shirou/gopsutil/v4/process"
  9. "github.com/uozi-tech/cosy/logger"
  10. )
  11. type NginxProcessInfo struct {
  12. Workers int `json:"workers"`
  13. Master int `json:"master"`
  14. Cache int `json:"cache"`
  15. Other int `json:"other"`
  16. CPUUsage float64 `json:"cpu_usage"`
  17. MemoryUsage float64 `json:"memory_usage"`
  18. }
  19. // GetNginxProcessInfo Get Nginx process information
  20. func GetNginxProcessInfo() (*NginxProcessInfo, error) {
  21. result := &NginxProcessInfo{
  22. Workers: 0,
  23. Master: 0,
  24. Cache: 0,
  25. Other: 0,
  26. CPUUsage: 0.0,
  27. MemoryUsage: 0.0,
  28. }
  29. // Find all Nginx processes
  30. processes, err := process.Processes()
  31. if err != nil {
  32. return result, fmt.Errorf("failed to get processes: %v", err)
  33. }
  34. totalMemory := 0.0
  35. workerCount := 0
  36. masterCount := 0
  37. cacheCount := 0
  38. otherCount := 0
  39. nginxProcesses := []*process.Process{}
  40. // Get the number of system CPU cores
  41. numCPU := runtime.NumCPU()
  42. // Get the PID of the Nginx master process
  43. var masterPID int32 = -1
  44. for _, p := range processes {
  45. name, err := p.Name()
  46. if err != nil {
  47. continue
  48. }
  49. cmdline, err := p.Cmdline()
  50. if err != nil {
  51. continue
  52. }
  53. // Check if it is the Nginx master process
  54. if strings.Contains(strings.ToLower(name), "nginx") &&
  55. (strings.Contains(cmdline, "master process") ||
  56. !strings.Contains(cmdline, "worker process")) &&
  57. p.Pid > 0 {
  58. masterPID = p.Pid
  59. masterCount++
  60. nginxProcesses = append(nginxProcesses, p)
  61. // Get the memory usage
  62. mem, err := p.MemoryInfo()
  63. if err == nil && mem != nil {
  64. // Convert to MB
  65. memoryUsage := float64(mem.RSS) / 1024 / 1024
  66. totalMemory += memoryUsage
  67. }
  68. break
  69. }
  70. }
  71. // Iterate through all processes, distinguishing between worker processes and other Nginx processes
  72. for _, p := range processes {
  73. if p.Pid == masterPID {
  74. continue // Already calculated the master process
  75. }
  76. name, err := p.Name()
  77. if err != nil {
  78. continue
  79. }
  80. // Only process Nginx related processes
  81. if !strings.Contains(strings.ToLower(name), "nginx") {
  82. continue
  83. }
  84. // Add to the Nginx process list
  85. nginxProcesses = append(nginxProcesses, p)
  86. // Get the parent process PID
  87. ppid, err := p.Ppid()
  88. if err != nil {
  89. continue
  90. }
  91. cmdline, err := p.Cmdline()
  92. if err != nil {
  93. continue
  94. }
  95. // Get the memory usage
  96. mem, err := p.MemoryInfo()
  97. if err == nil && mem != nil {
  98. // Convert to MB
  99. memoryUsage := float64(mem.RSS) / 1024 / 1024
  100. totalMemory += memoryUsage
  101. }
  102. // Distinguish between worker processes, cache processes, and other processes
  103. if ppid == masterPID || strings.Contains(cmdline, "worker process") {
  104. logger.Debug(cmdline)
  105. workerCount++
  106. } else if strings.Contains(cmdline, "cache") {
  107. cacheCount++
  108. } else {
  109. otherCount++
  110. }
  111. }
  112. // Calculate the CPU usage
  113. // First, measure the initial CPU time
  114. times1 := make(map[int32]float64)
  115. for _, p := range nginxProcesses {
  116. times, err := p.Times()
  117. if err == nil {
  118. // CPU time = user time + system time
  119. times1[p.Pid] = times.User + times.System
  120. }
  121. }
  122. // Wait for a short period of time
  123. time.Sleep(100 * time.Millisecond)
  124. // Measure the CPU time again
  125. totalCPUPercent := 0.0
  126. for _, p := range nginxProcesses {
  127. times, err := p.Times()
  128. if err != nil {
  129. continue
  130. }
  131. // Calculate the CPU time difference
  132. currentTotal := times.User + times.System
  133. if previousTotal, ok := times1[p.Pid]; ok {
  134. // Calculate the CPU usage percentage during this period (considering multiple cores)
  135. cpuDelta := currentTotal - previousTotal
  136. // Calculate the CPU usage per second (considering the sampling time)
  137. cpuPercent := (cpuDelta / 0.1) * 100.0 / float64(numCPU)
  138. totalCPUPercent += cpuPercent
  139. }
  140. }
  141. // Round to the nearest integer, which is more consistent with the top display
  142. totalCPUPercent = math.Round(totalCPUPercent)
  143. // Round the memory usage to two decimal places
  144. totalMemory = math.Round(totalMemory*100) / 100
  145. result.Workers = workerCount
  146. result.Master = masterCount
  147. result.Cache = cacheCount
  148. result.Other = otherCount
  149. result.CPUUsage = totalCPUPercent
  150. result.MemoryUsage = totalMemory
  151. return result, nil
  152. }