github.com/google/fleetspeak@v0.1.15-0.20240426164851-4f31f62c1aea/fleetspeak/src/client/internal/monitoring/resource_usage_fetcher.go (about) 1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build windows || darwin 16 17 package monitoring 18 19 import ( 20 "fmt" 21 "os/exec" 22 "time" 23 24 "github.com/shirou/gopsutil/process" 25 ) 26 27 // TODO 28 29 // ResourceUsage contains resource-usage data for a single process. 30 type ResourceUsage struct { 31 // When the resource-usage data was retrieved. 32 Timestamp time.Time 33 34 // Amount of CPU time scheduled for a process so far in user mode. 35 UserCPUMillis float64 36 37 // Amount of CPU time scheduled for a process so far in kernel mode. 38 SystemCPUMillis float64 39 40 // Resident set size for a process, in bytes. 41 ResidentMemory int64 42 43 // Number of open file descriptors. 44 NumFDs int32 45 } 46 47 // ResourceUsageFetcher obtains resource-usage data for a process from the OS. 48 type ResourceUsageFetcher struct{} 49 50 // ResourceUsageFromFinishedCmd returns a ResourceUsage struct with 51 // information from exec.Cmd.ProcessState. NOTE that this is only possible 52 // after the process has finished and has been waited for, and will most 53 // probably panic otherwise. 54 // This function doesn't fill in ResourceUsage.ResidentMemory. 55 func (f ResourceUsageFetcher) ResourceUsageFromFinishedCmd(cmd *exec.Cmd) *ResourceUsage { 56 return &ResourceUsage{ 57 Timestamp: time.Now(), 58 UserCPUMillis: float64(cmd.ProcessState.UserTime().Nanoseconds()) / 1e6, 59 SystemCPUMillis: float64(cmd.ProcessState.SystemTime().Nanoseconds()) / 1e6, 60 } 61 } 62 63 // ResourceUsageForPID returns a ResourceUsage struct with information 64 // from /proc/<PID>/stat and /proc/<PID>/statm . This is only possible with running processes, 65 // an error will be returned if the corresponding procfs entry is not present. 66 func (f ResourceUsageFetcher) ResourceUsageForPID(pid int) (*ResourceUsage, error) { 67 timestamp := time.Now() 68 69 process, err := process.NewProcess(int32(pid)) 70 if err != nil { 71 return nil, err 72 } 73 74 memoryInfo, err := process.MemoryInfo() 75 if err != nil { 76 return nil, err 77 } 78 79 times, err := process.Times() 80 if err != nil { 81 return nil, err 82 } 83 84 return &ResourceUsage{ 85 Timestamp: timestamp, 86 UserCPUMillis: times.User * 1e3, 87 SystemCPUMillis: times.System * 1e3, 88 ResidentMemory: int64(memoryInfo.RSS), 89 }, nil 90 } 91 92 // DebugStatusForPID returns a string containing extra debug info about resource-usage that may not be 93 // captured in ResourceUsage. This is only possible for running processes. 94 func (f ResourceUsageFetcher) DebugStatusForPID(pid int) (string, error) { 95 process, err := process.NewProcess(int32(pid)) 96 if err != nil { 97 return "", err 98 } 99 100 memoryInfo, err := process.MemoryInfo() 101 if err != nil { 102 return "", err 103 } 104 105 times, err := process.Times() 106 if err != nil { 107 return "", err 108 } 109 110 return fmt.Sprintf(` 111 Process: 112 %q 113 114 Times: 115 %q 116 117 MemoryInfo: 118 %q`, process, times, memoryInfo), nil 119 }