Merge pull request #162 from shirou/load/add_misc
[load]all: add Misc in load to get miscellaneous host info from /proc…
This commit is contained in:
commit
3618a777a8
19
load/load.go
19
load/load.go
|
@ -2,8 +2,16 @@ package load
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
var invoke common.Invoker
|
||||
|
||||
func init() {
|
||||
invoke = common.Invoke{}
|
||||
}
|
||||
|
||||
type LoadAvgStat struct {
|
||||
Load1 float64 `json:"load1"`
|
||||
Load5 float64 `json:"load5"`
|
||||
|
@ -14,3 +22,14 @@ func (l LoadAvgStat) String() string {
|
|||
s, _ := json.Marshal(l)
|
||||
return string(s)
|
||||
}
|
||||
|
||||
type MiscStat struct {
|
||||
ProcsRunning int `json:"procsRunning"`
|
||||
ProcsBlocked int `json:"procsBlocked"`
|
||||
Ctxt int `json:"ctxt"`
|
||||
}
|
||||
|
||||
func (m MiscStat) String() string {
|
||||
s, _ := json.Marshal(m)
|
||||
return string(s)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
package load
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
@ -35,3 +37,32 @@ func LoadAvg() (*LoadAvgStat, error) {
|
|||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
||||
// Misc returnes miscellaneous host-wide statistics.
|
||||
// darwin use ps command to get process running/blocked count.
|
||||
// Almost same as FreeBSD implementation, but state is different.
|
||||
// U means 'Uninterruptible Sleep'.
|
||||
func Misc() (*MiscStat, error) {
|
||||
bin, err := exec.LookPath("ps")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := invoke.Command(bin, "axo", "state")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
|
||||
ret := MiscStat{}
|
||||
for _, l := range lines {
|
||||
if strings.Contains(l, "R") {
|
||||
ret.ProcsRunning += 1
|
||||
} else if strings.Contains(l, "U") {
|
||||
// uninterruptible sleep == blocked
|
||||
ret.ProcsBlocked += 1
|
||||
}
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
package load
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
@ -35,3 +37,29 @@ func LoadAvg() (*LoadAvgStat, error) {
|
|||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Misc returnes miscellaneous host-wide statistics.
|
||||
// darwin use ps command to get process running/blocked count.
|
||||
// Almost same as Darwin implementation, but state is different.
|
||||
func Misc() (*MiscStat, error) {
|
||||
bin, err := exec.LookPath("ps")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := invoke.Command(bin, "axo", "state")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
|
||||
ret := MiscStat{}
|
||||
for _, l := range lines {
|
||||
if strings.Contains(l, "R") {
|
||||
ret.ProcsRunning += 1
|
||||
} else if strings.Contains(l, "D") {
|
||||
ret.ProcsBlocked += 1
|
||||
}
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
|
|
@ -40,3 +40,40 @@ func LoadAvg() (*LoadAvgStat, error) {
|
|||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
||||
// Misc returnes miscellaneous host-wide statistics.
|
||||
// Note: the name should be changed near future.
|
||||
func Misc() (*MiscStat, error) {
|
||||
filename := common.HostProc("stat")
|
||||
out, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := &MiscStat{}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != 2 {
|
||||
continue
|
||||
}
|
||||
v, err := strconv.ParseInt(fields[1], 10, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "procs_running":
|
||||
ret.ProcsRunning = int(v)
|
||||
case "procs_blocked":
|
||||
ret.ProcsBlocked = int(v)
|
||||
case "ctxt":
|
||||
ret.Ctxt = int(v)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
|
@ -28,3 +28,27 @@ func TestLoadAvgStat_String(t *testing.T) {
|
|||
t.Errorf("LoadAvgStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMisc(t *testing.T) {
|
||||
v, err := Misc()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
|
||||
empty := &MiscStat{}
|
||||
if v == empty {
|
||||
t.Errorf("error load: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMiscStatString(t *testing.T) {
|
||||
v := MiscStat{
|
||||
ProcsRunning: 1,
|
||||
ProcsBlocked: 2,
|
||||
Ctxt: 3,
|
||||
}
|
||||
e := `{"procsRunning":1,"procsBlocked":2,"ctxt":3}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("TestMiscString string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,3 +11,9 @@ func LoadAvg() (*LoadAvgStat, error) {
|
|||
|
||||
return &ret, common.NotImplementedError
|
||||
}
|
||||
|
||||
func Misc() (*MiscStat, error) {
|
||||
ret := MiscStat{}
|
||||
|
||||
return &ret, common.NotImplementedError
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -673,7 +674,11 @@ func callLsof(arg string, pid int32) ([]string, error) {
|
|||
} else {
|
||||
cmd = []string{"-a", "-F" + arg, "-p", strconv.Itoa(int(pid))}
|
||||
}
|
||||
out, err := invoke.Command("/usr/bin/lsof", cmd...)
|
||||
lsof, err := exec.LookPath("lsof")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
out, err := invoke.Command(lsof, cmd...)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue