github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/process/process.go (about) 1 package process 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "runtime" 8 "sort" 9 "time" 10 11 "github.com/gofiber/fiber/v2/internal/gopsutil/common" 12 "github.com/gofiber/fiber/v2/internal/gopsutil/cpu" 13 "github.com/gofiber/fiber/v2/internal/gopsutil/mem" 14 ) 15 16 var ( 17 invoke common.Invoker = common.Invoke{} 18 ErrorNoChildren = errors.New("process does not have children") 19 ErrorProcessNotRunning = errors.New("process does not exist") 20 ) 21 22 type Process struct { 23 Pid int32 `json:"pid"` 24 name string 25 status string 26 parent int32 27 numCtxSwitches *NumCtxSwitchesStat 28 uids []int32 29 gids []int32 30 groups []int32 31 numThreads int32 32 memInfo *MemoryInfoStat 33 sigInfo *SignalInfoStat 34 createTime int64 35 36 lastCPUTimes *cpu.TimesStat 37 lastCPUTime time.Time 38 39 tgid int32 40 } 41 42 type OpenFilesStat struct { 43 Path string `json:"path"` 44 Fd uint64 `json:"fd"` 45 } 46 47 type MemoryInfoStat struct { 48 RSS uint64 `json:"rss"` // bytes 49 VMS uint64 `json:"vms"` // bytes 50 HWM uint64 `json:"hwm"` // bytes 51 Data uint64 `json:"data"` // bytes 52 Stack uint64 `json:"stack"` // bytes 53 Locked uint64 `json:"locked"` // bytes 54 Swap uint64 `json:"swap"` // bytes 55 } 56 57 type SignalInfoStat struct { 58 PendingProcess uint64 `json:"pending_process"` 59 PendingThread uint64 `json:"pending_thread"` 60 Blocked uint64 `json:"blocked"` 61 Ignored uint64 `json:"ignored"` 62 Caught uint64 `json:"caught"` 63 } 64 65 type RlimitStat struct { 66 Resource int32 `json:"resource"` 67 Soft int32 `json:"soft"` //TODO too small. needs to be uint64 68 Hard int32 `json:"hard"` //TODO too small. needs to be uint64 69 Used uint64 `json:"used"` 70 } 71 72 type IOCountersStat struct { 73 ReadCount uint64 `json:"readCount"` 74 WriteCount uint64 `json:"writeCount"` 75 ReadBytes uint64 `json:"readBytes"` 76 WriteBytes uint64 `json:"writeBytes"` 77 } 78 79 type NumCtxSwitchesStat struct { 80 Voluntary int64 `json:"voluntary"` 81 Involuntary int64 `json:"involuntary"` 82 } 83 84 type PageFaultsStat struct { 85 MinorFaults uint64 `json:"minorFaults"` 86 MajorFaults uint64 `json:"majorFaults"` 87 ChildMinorFaults uint64 `json:"childMinorFaults"` 88 ChildMajorFaults uint64 `json:"childMajorFaults"` 89 } 90 91 // Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h 92 // from libc6-dev package in Ubuntu 16.10 93 const ( 94 RLIMIT_CPU int32 = 0 95 RLIMIT_FSIZE int32 = 1 96 RLIMIT_DATA int32 = 2 97 RLIMIT_STACK int32 = 3 98 RLIMIT_CORE int32 = 4 99 RLIMIT_RSS int32 = 5 100 RLIMIT_NPROC int32 = 6 101 RLIMIT_NOFILE int32 = 7 102 RLIMIT_MEMLOCK int32 = 8 103 RLIMIT_AS int32 = 9 104 RLIMIT_LOCKS int32 = 10 105 RLIMIT_SIGPENDING int32 = 11 106 RLIMIT_MSGQUEUE int32 = 12 107 RLIMIT_NICE int32 = 13 108 RLIMIT_RTPRIO int32 = 14 109 RLIMIT_RTTIME int32 = 15 110 ) 111 112 func (p Process) String() string { 113 s, _ := json.Marshal(p) 114 return string(s) 115 } 116 117 func (o OpenFilesStat) String() string { 118 s, _ := json.Marshal(o) 119 return string(s) 120 } 121 122 func (m MemoryInfoStat) String() string { 123 s, _ := json.Marshal(m) 124 return string(s) 125 } 126 127 func (r RlimitStat) String() string { 128 s, _ := json.Marshal(r) 129 return string(s) 130 } 131 132 func (i IOCountersStat) String() string { 133 s, _ := json.Marshal(i) 134 return string(s) 135 } 136 137 func (p NumCtxSwitchesStat) String() string { 138 s, _ := json.Marshal(p) 139 return string(s) 140 } 141 142 // Pids returns a slice of process ID list which are running now. 143 func Pids() ([]int32, error) { 144 return PidsWithContext(context.Background()) 145 } 146 147 func PidsWithContext(ctx context.Context) ([]int32, error) { 148 pids, err := pidsWithContext(ctx) 149 sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] }) 150 return pids, err 151 } 152 153 // NewProcess creates a new Process instance, it only stores the pid and 154 // checks that the process exists. Other method on Process can be used 155 // to get more information about the process. An error will be returned 156 // if the process does not exist. 157 func NewProcess(pid int32) (*Process, error) { 158 p := &Process{Pid: pid} 159 160 exists, err := PidExists(pid) 161 if err != nil { 162 return p, err 163 } 164 if !exists { 165 return p, ErrorProcessNotRunning 166 } 167 _, err = p.CreateTime() 168 return p, err 169 } 170 171 func PidExists(pid int32) (bool, error) { 172 return PidExistsWithContext(context.Background(), pid) 173 } 174 175 // Background returns true if the process is in background, false otherwise. 176 func (p *Process) Background() (bool, error) { 177 return p.BackgroundWithContext(context.Background()) 178 } 179 180 func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) { 181 fg, err := p.ForegroundWithContext(ctx) 182 if err != nil { 183 return false, err 184 } 185 return !fg, err 186 } 187 188 // If interval is 0, return difference from last call(non-blocking). 189 // If interval > 0, wait interval sec and return diffrence between start and end. 190 func (p *Process) Percent(interval time.Duration) (float64, error) { 191 return p.PercentWithContext(context.Background(), interval) 192 } 193 194 func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) { 195 cpuTimes, err := p.Times() 196 if err != nil { 197 return 0, err 198 } 199 now := time.Now() 200 201 if interval > 0 { 202 p.lastCPUTimes = cpuTimes 203 p.lastCPUTime = now 204 if err := common.Sleep(ctx, interval); err != nil { 205 return 0, err 206 } 207 cpuTimes, err = p.Times() 208 now = time.Now() 209 if err != nil { 210 return 0, err 211 } 212 } else { 213 if p.lastCPUTimes == nil { 214 // invoked first time 215 p.lastCPUTimes = cpuTimes 216 p.lastCPUTime = now 217 return 0, nil 218 } 219 } 220 221 numcpu := runtime.NumCPU() 222 delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu) 223 ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu) 224 p.lastCPUTimes = cpuTimes 225 p.lastCPUTime = now 226 return ret, nil 227 } 228 229 // IsRunning returns whether the process is still running or not. 230 func (p *Process) IsRunning() (bool, error) { 231 return p.IsRunningWithContext(context.Background()) 232 } 233 234 func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) { 235 createTime, err := p.CreateTimeWithContext(ctx) 236 if err != nil { 237 return false, err 238 } 239 p2, err := NewProcess(p.Pid) 240 if err == ErrorProcessNotRunning { 241 return false, nil 242 } 243 createTime2, err := p2.CreateTimeWithContext(ctx) 244 if err != nil { 245 return false, err 246 } 247 return createTime == createTime2, nil 248 } 249 250 // CreateTime returns created time of the process in milliseconds since the epoch, in UTC. 251 func (p *Process) CreateTime() (int64, error) { 252 return p.CreateTimeWithContext(context.Background()) 253 } 254 255 func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) { 256 if p.createTime != 0 { 257 return p.createTime, nil 258 } 259 createTime, err := p.createTimeWithContext(ctx) 260 p.createTime = createTime 261 return p.createTime, err 262 } 263 264 func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 { 265 if delta == 0 { 266 return 0 267 } 268 delta_proc := t2.Total() - t1.Total() 269 overall_percent := ((delta_proc / delta) * 100) * float64(numcpu) 270 return overall_percent 271 } 272 273 // MemoryPercent returns how many percent of the total RAM this process uses 274 func (p *Process) MemoryPercent() (float32, error) { 275 return p.MemoryPercentWithContext(context.Background()) 276 } 277 278 func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) { 279 machineMemory, err := mem.VirtualMemory() 280 if err != nil { 281 return 0, err 282 } 283 total := machineMemory.Total 284 285 processMemory, err := p.MemoryInfo() 286 if err != nil { 287 return 0, err 288 } 289 used := processMemory.RSS 290 291 return (100 * float32(used) / float32(total)), nil 292 } 293 294 // CPU_Percent returns how many percent of the CPU time this process uses 295 func (p *Process) CPUPercent() (float64, error) { 296 return p.CPUPercentWithContext(context.Background()) 297 } 298 299 func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) { 300 crt_time, err := p.CreateTime() 301 if err != nil { 302 return 0, err 303 } 304 305 cput, err := p.Times() 306 if err != nil { 307 return 0, err 308 } 309 310 created := time.Unix(0, crt_time*int64(time.Millisecond)) 311 totalTime := time.Since(created).Seconds() 312 if totalTime <= 0 { 313 return 0, nil 314 } 315 316 return 100 * cput.Total() / totalTime, nil 317 } 318 319 // Groups returns all group IDs(include supplementary groups) of the process as a slice of the int 320 func (p *Process) Groups() ([]int32, error) { 321 return p.GroupsWithContext(context.Background()) 322 }