package performance import ( "fmt" "math" "runtime" "strings" "time" "github.com/shirou/gopsutil/v4/process" ) type NginxProcessInfo struct { Workers int `json:"workers"` Master int `json:"master"` Cache int `json:"cache"` Other int `json:"other"` CPUUsage float64 `json:"cpu_usage"` MemoryUsage float64 `json:"memory_usage"` } // GetNginxProcessInfo Get Nginx process information func GetNginxProcessInfo() (*NginxProcessInfo, error) { result := &NginxProcessInfo{ Workers: 0, Master: 0, Cache: 0, Other: 0, CPUUsage: 0.0, MemoryUsage: 0.0, } // Find all Nginx processes processes, err := process.Processes() if err != nil { return result, fmt.Errorf("failed to get processes: %v", err) } totalMemory := 0.0 workerCount := 0 masterCount := 0 cacheCount := 0 otherCount := 0 nginxProcesses := []*process.Process{} // Get the number of system CPU cores numCPU := runtime.NumCPU() // Get the PID of the Nginx master process var masterPID int32 = -1 for _, p := range processes { name, err := p.Name() if err != nil { continue } cmdline, err := p.Cmdline() if err != nil { continue } // Check if it is the Nginx master process if strings.Contains(strings.ToLower(name), "nginx") && (strings.Contains(cmdline, "master process") || !strings.Contains(cmdline, "worker process")) && p.Pid > 0 { masterPID = p.Pid masterCount++ nginxProcesses = append(nginxProcesses, p) // Get the memory usage mem, err := p.MemoryInfo() if err == nil && mem != nil { // Convert to MB memoryUsage := float64(mem.RSS) / 1024 / 1024 totalMemory += memoryUsage } break } } // Iterate through all processes, distinguishing between worker processes and other Nginx processes for _, p := range processes { if p.Pid == masterPID { continue // Already calculated the master process } name, err := p.Name() if err != nil { continue } // Only process Nginx related processes if !strings.Contains(strings.ToLower(name), "nginx") { continue } // Add to the Nginx process list nginxProcesses = append(nginxProcesses, p) // Get the parent process PID ppid, err := p.Ppid() if err != nil { continue } cmdline, err := p.Cmdline() if err != nil { continue } // Get the memory usage mem, err := p.MemoryInfo() if err == nil && mem != nil { // Convert to MB memoryUsage := float64(mem.RSS) / 1024 / 1024 totalMemory += memoryUsage } // Distinguish between worker processes, cache processes, and other processes if ppid == masterPID && strings.Contains(cmdline, "worker process") { workerCount++ } else if ppid == masterPID && strings.Contains(cmdline, "cache") { cacheCount++ } else { otherCount++ } } // Calculate the CPU usage // First, measure the initial CPU time times1 := make(map[int32]float64) for _, p := range nginxProcesses { times, err := p.Times() if err == nil { // CPU time = user time + system time times1[p.Pid] = times.User + times.System } } // Wait for a short period of time time.Sleep(100 * time.Millisecond) // Measure the CPU time again totalCPUPercent := 0.0 for _, p := range nginxProcesses { times, err := p.Times() if err != nil { continue } // Calculate the CPU time difference currentTotal := times.User + times.System if previousTotal, ok := times1[p.Pid]; ok { // Calculate the CPU usage percentage during this period (considering multiple cores) cpuDelta := currentTotal - previousTotal // Calculate the CPU usage per second (considering the sampling time) cpuPercent := (cpuDelta / 0.1) * 100.0 / float64(numCPU) totalCPUPercent += cpuPercent } } // Round to the nearest integer, which is more consistent with the top display totalCPUPercent = math.Round(totalCPUPercent) // Round the memory usage to two decimal places totalMemory = math.Round(totalMemory*100) / 100 result.Workers = workerCount result.Master = masterCount result.Cache = cacheCount result.Other = otherCount result.CPUUsage = totalCPUPercent result.MemoryUsage = totalMemory return result, nil }