|
|
|
@ -14,10 +14,12 @@ import (
|
|
|
|
|
"strings"
|
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
|
|
"bufio"
|
|
|
|
|
"github.com/shirou/gopsutil/cpu"
|
|
|
|
|
"github.com/shirou/gopsutil/host"
|
|
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
|
|
|
|
"github.com/shirou/gopsutil/net"
|
|
|
|
|
"math"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
@ -198,7 +200,7 @@ func (p *Process) IOnice() (int32, error) {
|
|
|
|
|
|
|
|
|
|
// Rlimit returns Resource Limits.
|
|
|
|
|
func (p *Process) Rlimit() ([]RlimitStat, error) {
|
|
|
|
|
return nil, common.ErrNotImplementedError
|
|
|
|
|
return p.fillFromLimits()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IOCounters returns IO Counters.
|
|
|
|
@ -407,6 +409,111 @@ func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
|
|
|
|
|
** Internal functions
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
func limitToInt(val string) (int32, error) {
|
|
|
|
|
if val == "unlimited" {
|
|
|
|
|
return math.MaxInt32, nil
|
|
|
|
|
} else {
|
|
|
|
|
res, err := strconv.ParseInt(val, 10, 32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
return int32(res), nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get num_fds from /proc/(pid)/limits
|
|
|
|
|
func (p *Process) fillFromLimits() ([]RlimitStat, error) {
|
|
|
|
|
pid := p.Pid
|
|
|
|
|
limitsFile := common.HostProc(strconv.Itoa(int(pid)), "limits")
|
|
|
|
|
d, err := os.Open(limitsFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer d.Close()
|
|
|
|
|
|
|
|
|
|
var limitStats []RlimitStat
|
|
|
|
|
|
|
|
|
|
limitsScanner := bufio.NewScanner(d)
|
|
|
|
|
for limitsScanner.Scan() {
|
|
|
|
|
var statItem RlimitStat
|
|
|
|
|
|
|
|
|
|
str := strings.Fields(limitsScanner.Text())
|
|
|
|
|
|
|
|
|
|
// Remove the header line
|
|
|
|
|
if strings.Contains(str[len(str)-1], "Units") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assert that last item is a Hard limit
|
|
|
|
|
statItem.Hard, err = limitToInt(str[len(str)-1])
|
|
|
|
|
if err != nil {
|
|
|
|
|
// On error remove last item an try once again since it can be unit or header line
|
|
|
|
|
str = str[:len(str)-1]
|
|
|
|
|
statItem.Hard, err = limitToInt(str[len(str)-1])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Remove last item from string
|
|
|
|
|
str = str[:len(str)-1]
|
|
|
|
|
|
|
|
|
|
//Now last item is a Soft limit
|
|
|
|
|
statItem.Soft, err = limitToInt(str[len(str)-1])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// Remove last item from string
|
|
|
|
|
str = str[:len(str)-1]
|
|
|
|
|
|
|
|
|
|
//The rest is a stats name
|
|
|
|
|
resourceName := strings.Join(str, " ")
|
|
|
|
|
switch resourceName {
|
|
|
|
|
case "Max cpu time":
|
|
|
|
|
statItem.Resource = RLIMIT_CPU
|
|
|
|
|
case "Max file size":
|
|
|
|
|
statItem.Resource = RLIMIT_FSIZE
|
|
|
|
|
case "Max data size":
|
|
|
|
|
statItem.Resource = RLIMIT_DATA
|
|
|
|
|
case "Max stack size":
|
|
|
|
|
statItem.Resource = RLIMIT_STACK
|
|
|
|
|
case "Max core file size":
|
|
|
|
|
statItem.Resource = RLIMIT_CORE
|
|
|
|
|
case "Max resident set":
|
|
|
|
|
statItem.Resource = RLIMIT_RSS
|
|
|
|
|
case "Max processes":
|
|
|
|
|
statItem.Resource = RLIMIT_NPROC
|
|
|
|
|
case "Max open files":
|
|
|
|
|
statItem.Resource = RLIMIT_NOFILE
|
|
|
|
|
case "Max locked memory":
|
|
|
|
|
statItem.Resource = RLIMIT_MEMLOCK
|
|
|
|
|
case "Max address space":
|
|
|
|
|
statItem.Resource = RLIMIT_AS
|
|
|
|
|
case "Max file locks":
|
|
|
|
|
statItem.Resource = RLIMIT_LOCKS
|
|
|
|
|
case "Max pending signals":
|
|
|
|
|
statItem.Resource = RLIMIT_SIGPENDING
|
|
|
|
|
case "Max msgqueue size":
|
|
|
|
|
statItem.Resource = RLIMIT_MSGQUEUE
|
|
|
|
|
case "Max nice priority":
|
|
|
|
|
statItem.Resource = RLIMIT_NICE
|
|
|
|
|
case "Max realtime priority":
|
|
|
|
|
statItem.Resource = RLIMIT_RTPRIO
|
|
|
|
|
case "Max realtime timeout":
|
|
|
|
|
statItem.Resource = RLIMIT_RTTIME
|
|
|
|
|
default:
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
limitStats = append(limitStats, statItem)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := limitsScanner.Err(); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return limitStats, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get num_fds from /proc/(pid)/fd
|
|
|
|
|
func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) {
|
|
|
|
|
pid := p.Pid
|
|
|
|
|