Vendored gopsutil to fix partial vendoring
This commit is contained in:
parent
0dd9606817
commit
192176b89e
|
@ -0,0 +1,61 @@
|
|||
gopsutil is distributed under BSD license reproduced below.
|
||||
|
||||
Copyright (c) 2014, WAKAYAMA Shirou
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the gopsutil authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
-------
|
||||
internal/common/binary.go in the gopsutil is copied and modifid from golang/encoding/binary.go.
|
||||
|
||||
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,6 +1,7 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
@ -12,6 +13,9 @@ import (
|
|||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
// TimesStat contains the amounts of time the CPU has spent performing different
|
||||
// kinds of work. Time units are in USER_HZ or Jiffies (typically hundredths of
|
||||
// a second). It is based on linux /proc/stat file.
|
||||
type TimesStat struct {
|
||||
CPU string `json:"cpu"`
|
||||
User float64 `json:"user"`
|
||||
|
@ -61,6 +65,10 @@ func init() {
|
|||
}
|
||||
|
||||
func Counts(logical bool) (int, error) {
|
||||
return CountsWithContext(context.Background(), logical)
|
||||
}
|
||||
|
||||
func CountsWithContext(ctx context.Context, logical bool) (int, error) {
|
||||
return runtime.NumCPU(), nil
|
||||
}
|
||||
|
||||
|
@ -134,6 +142,10 @@ func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
|
|||
// If an interval of 0 is given it will compare the current cpu times against the last call.
|
||||
// Returns one value per cpu, or a single value if percpu is set to false.
|
||||
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
|
||||
return PercentWithContext(context.Background(), interval, percpu)
|
||||
}
|
||||
|
||||
func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
|
||||
if interval <= 0 {
|
||||
return percentUsedFromLastCall(percpu)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -22,6 +23,10 @@ const (
|
|||
var ClocksPerSec = float64(128)
|
||||
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
return TimesWithContext(context.Background(), percpu)
|
||||
}
|
||||
|
||||
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
|
||||
if percpu {
|
||||
return perCPUTimes()
|
||||
}
|
||||
|
@ -31,6 +36,10 @@ func Times(percpu bool) ([]TimesStat, error) {
|
|||
|
||||
// Returns only one CPUInfoStat on FreeBSD
|
||||
func Info() ([]InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
|
||||
var ret []InfoStat
|
||||
sysctl, err := exec.LookPath("/usr/sbin/sysctl")
|
||||
if err != nil {
|
||||
|
|
|
@ -3,13 +3,23 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
return TimesWithContext(context.Background(), percpu)
|
||||
}
|
||||
|
||||
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
|
||||
return []TimesStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Info() ([]InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
|
||||
return []InfoStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
// sys/resource.h
|
||||
const (
|
||||
CPUser = 0
|
||||
CPNice = 1
|
||||
CPSys = 2
|
||||
CPIntr = 3
|
||||
CPIdle = 4
|
||||
CPUStates = 5
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var ClocksPerSec = float64(128)
|
||||
|
@ -27,6 +21,8 @@ var featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`)
|
|||
var featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`)
|
||||
var cpuEnd = regexp.MustCompile(`^Trying to mount root`)
|
||||
var cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`)
|
||||
var cpuTimesSize int
|
||||
var emptyTimes cpuTimes
|
||||
|
||||
func init() {
|
||||
getconf, err := exec.LookPath("/usr/bin/getconf")
|
||||
|
@ -43,97 +39,84 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func timeStat(name string, t *cpuTimes) *TimesStat {
|
||||
return &TimesStat{
|
||||
User: float64(t.User) / ClocksPerSec,
|
||||
Nice: float64(t.Nice) / ClocksPerSec,
|
||||
System: float64(t.Sys) / ClocksPerSec,
|
||||
Idle: float64(t.Idle) / ClocksPerSec,
|
||||
Irq: float64(t.Intr) / ClocksPerSec,
|
||||
CPU: name,
|
||||
}
|
||||
}
|
||||
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
var ret []TimesStat
|
||||
return TimesWithContext(context.Background(), percpu)
|
||||
}
|
||||
|
||||
var sysctlCall string
|
||||
var ncpu int
|
||||
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
|
||||
if percpu {
|
||||
sysctlCall = "kern.cp_times"
|
||||
ncpu, _ = Counts(true)
|
||||
} else {
|
||||
sysctlCall = "kern.cp_time"
|
||||
ncpu = 1
|
||||
buf, err := unix.SysctlRaw("kern.cp_times")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We can't do this in init due to the conflict with cpu.init()
|
||||
if cpuTimesSize == 0 {
|
||||
cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())
|
||||
}
|
||||
|
||||
ncpus := len(buf) / cpuTimesSize
|
||||
ret := make([]TimesStat, 0, ncpus)
|
||||
for i := 0; i < ncpus; i++ {
|
||||
times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))
|
||||
if *times == emptyTimes {
|
||||
// CPU not present
|
||||
continue
|
||||
}
|
||||
ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times))
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
cpuTimes, err := common.DoSysctrl(sysctlCall)
|
||||
buf, err := unix.SysctlRaw("kern.cp_time")
|
||||
if err != nil {
|
||||
return ret, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < ncpu; i++ {
|
||||
offset := CPUStates * i
|
||||
user, err := strconv.ParseFloat(cpuTimes[CPUser+offset], 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
nice, err := strconv.ParseFloat(cpuTimes[CPNice+offset], 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
sys, err := strconv.ParseFloat(cpuTimes[CPSys+offset], 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
idle, err := strconv.ParseFloat(cpuTimes[CPIdle+offset], 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
intr, err := strconv.ParseFloat(cpuTimes[CPIntr+offset], 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
c := TimesStat{
|
||||
User: float64(user / ClocksPerSec),
|
||||
Nice: float64(nice / ClocksPerSec),
|
||||
System: float64(sys / ClocksPerSec),
|
||||
Idle: float64(idle / ClocksPerSec),
|
||||
Irq: float64(intr / ClocksPerSec),
|
||||
}
|
||||
if !percpu {
|
||||
c.CPU = "cpu-total"
|
||||
} else {
|
||||
c.CPU = fmt.Sprintf("cpu%d", i)
|
||||
}
|
||||
|
||||
ret = append(ret, c)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
|
||||
return []TimesStat{*timeStat("cpu-total", times)}, nil
|
||||
}
|
||||
|
||||
// Returns only one InfoStat on FreeBSD. The information regarding core
|
||||
// count, however is accurate and it is assumed that all InfoStat attributes
|
||||
// are the same across CPUs.
|
||||
func Info() ([]InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
|
||||
const dmesgBoot = "/var/run/dmesg.boot"
|
||||
|
||||
c, num, err := parseDmesgBoot(dmesgBoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var vals []string
|
||||
if vals, err = common.DoSysctrl("hw.clockrate"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.Mhz, err = strconv.ParseFloat(vals[0], 64); err != nil {
|
||||
return nil, fmt.Errorf("unable to parse FreeBSD CPU clock rate: %v", err)
|
||||
}
|
||||
|
||||
if vals, err = common.DoSysctrl("hw.ncpu"); err != nil {
|
||||
var u32 uint32
|
||||
if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var i64 int64
|
||||
if i64, err = strconv.ParseInt(vals[0], 10, 32); err != nil {
|
||||
return nil, fmt.Errorf("unable to parse FreeBSD cores: %v", err)
|
||||
}
|
||||
c.Cores = int32(i64)
|
||||
c.Mhz = float64(u32)
|
||||
|
||||
if vals, err = common.DoSysctrl("hw.model"); err != nil {
|
||||
if u32, err = unix.SysctlUint32("hw.ncpu"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Cores = int32(u32)
|
||||
|
||||
if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.ModelName = strings.Join(vals, " ")
|
||||
|
||||
ret := make([]InfoStat, num)
|
||||
for i := 0; i < num; i++ {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package cpu
|
||||
|
||||
type cpuTimes struct {
|
||||
User uint32
|
||||
Nice uint32
|
||||
Sys uint32
|
||||
Intr uint32
|
||||
Idle uint32
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package cpu
|
||||
|
||||
type cpuTimes struct {
|
||||
User uint64
|
||||
Nice uint64
|
||||
Sys uint64
|
||||
Intr uint64
|
||||
Idle uint64
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func TestParseDmesgBoot(t *testing.T) {
|
||||
if runtime.GOOS != "freebsd" {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
var cpuTests = []struct {
|
||||
file string
|
||||
cpuNum int
|
||||
cores int32
|
||||
}{
|
||||
{"1cpu_2core.txt", 1, 2},
|
||||
{"1cpu_4core.txt", 1, 4},
|
||||
{"2cpu_4core.txt", 2, 4},
|
||||
}
|
||||
for _, tt := range cpuTests {
|
||||
v, num, err := parseDmesgBoot(filepath.Join("testdata", "freebsd", tt.file))
|
||||
if err != nil {
|
||||
t.Errorf("parseDmesgBoot failed(%s), %v", tt.file, err)
|
||||
}
|
||||
if num != tt.cpuNum {
|
||||
t.Errorf("parseDmesgBoot wrong length(%s), %v", tt.file, err)
|
||||
}
|
||||
if v.Cores != tt.cores {
|
||||
t.Errorf("parseDmesgBoot wrong core(%s), %v", tt.file, err)
|
||||
}
|
||||
if !common.StringsContains(v.Flags, "fpu") {
|
||||
t.Errorf("parseDmesgBoot fail to parse features(%s), %v", tt.file, err)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
@ -30,6 +31,10 @@ func init() {
|
|||
}
|
||||
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
return TimesWithContext(context.Background(), percpu)
|
||||
}
|
||||
|
||||
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
|
||||
filename := common.HostProc("stat")
|
||||
var lines = []string{}
|
||||
if percpu {
|
||||
|
@ -104,6 +109,10 @@ func finishCPUInfo(c *InfoStat) error {
|
|||
// For example a single socket board with two cores each with HT will
|
||||
// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
|
||||
func Info() ([]InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
|
||||
filename := common.HostProc("cpuinfo")
|
||||
lines, _ := common.ReadLines(filename)
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTimesEmpty(t *testing.T) {
|
||||
orig := os.Getenv("HOST_PROC")
|
||||
os.Setenv("HOST_PROC", "testdata/linux/times_empty")
|
||||
_, err := Times(true)
|
||||
if err != nil {
|
||||
t.Error("Times(true) failed")
|
||||
}
|
||||
_, err = Times(false)
|
||||
if err != nil {
|
||||
t.Error("Times(false) failed")
|
||||
}
|
||||
os.Setenv("HOST_PROC", orig)
|
||||
}
|
||||
|
||||
func TestCPUparseStatLine_424(t *testing.T) {
|
||||
orig := os.Getenv("HOST_PROC")
|
||||
os.Setenv("HOST_PROC", "testdata/linux/424/proc")
|
||||
{
|
||||
l, err := Times(true)
|
||||
if err != nil || len(l) == 0 {
|
||||
t.Error("Times(true) failed")
|
||||
}
|
||||
t.Logf("Times(true): %#v", l)
|
||||
}
|
||||
{
|
||||
l, err := Times(false)
|
||||
if err != nil || len(l) == 0 {
|
||||
t.Error("Times(false) failed")
|
||||
}
|
||||
t.Logf("Times(false): %#v", l)
|
||||
}
|
||||
os.Setenv("HOST_PROC", orig)
|
||||
}
|
|
@ -4,6 +4,7 @@ package cpu
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
@ -49,6 +50,10 @@ func init() {
|
|||
}
|
||||
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
return TimesWithContext(context.Background(), percpu)
|
||||
}
|
||||
|
||||
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
|
||||
var ret []TimesStat
|
||||
|
||||
var ncpu int
|
||||
|
@ -96,6 +101,10 @@ func Times(percpu bool) ([]TimesStat, error) {
|
|||
|
||||
// Returns only one (minimal) CPUInfoStat on OpenBSD
|
||||
func Info() ([]InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
|
||||
var ret []InfoStat
|
||||
|
||||
c := InfoStat{}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
@ -30,10 +31,18 @@ func init() {
|
|||
}
|
||||
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
return TimesWithContext(context.Background(), percpu)
|
||||
}
|
||||
|
||||
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
|
||||
return []TimesStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Info() ([]InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
|
||||
psrInfo, err := exec.LookPath("/usr/sbin/psrinfo")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot find psrinfo: %s", err)
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseISAInfo(t *testing.T) {
|
||||
cases := []struct {
|
||||
filename string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
"1cpu_1core_isainfo.txt",
|
||||
[]string{"rdseed", "adx", "avx2", "fma", "bmi2", "bmi1", "rdrand", "f16c", "vmx",
|
||||
"avx", "xsave", "pclmulqdq", "aes", "movbe", "sse4.2", "sse4.1", "ssse3", "popcnt",
|
||||
"tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8",
|
||||
"tsc", "fpu"},
|
||||
},
|
||||
{
|
||||
"2cpu_1core_isainfo.txt",
|
||||
[]string{"rdseed", "adx", "avx2", "fma", "bmi2", "bmi1", "rdrand", "f16c", "vmx",
|
||||
"avx", "xsave", "pclmulqdq", "aes", "movbe", "sse4.2", "sse4.1", "ssse3", "popcnt",
|
||||
"tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8",
|
||||
"tsc", "fpu"},
|
||||
},
|
||||
{
|
||||
"2cpu_8core_isainfo.txt",
|
||||
[]string{"vmx", "avx", "xsave", "pclmulqdq", "aes", "sse4.2", "sse4.1", "ssse3", "popcnt",
|
||||
"tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8",
|
||||
"tsc", "fpu"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
content, err := ioutil.ReadFile(filepath.Join("testdata", "solaris", tc.filename))
|
||||
if err != nil {
|
||||
t.Errorf("cannot read test case: %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(tc.expected)
|
||||
|
||||
flags, err := parseISAInfo(string(content))
|
||||
if err != nil {
|
||||
t.Fatalf("parseISAInfo: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tc.expected, flags) {
|
||||
t.Fatalf("Bad flags\nExpected: %v\n Actual: %v", tc.expected, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseProcessorInfo(t *testing.T) {
|
||||
cases := []struct {
|
||||
filename string
|
||||
expected []InfoStat
|
||||
}{
|
||||
{
|
||||
"1cpu_1core_psrinfo.txt",
|
||||
[]InfoStat{
|
||||
{CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "0", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312},
|
||||
},
|
||||
},
|
||||
{
|
||||
"2cpu_1core_psrinfo.txt",
|
||||
[]InfoStat{
|
||||
{CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "0", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312},
|
||||
{CPU: 1, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "1", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312},
|
||||
},
|
||||
},
|
||||
{
|
||||
"2cpu_8core_psrinfo.txt",
|
||||
[]InfoStat{
|
||||
{CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "0", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 1, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "1", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 2, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "2", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 3, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "3", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 4, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "4", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 5, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "5", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 6, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "6", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 7, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "7", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 8, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "0", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 9, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "1", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 10, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "2", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 11, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "3", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 12, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "4", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 13, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "5", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 14, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "6", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
{CPU: 15, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "7", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
content, err := ioutil.ReadFile(filepath.Join("testdata", "solaris", tc.filename))
|
||||
if err != nil {
|
||||
t.Errorf("cannot read test case: %s", err)
|
||||
}
|
||||
|
||||
cpus, err := parseProcessorInfo(string(content))
|
||||
|
||||
if !reflect.DeepEqual(tc.expected, cpus) {
|
||||
t.Fatalf("Bad Processor Info\nExpected: %v\n Actual: %v", tc.expected, cpus)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCpu_times(t *testing.T) {
|
||||
v, err := Times(false)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Error("could not get CPUs ", err)
|
||||
}
|
||||
empty := TimesStat{}
|
||||
for _, vv := range v {
|
||||
if vv == empty {
|
||||
t.Errorf("could not get CPU User: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCpu_counts(t *testing.T) {
|
||||
v, err := Counts(true)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if v == 0 {
|
||||
t.Errorf("could not get CPU counts: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUTimeStat_String(t *testing.T) {
|
||||
v := TimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 100.1,
|
||||
System: 200.1,
|
||||
Idle: 300.1,
|
||||
}
|
||||
e := `{"cpu":"cpu0","user":100.1,"system":200.1,"idle":300.1,"nice":0.0,"iowait":0.0,"irq":0.0,"softirq":0.0,"steal":0.0,"guest":0.0,"guestNice":0.0,"stolen":0.0}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("CPUTimesStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCpuInfo(t *testing.T) {
|
||||
v, err := Info()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Errorf("could not get CPU Info")
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.ModelName == "" {
|
||||
t.Errorf("could not get CPU Info: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testCPUPercent(t *testing.T, percpu bool) {
|
||||
numcpu := runtime.NumCPU()
|
||||
testCount := 3
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
testCount = 100
|
||||
v, err := Percent(time.Millisecond, percpu)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
// Skip CircleCI which CPU num is different
|
||||
if os.Getenv("CIRCLECI") != "true" {
|
||||
if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) {
|
||||
t.Fatalf("wrong number of entries from CPUPercent: %v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < testCount; i++ {
|
||||
duration := time.Duration(10) * time.Microsecond
|
||||
v, err := Percent(duration, percpu)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
for _, percent := range v {
|
||||
// Check for slightly greater then 100% to account for any rounding issues.
|
||||
if percent < 0.0 || percent > 100.0001*float64(numcpu) {
|
||||
t.Fatalf("CPUPercent value is invalid: %f", percent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testCPUPercentLastUsed(t *testing.T, percpu bool) {
|
||||
|
||||
numcpu := runtime.NumCPU()
|
||||
testCount := 10
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
testCount = 2
|
||||
v, err := Percent(time.Millisecond, percpu)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
// Skip CircleCI which CPU num is different
|
||||
if os.Getenv("CIRCLECI") != "true" {
|
||||
if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) {
|
||||
t.Fatalf("wrong number of entries from CPUPercent: %v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < testCount; i++ {
|
||||
v, err := Percent(0, percpu)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
for _, percent := range v {
|
||||
// Check for slightly greater then 100% to account for any rounding issues.
|
||||
if percent < 0.0 || percent > 100.0001*float64(numcpu) {
|
||||
t.Fatalf("CPUPercent value is invalid: %f", percent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCPUPercent(t *testing.T) {
|
||||
testCPUPercent(t, false)
|
||||
}
|
||||
|
||||
func TestCPUPercentPerCpu(t *testing.T) {
|
||||
testCPUPercent(t, true)
|
||||
}
|
||||
|
||||
func TestCPUPercentIntervalZero(t *testing.T) {
|
||||
testCPUPercentLastUsed(t, false)
|
||||
}
|
||||
|
||||
func TestCPUPercentIntervalZeroPerCPU(t *testing.T) {
|
||||
testCPUPercentLastUsed(t, true)
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
|
@ -45,6 +46,10 @@ type Win32_PerfFormattedData_PerfOS_System struct {
|
|||
|
||||
// Times returns times stat per cpu and combined for all CPUs
|
||||
func Times(percpu bool) ([]TimesStat, error) {
|
||||
return TimesWithContext(context.Background(), percpu)
|
||||
}
|
||||
|
||||
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
|
||||
if percpu {
|
||||
return perCPUTimes()
|
||||
}
|
||||
|
@ -78,11 +83,14 @@ func Times(percpu bool) ([]TimesStat, error) {
|
|||
}
|
||||
|
||||
func Info() ([]InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
|
||||
var ret []InfoStat
|
||||
var dst []Win32_Processor
|
||||
q := wmi.CreateQuery(&dst, "")
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
|
@ -112,18 +120,34 @@ func Info() ([]InfoStat, error) {
|
|||
// PerfInfo returns the performance counter's instance value for ProcessorInformation.
|
||||
// Name property is the key by which overall, per cpu and per core metric is known.
|
||||
func PerfInfo() ([]Win32_PerfFormattedData_Counters_ProcessorInformation, error) {
|
||||
return PerfInfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func PerfInfoWithContext(ctx context.Context) ([]Win32_PerfFormattedData_Counters_ProcessorInformation, error) {
|
||||
var ret []Win32_PerfFormattedData_Counters_ProcessorInformation
|
||||
|
||||
q := wmi.CreateQuery(&ret, "")
|
||||
err := wmi.Query(q, &ret)
|
||||
err := common.WMIQueryWithContext(ctx, q, &ret)
|
||||
if err != nil {
|
||||
return []Win32_PerfFormattedData_Counters_ProcessorInformation{}, err
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// ProcInfo returns processes count and processor queue length in the system.
|
||||
// There is a single queue for processor even on multiprocessors systems.
|
||||
func ProcInfo() ([]Win32_PerfFormattedData_PerfOS_System, error) {
|
||||
return ProcInfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func ProcInfoWithContext(ctx context.Context) ([]Win32_PerfFormattedData_PerfOS_System, error) {
|
||||
var ret []Win32_PerfFormattedData_PerfOS_System
|
||||
q := wmi.CreateQuery(&ret, "")
|
||||
err := wmi.Query(q, &ret)
|
||||
err := common.WMIQueryWithContext(ctx, q, &ret)
|
||||
if err != nil {
|
||||
return []Win32_PerfFormattedData_PerfOS_System{}, err
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"unsafe"
|
||||
|
||||
|
@ -11,6 +12,10 @@ import (
|
|||
)
|
||||
|
||||
func Partitions(all bool) ([]PartitionStat, error) {
|
||||
return PartitionsWithContext(context.Background(), all)
|
||||
}
|
||||
|
||||
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
||||
var ret []PartitionStat
|
||||
|
||||
count, err := Getfsstat(nil, MntWait)
|
||||
|
@ -88,6 +93,10 @@ func Partitions(all bool) ([]PartitionStat, error) {
|
|||
}
|
||||
|
||||
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
||||
return GetfsstatWithContext(context.Background(), buf, flags)
|
||||
}
|
||||
|
||||
func GetfsstatWithContext(ctx context.Context, buf []Statfs_t, flags int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
var bufsize uintptr
|
||||
if len(buf) > 0 {
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef struct
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
@ -34,6 +35,10 @@ import (
|
|||
)
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
if C.StartIOCounterFetch() == 0 {
|
||||
return nil, errors.New("Unable to fetch disk list")
|
||||
}
|
||||
|
|
|
@ -3,8 +3,16 @@
|
|||
|
||||
package disk
|
||||
|
||||
import "github.com/shirou/gopsutil/internal/common"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -2,16 +2,32 @@
|
|||
|
||||
package disk
|
||||
|
||||
import "github.com/shirou/gopsutil/internal/common"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Partitions(all bool) ([]PartitionStat, error) {
|
||||
return PartitionsWithContext(context.Background(), all)
|
||||
}
|
||||
|
||||
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
||||
return []PartitionStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Usage(path string) (*UsageStat, error) {
|
||||
return UsageWithContext(context.Background(), path)
|
||||
}
|
||||
|
||||
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package disk
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"path"
|
||||
"strconv"
|
||||
|
@ -15,6 +16,10 @@ import (
|
|||
)
|
||||
|
||||
func Partitions(all bool) ([]PartitionStat, error) {
|
||||
return PartitionsWithContext(context.Background(), all)
|
||||
}
|
||||
|
||||
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
||||
var ret []PartitionStat
|
||||
|
||||
// get length
|
||||
|
@ -96,6 +101,10 @@ func Partitions(all bool) ([]PartitionStat, error) {
|
|||
}
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
// statinfo->devinfo->devstat
|
||||
// /usr/include/devinfo.h
|
||||
ret := make(map[string]IOCountersStat)
|
||||
|
@ -150,6 +159,10 @@ func (b Bintime) Compute() float64 {
|
|||
// Getfsstat is borrowed from pkg/syscall/syscall_freebsd.go
|
||||
// change Statfs_t to Statfs in order to get more information
|
||||
func Getfsstat(buf []Statfs, flags int) (n int, err error) {
|
||||
return GetfsstatWithContext(context.Background(), buf, flags)
|
||||
}
|
||||
|
||||
func GetfsstatWithContext(ctx context.Context, buf []Statfs, flags int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
var bufsize uintptr
|
||||
if len(buf) > 0 {
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -216,6 +218,10 @@ var fsTypeMap = map[int64]string{
|
|||
// physical devices only (e.g. hard disks, cd-rom drives, USB keys)
|
||||
// and ignore all others (e.g. memory partitions such as /dev/shm)
|
||||
func Partitions(all bool) ([]PartitionStat, error) {
|
||||
return PartitionsWithContext(context.Background(), all)
|
||||
}
|
||||
|
||||
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
||||
filename := common.HostProc("self/mounts")
|
||||
lines, err := common.ReadLines(filename)
|
||||
if err != nil {
|
||||
|
@ -272,6 +278,10 @@ func getFileSystems() ([]string, error) {
|
|||
}
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
filename := common.HostProc("diskstats")
|
||||
lines, err := common.ReadLines(filename)
|
||||
if err != nil {
|
||||
|
@ -280,6 +290,11 @@ func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
|||
ret := make(map[string]IOCountersStat, 0)
|
||||
empty := IOCountersStat{}
|
||||
|
||||
// use only basename such as "/dev/sda1" to "sda1"
|
||||
for i, name := range names {
|
||||
names[i] = filepath.Base(name)
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 14 {
|
||||
|
@ -363,6 +378,10 @@ func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
|||
// GetDiskSerialNumber returns Serial Number of given device or empty string
|
||||
// on error. Name of device is expected, eg. /dev/sda
|
||||
func GetDiskSerialNumber(name string) string {
|
||||
return GetDiskSerialNumberWithContext(context.Background(), name)
|
||||
}
|
||||
|
||||
func GetDiskSerialNumberWithContext(ctx context.Context, name string) string {
|
||||
n := fmt.Sprintf("--name=%s", name)
|
||||
udevadm, err := exec.LookPath("/sbin/udevadm")
|
||||
if err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@ package disk
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"path"
|
||||
"unsafe"
|
||||
|
@ -13,6 +14,10 @@ import (
|
|||
)
|
||||
|
||||
func Partitions(all bool) ([]PartitionStat, error) {
|
||||
return PartitionsWithContext(context.Background(), all)
|
||||
}
|
||||
|
||||
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
||||
var ret []PartitionStat
|
||||
|
||||
// get length
|
||||
|
@ -64,9 +69,13 @@ func Partitions(all bool) ([]PartitionStat, error) {
|
|||
}
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
ret := make(map[string]IOCountersStat)
|
||||
|
||||
r, err := unix.Sysctl("hw.diskstats")
|
||||
r, err := unix.SysctlRaw("hw.diskstats")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -106,6 +115,10 @@ func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
|||
// Getfsstat is borrowed from pkg/syscall/syscall_freebsd.go
|
||||
// change Statfs_t to Statfs in order to get more information
|
||||
func Getfsstat(buf []Statfs, flags int) (n int, err error) {
|
||||
return GetfsstatWithContext(context.Background(), buf, flags)
|
||||
}
|
||||
|
||||
func GetfsstatWithContext(ctx context.Context, buf []Statfs, flags int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
var bufsize uintptr
|
||||
if len(buf) > 0 {
|
||||
|
@ -133,6 +146,10 @@ func parseDiskstats(buf []byte) (Diskstats, error) {
|
|||
}
|
||||
|
||||
func Usage(path string) (*UsageStat, error) {
|
||||
return UsageWithContext(context.Background(), path)
|
||||
}
|
||||
|
||||
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
|
||||
stat := unix.Statfs_t{}
|
||||
err := unix.Statfs(path, &stat)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
// +build solaris
|
||||
|
||||
package disk
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
// _DEFAULT_NUM_MOUNTS is set to `cat /etc/mnttab | wc -l` rounded up to the
|
||||
// nearest power of two.
|
||||
_DEFAULT_NUM_MOUNTS = 32
|
||||
|
||||
// _MNTTAB default place to read mount information
|
||||
_MNTTAB = "/etc/mnttab"
|
||||
)
|
||||
|
||||
var (
|
||||
// A blacklist of read-only virtual filesystems. Writable filesystems are of
|
||||
// operational concern and must not be included in this list.
|
||||
fsTypeBlacklist = map[string]struct{}{
|
||||
"ctfs": struct{}{},
|
||||
"dev": struct{}{},
|
||||
"fd": struct{}{},
|
||||
"lofs": struct{}{},
|
||||
"lxproc": struct{}{},
|
||||
"mntfs": struct{}{},
|
||||
"objfs": struct{}{},
|
||||
"proc": struct{}{},
|
||||
}
|
||||
)
|
||||
|
||||
func Partitions(all bool) ([]PartitionStat, error) {
|
||||
return PartitionsWithContext(context.Background(), all)
|
||||
}
|
||||
|
||||
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
||||
ret := make([]PartitionStat, 0, _DEFAULT_NUM_MOUNTS)
|
||||
|
||||
// Scan mnttab(4)
|
||||
f, err := os.Open(_MNTTAB)
|
||||
if err != nil {
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = f.Close()
|
||||
} else {
|
||||
f.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Split(scanner.Text(), "\t")
|
||||
|
||||
if _, found := fsTypeBlacklist[fields[2]]; found {
|
||||
continue
|
||||
}
|
||||
|
||||
ret = append(ret, PartitionStat{
|
||||
// NOTE(seanc@): Device isn't exactly accurate: from mnttab(4): "The name
|
||||
// of the resource that has been mounted." Ideally this value would come
|
||||
// from Statvfs_t.Fsid but I'm leaving it to the caller to traverse
|
||||
// unix.Statvfs().
|
||||
Device: fields[0],
|
||||
Mountpoint: fields[1],
|
||||
Fstype: fields[2],
|
||||
Opts: fields[3],
|
||||
})
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("unable to scan %q: %v", _MNTTAB, err)
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Usage(path string) (*UsageStat, error) {
|
||||
return UsageWithContext(context.Background(), path)
|
||||
}
|
||||
|
||||
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
|
||||
statvfs := unix.Statvfs_t{}
|
||||
if err := unix.Statvfs(path, &statvfs); err != nil {
|
||||
return nil, fmt.Errorf("unable to call statvfs(2) on %q: %v", path, err)
|
||||
}
|
||||
|
||||
usageStat := &UsageStat{
|
||||
Path: path,
|
||||
Fstype: common.IntToString(statvfs.Basetype[:]),
|
||||
Total: statvfs.Blocks * statvfs.Frsize,
|
||||
Free: statvfs.Bfree * statvfs.Frsize,
|
||||
Used: (statvfs.Blocks - statvfs.Bfree) * statvfs.Frsize,
|
||||
|
||||
// NOTE: ZFS (and FreeBZSD's UFS2) use dynamic inode/dnode allocation.
|
||||
// Explicitly return a near-zero value for InodesUsedPercent so that nothing
|
||||
// attempts to garbage collect based on a lack of available inodes/dnodes.
|
||||
// Similarly, don't use the zero value to prevent divide-by-zero situations
|
||||
// and inject a faux near-zero value. Filesystems evolve. Has your
|
||||
// filesystem evolved? Probably not if you care about the number of
|
||||
// available inodes.
|
||||
InodesTotal: 1024.0 * 1024.0,
|
||||
InodesUsed: 1024.0,
|
||||
InodesFree: math.MaxUint64,
|
||||
InodesUsedPercent: (1024.0 / (1024.0 * 1024.0)) * 100.0,
|
||||
}
|
||||
|
||||
usageStat.UsedPercent = (float64(usageStat.Used) / float64(usageStat.Total)) * 100.0
|
||||
|
||||
return usageStat, nil
|
||||
}
|
|
@ -2,12 +2,20 @@
|
|||
|
||||
package disk
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Usage returns a file system usage. path is a filessytem path such
|
||||
// as "/", not device file path like "/dev/vda1". If you want to use
|
||||
// a return value of disk.Partitions, use "Mountpoint" not "Device".
|
||||
func Usage(path string) (*UsageStat, error) {
|
||||
return UsageWithContext(context.Background(), path)
|
||||
}
|
||||
|
||||
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
|
||||
stat := unix.Statfs_t{}
|
||||
err := unix.Statfs(path, &stat)
|
||||
if err != nil {
|
||||
|
|
|
@ -4,9 +4,9 @@ package disk
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"unsafe"
|
||||
|
||||
"github.com/StackExchange/wmi"
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
@ -36,6 +36,10 @@ type Win32_PerfFormattedData struct {
|
|||
const WaitMSec = 500
|
||||
|
||||
func Usage(path string) (*UsageStat, error) {
|
||||
return UsageWithContext(context.Background(), path)
|
||||
}
|
||||
|
||||
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
|
||||
ret := &UsageStat{}
|
||||
|
||||
lpFreeBytesAvailable := int64(0)
|
||||
|
@ -64,6 +68,10 @@ func Usage(path string) (*UsageStat, error) {
|
|||
}
|
||||
|
||||
func Partitions(all bool) ([]PartitionStat, error) {
|
||||
return PartitionsWithContext(context.Background(), all)
|
||||
}
|
||||
|
||||
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
|
||||
var ret []PartitionStat
|
||||
lpBuffer := make([]byte, 254)
|
||||
diskret, _, err := procGetLogicalDriveStringsW.Call(
|
||||
|
@ -129,10 +137,14 @@ func Partitions(all bool) ([]PartitionStat, error) {
|
|||
}
|
||||
|
||||
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), names...)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
|
||||
ret := make(map[string]IOCountersStat, 0)
|
||||
var dst []Win32_PerfFormattedData
|
||||
|
||||
err := wmi.Query("SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk ", &dst)
|
||||
err := common.WMIQueryWithContext(ctx, "SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk", &dst)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
// +build ignore
|
||||
// Hand writing: _Ctype_struct___0
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
|
||||
*/
|
||||
|
||||
package disk
|
||||
|
||||
/*
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <devstat.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
// because statinfo has long double snap_time, redefine with changing long long
|
||||
struct statinfo2 {
|
||||
long cp_time[CPUSTATES];
|
||||
long tk_nin;
|
||||
long tk_nout;
|
||||
struct devinfo *dinfo;
|
||||
long long snap_time;
|
||||
};
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
sizeofLongDouble = C.sizeof_longlong
|
||||
|
||||
DEVSTAT_NO_DATA = 0x00
|
||||
DEVSTAT_READ = 0x01
|
||||
DEVSTAT_WRITE = 0x02
|
||||
DEVSTAT_FREE = 0x03
|
||||
|
||||
// from sys/mount.h
|
||||
MNT_RDONLY = 0x00000001 /* read only filesystem */
|
||||
MNT_SYNCHRONOUS = 0x00000002 /* filesystem written synchronously */
|
||||
MNT_NOEXEC = 0x00000004 /* can't exec from filesystem */
|
||||
MNT_NOSUID = 0x00000008 /* don't honor setuid bits on fs */
|
||||
MNT_UNION = 0x00000020 /* union with underlying filesystem */
|
||||
MNT_ASYNC = 0x00000040 /* filesystem written asynchronously */
|
||||
MNT_SUIDDIR = 0x00100000 /* special handling of SUID on dirs */
|
||||
MNT_SOFTDEP = 0x00200000 /* soft updates being done */
|
||||
MNT_NOSYMFOLLOW = 0x00400000 /* do not follow symlinks */
|
||||
MNT_GJOURNAL = 0x02000000 /* GEOM journal support enabled */
|
||||
MNT_MULTILABEL = 0x04000000 /* MAC support for individual objects */
|
||||
MNT_ACLS = 0x08000000 /* ACL support enabled */
|
||||
MNT_NOATIME = 0x10000000 /* disable update of file access time */
|
||||
MNT_NOCLUSTERR = 0x40000000 /* disable cluster read */
|
||||
MNT_NOCLUSTERW = 0x80000000 /* disable cluster write */
|
||||
MNT_NFS4ACLS = 0x00000010
|
||||
|
||||
MNT_WAIT = 1 /* synchronously wait for I/O to complete */
|
||||
MNT_NOWAIT = 2 /* start all I/O, but do not wait for it */
|
||||
MNT_LAZY = 3 /* push data not written by filesystem syncer */
|
||||
MNT_SUSPEND = 4 /* Suspend file system after sync */
|
||||
)
|
||||
|
||||
const (
|
||||
sizeOfDevstat = C.sizeof_struct_devstat
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
_C_long_double C.longlong
|
||||
)
|
||||
|
||||
type Statfs C.struct_statfs
|
||||
type Fsid C.struct_fsid
|
||||
|
||||
type Devstat C.struct_devstat
|
||||
type Bintime C.struct_bintime
|
|
@ -1,70 +0,0 @@
|
|||
// +build ignore
|
||||
// Hand writing: _Ctype_struct___0
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
package disk
|
||||
|
||||
/*
|
||||
#include <sys/types.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
sizeofLongDouble = C.sizeof_longlong
|
||||
|
||||
DEVSTAT_NO_DATA = 0x00
|
||||
DEVSTAT_READ = 0x01
|
||||
DEVSTAT_WRITE = 0x02
|
||||
DEVSTAT_FREE = 0x03
|
||||
|
||||
// from sys/mount.h
|
||||
MNT_RDONLY = 0x00000001 /* read only filesystem */
|
||||
MNT_SYNCHRONOUS = 0x00000002 /* filesystem written synchronously */
|
||||
MNT_NOEXEC = 0x00000004 /* can't exec from filesystem */
|
||||
MNT_NOSUID = 0x00000008 /* don't honor setuid bits on fs */
|
||||
MNT_NODEV = 0x00000010 /* don't interpret special files */
|
||||
MNT_ASYNC = 0x00000040 /* filesystem written asynchronously */
|
||||
|
||||
MNT_WAIT = 1 /* synchronously wait for I/O to complete */
|
||||
MNT_NOWAIT = 2 /* start all I/O, but do not wait for it */
|
||||
MNT_LAZY = 3 /* push data not written by filesystem syncer */
|
||||
)
|
||||
|
||||
const (
|
||||
sizeOfDiskstats = C.sizeof_struct_diskstats
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
_C_long_double C.longlong
|
||||
)
|
||||
|
||||
type Statfs C.struct_statfs
|
||||
type Diskstats C.struct_diskstats
|
||||
type Fsid C.fsid_t
|
||||
type Timeval C.struct_timeval
|
||||
|
||||
type Diskstat C.struct_diskstat
|
||||
type Bintime C.struct_bintime
|
|
@ -4,6 +4,7 @@ package host
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -23,6 +24,10 @@ import (
|
|||
const USER_PROCESS = 7
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
PlatformFamily: "darwin",
|
||||
|
@ -77,6 +82,10 @@ func Info() (*InfoStat, error) {
|
|||
var cachedBootTime uint64
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
return BootTimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
||||
t := atomic.LoadUint64(&cachedBootTime)
|
||||
if t != 0 {
|
||||
return t, nil
|
||||
|
@ -102,6 +111,10 @@ func uptime(boot uint64) uint64 {
|
|||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return UptimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -110,6 +123,10 @@ func Uptime() (uint64, error) {
|
|||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
return UsersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
||||
utmpfile := "/var/run/utmpx"
|
||||
var ret []UserStat
|
||||
|
||||
|
@ -154,6 +171,10 @@ func Users() ([]UserStat, error) {
|
|||
}
|
||||
|
||||
func PlatformInformation() (string, string, string, error) {
|
||||
return PlatformInformationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
|
||||
platform := ""
|
||||
family := ""
|
||||
pver := ""
|
||||
|
@ -181,10 +202,18 @@ func PlatformInformation() (string, string, string, error) {
|
|||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
return VirtualizationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
||||
return "", "", common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func KernelVersion() (string, error) {
|
||||
return KernelVersionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
||||
_, _, version, err := PlatformInformation()
|
||||
return version, err
|
||||
}
|
||||
|
|
|
@ -6,8 +6,13 @@ package host
|
|||
// #cgo LDFLAGS: -framework IOKit
|
||||
// #include "include/smc.c"
|
||||
import "C"
|
||||
import "context"
|
||||
|
||||
func SensorsTemperatures() ([]TemperatureStat, error) {
|
||||
return SensorsTemperaturesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
||||
temperatureKeys := []string{
|
||||
C.AMBIENT_AIR_0,
|
||||
C.AMBIENT_AIR_1,
|
||||
|
|
|
@ -3,8 +3,16 @@
|
|||
|
||||
package host
|
||||
|
||||
import "github.com/shirou/gopsutil/internal/common"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func SensorsTemperatures() ([]TemperatureStat, error) {
|
||||
return SensorsTemperaturesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
||||
return []TemperatureStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -2,28 +2,56 @@
|
|||
|
||||
package host
|
||||
|
||||
import "github.com/shirou/gopsutil/internal/common"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
return BootTimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
||||
return 0, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return UptimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
||||
return 0, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
return UsersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
||||
return []UserStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
return VirtualizationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
||||
return "", "", common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func KernelVersion() (string, error) {
|
||||
return KernelVersionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
||||
return "", common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -4,19 +4,21 @@ package host
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -26,6 +28,10 @@ const (
|
|||
)
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
PlatformFamily: "freebsd",
|
||||
|
@ -61,9 +67,9 @@ func Info() (*InfoStat, error) {
|
|||
ret.Procs = uint64(len(procs))
|
||||
}
|
||||
|
||||
values, err := common.DoSysctrl("kern.hostuuid")
|
||||
if err == nil && len(values) == 1 && values[0] != "" {
|
||||
ret.HostID = strings.ToLower(values[0])
|
||||
hostid, err := unix.Sysctl("kern.hostuuid")
|
||||
if err == nil && hostid != "" {
|
||||
ret.HostID = strings.ToLower(hostid)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
@ -73,23 +79,21 @@ func Info() (*InfoStat, error) {
|
|||
var cachedBootTime uint64
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
return BootTimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
||||
t := atomic.LoadUint64(&cachedBootTime)
|
||||
if t != 0 {
|
||||
return t, nil
|
||||
}
|
||||
values, err := common.DoSysctrl("kern.boottime")
|
||||
buf, err := unix.SysctlRaw("kern.boottime")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
|
||||
v := strings.Replace(values[2], ",", "", 1)
|
||||
|
||||
boottime, err := strconv.ParseUint(v, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
t = uint64(boottime)
|
||||
atomic.StoreUint64(&cachedBootTime, t)
|
||||
tv := *(*syscall.Timeval)(unsafe.Pointer((&buf[0])))
|
||||
atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec))
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
@ -99,6 +103,10 @@ func uptime(boot uint64) uint64 {
|
|||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return UptimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -107,6 +115,10 @@ func Uptime() (uint64, error) {
|
|||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
return UsersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
||||
utmpfile := "/var/run/utx.active"
|
||||
if !common.PathExists(utmpfile) {
|
||||
utmpfile = "/var/run/utmp" // before 9.0
|
||||
|
@ -152,6 +164,10 @@ func Users() ([]UserStat, error) {
|
|||
}
|
||||
|
||||
func PlatformInformation() (string, string, string, error) {
|
||||
return PlatformInformationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
|
||||
platform := ""
|
||||
family := ""
|
||||
version := ""
|
||||
|
@ -174,6 +190,10 @@ func PlatformInformation() (string, string, string, error) {
|
|||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
return VirtualizationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
||||
return "", "", common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
|
@ -217,10 +237,18 @@ func getUsersFromUtmp(utmpfile string) ([]UserStat, error) {
|
|||
}
|
||||
|
||||
func SensorsTemperatures() ([]TemperatureStat, error) {
|
||||
return SensorsTemperaturesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
||||
return []TemperatureStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func KernelVersion() (string, error) {
|
||||
return KernelVersionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
||||
_, _, version, err := PlatformInformation()
|
||||
return version, err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package host
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -31,6 +32,10 @@ type LSB struct {
|
|||
const USER_PROCESS = 7
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
}
|
||||
|
@ -91,11 +96,26 @@ var cachedBootTime uint64
|
|||
|
||||
// BootTime returns the system boot time expressed in seconds since the epoch.
|
||||
func BootTime() (uint64, error) {
|
||||
return BootTimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
||||
t := atomic.LoadUint64(&cachedBootTime)
|
||||
if t != 0 {
|
||||
return t, nil
|
||||
}
|
||||
filename := common.HostProc("stat")
|
||||
|
||||
system, role, err := Virtualization()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
statFile := "stat"
|
||||
if system == "lxc" && role == "guest" {
|
||||
// if lxc, /proc/uptime is used.
|
||||
statFile = "uptime"
|
||||
}
|
||||
|
||||
filename := common.HostProc(statFile)
|
||||
lines, err := common.ReadLines(filename)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -124,6 +144,10 @@ func uptime(boot uint64) uint64 {
|
|||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return UptimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -132,7 +156,11 @@ func Uptime() (uint64, error) {
|
|||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
utmpfile := "/var/run/utmp"
|
||||
return UsersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
||||
utmpfile := common.HostVar("run/utmp")
|
||||
|
||||
file, err := os.Open(utmpfile)
|
||||
if err != nil {
|
||||
|
@ -249,6 +277,10 @@ func getLSB() (*LSB, error) {
|
|||
}
|
||||
|
||||
func PlatformInformation() (platform string, family string, version string, err error) {
|
||||
return PlatformInformationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) {
|
||||
|
||||
lsb, err := getLSB()
|
||||
if err != nil {
|
||||
|
@ -371,6 +403,10 @@ func PlatformInformation() (platform string, family string, version string, err
|
|||
}
|
||||
|
||||
func KernelVersion() (version string, err error) {
|
||||
return KernelVersionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func KernelVersionWithContext(ctx context.Context) (version string, err error) {
|
||||
filename := common.HostProc("sys/kernel/osrelease")
|
||||
if common.PathExists(filename) {
|
||||
contents, err := common.ReadLines(filename)
|
||||
|
@ -430,6 +466,10 @@ func getSusePlatform(contents []string) string {
|
|||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
return VirtualizationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
||||
var system string
|
||||
var role string
|
||||
|
||||
|
@ -533,6 +573,10 @@ func Virtualization() (string, string, error) {
|
|||
}
|
||||
|
||||
func SensorsTemperatures() ([]TemperatureStat, error) {
|
||||
return SensorsTemperaturesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
||||
var temperatures []TemperatureStat
|
||||
files, err := filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_*"))
|
||||
if err != nil {
|
||||
|
@ -541,28 +585,52 @@ func SensorsTemperatures() ([]TemperatureStat, error) {
|
|||
if len(files) == 0 {
|
||||
// CentOS has an intermediate /device directory:
|
||||
// https://github.com/giampaolo/psutil/issues/971
|
||||
files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_*"))
|
||||
files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/device/temp*_*"))
|
||||
if err != nil {
|
||||
return temperatures, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, match := range files {
|
||||
match = strings.Split(match, "_")[0]
|
||||
name, err := ioutil.ReadFile(filepath.Join(filepath.Dir(match), "name"))
|
||||
// example directory
|
||||
// device/ temp1_crit_alarm temp2_crit_alarm temp3_crit_alarm temp4_crit_alarm temp5_crit_alarm temp6_crit_alarm temp7_crit_alarm
|
||||
// name temp1_input temp2_input temp3_input temp4_input temp5_input temp6_input temp7_input
|
||||
// power/ temp1_label temp2_label temp3_label temp4_label temp5_label temp6_label temp7_label
|
||||
// subsystem/ temp1_max temp2_max temp3_max temp4_max temp5_max temp6_max temp7_max
|
||||
// temp1_crit temp2_crit temp3_crit temp4_crit temp5_crit temp6_crit temp7_crit uevent
|
||||
for _, file := range files {
|
||||
filename := strings.Split(filepath.Base(file), "_")
|
||||
if filename[1] == "label" {
|
||||
// Do not try to read the temperature of the label file
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the label of the temperature you are reading
|
||||
var label string
|
||||
c, _ := ioutil.ReadFile(filepath.Join(filepath.Dir(file), filename[0]+"_label"))
|
||||
if c != nil {
|
||||
//format the label from "Core 0" to "core0_"
|
||||
label = fmt.Sprintf("%s_", strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(c))), " "), ""))
|
||||
}
|
||||
|
||||
// Get the name of the tempearture you are reading
|
||||
name, err := ioutil.ReadFile(filepath.Join(filepath.Dir(file), "name"))
|
||||
if err != nil {
|
||||
return temperatures, err
|
||||
}
|
||||
current, err := ioutil.ReadFile(match + "_input")
|
||||
|
||||
// Get the temperature reading
|
||||
current, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return temperatures, err
|
||||
}
|
||||
temperature, err := strconv.ParseFloat(string(current), 64)
|
||||
temperature, err := strconv.ParseFloat(strings.TrimSpace(string(current)), 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
tempName := strings.TrimSpace(strings.ToLower(string(strings.Join(filename[1:], ""))))
|
||||
temperatures = append(temperatures, TemperatureStat{
|
||||
SensorKey: string(name),
|
||||
SensorKey: fmt.Sprintf("%s_%s%s", strings.TrimSpace(string(name)), label, tempName),
|
||||
Temperature: temperature / 1000.0,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_linux.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x4
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x4
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int32
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
Id [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv timeval
|
||||
Addr_v6 [4]int32
|
||||
X__unused [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type timeval struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_linux.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x4
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x4
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int32
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
Id [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv timeval
|
||||
Addr_v6 [4]int32
|
||||
X__unused [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type timeval struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// +build linux
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetRedhatishVersion(t *testing.T) {
|
||||
var ret string
|
||||
c := []string{"Rawhide"}
|
||||
ret = getRedhatishVersion(c)
|
||||
if ret != "rawhide" {
|
||||
t.Errorf("Could not get version rawhide: %v", ret)
|
||||
}
|
||||
|
||||
c = []string{"Fedora release 15 (Lovelock)"}
|
||||
ret = getRedhatishVersion(c)
|
||||
if ret != "15" {
|
||||
t.Errorf("Could not get version fedora: %v", ret)
|
||||
}
|
||||
|
||||
c = []string{"Enterprise Linux Server release 5.5 (Carthage)"}
|
||||
ret = getRedhatishVersion(c)
|
||||
if ret != "5.5" {
|
||||
t.Errorf("Could not get version redhat enterprise: %v", ret)
|
||||
}
|
||||
|
||||
c = []string{""}
|
||||
ret = getRedhatishVersion(c)
|
||||
if ret != "" {
|
||||
t.Errorf("Could not get version with no value: %v", ret)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRedhatishPlatform(t *testing.T) {
|
||||
var ret string
|
||||
c := []string{"red hat"}
|
||||
ret = getRedhatishPlatform(c)
|
||||
if ret != "redhat" {
|
||||
t.Errorf("Could not get platform redhat: %v", ret)
|
||||
}
|
||||
|
||||
c = []string{"Fedora release 15 (Lovelock)"}
|
||||
ret = getRedhatishPlatform(c)
|
||||
if ret != "fedora" {
|
||||
t.Errorf("Could not get platform fedora: %v", ret)
|
||||
}
|
||||
|
||||
c = []string{"Enterprise Linux Server release 5.5 (Carthage)"}
|
||||
ret = getRedhatishPlatform(c)
|
||||
if ret != "enterprise" {
|
||||
t.Errorf("Could not get platform redhat enterprise: %v", ret)
|
||||
}
|
||||
|
||||
c = []string{""}
|
||||
ret = getRedhatishPlatform(c)
|
||||
if ret != "" {
|
||||
t.Errorf("Could not get platform with no value: %v", ret)
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ package host
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -25,6 +26,10 @@ const (
|
|||
)
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
PlatformFamily: "openbsd",
|
||||
|
@ -62,6 +67,10 @@ func Info() (*InfoStat, error) {
|
|||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
return BootTimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
||||
val, err := common.DoSysctrl("kern.boottime")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -80,6 +89,10 @@ func uptime(boot uint64) uint64 {
|
|||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return UptimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -88,6 +101,10 @@ func Uptime() (uint64, error) {
|
|||
}
|
||||
|
||||
func PlatformInformation() (string, string, string, error) {
|
||||
return PlatformInformationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
|
||||
platform := ""
|
||||
family := ""
|
||||
version := ""
|
||||
|
@ -110,10 +127,18 @@ func PlatformInformation() (string, string, string, error) {
|
|||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
return VirtualizationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
||||
return "", "", common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
return UsersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
||||
var ret []UserStat
|
||||
utmpfile := "/var/run/utmp"
|
||||
file, err := os.Open(utmpfile)
|
||||
|
@ -153,10 +178,18 @@ func Users() ([]UserStat, error) {
|
|||
}
|
||||
|
||||
func SensorsTemperatures() ([]TemperatureStat, error) {
|
||||
return SensorsTemperaturesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
||||
return []TemperatureStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func KernelVersion() (string, error) {
|
||||
return KernelVersionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
||||
_, _, version, err := PlatformInformation()
|
||||
return version, err
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package host
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -17,6 +18,10 @@ import (
|
|||
)
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
||||
result := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
}
|
||||
|
@ -142,6 +147,10 @@ func Info() (*InfoStat, error) {
|
|||
var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`)
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
return BootTimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
||||
kstat, err := exec.LookPath("/usr/bin/kstat")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -161,6 +170,10 @@ func BootTime() (uint64, error) {
|
|||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return UptimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
||||
bootTime, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -173,18 +186,34 @@ func uptimeSince(since uint64) uint64 {
|
|||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
return UsersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
||||
return []UserStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func SensorsTemperatures() ([]TemperatureStat, error) {
|
||||
return SensorsTemperaturesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
||||
return []TemperatureStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
return VirtualizationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
||||
return "", "", common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func KernelVersion() (string, error) {
|
||||
return KernelVersionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
||||
// Parse versions from output of `uname(1)`
|
||||
uname, err := exec.LookPath("/usr/bin/uname")
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
package host
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHostInfo(t *testing.T) {
|
||||
v, err := Info()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
empty := &InfoStat{}
|
||||
if v == empty {
|
||||
t.Errorf("Could not get hostinfo %v", v)
|
||||
}
|
||||
if v.Procs == 0 {
|
||||
t.Errorf("Could not determine the number of host processes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUptime(t *testing.T) {
|
||||
if os.Getenv("CIRCLECI") == "true" {
|
||||
t.Skip("Skip CI")
|
||||
}
|
||||
|
||||
v, err := Uptime()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if v == 0 {
|
||||
t.Errorf("Could not get up time %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoot_time(t *testing.T) {
|
||||
if os.Getenv("CIRCLECI") == "true" {
|
||||
t.Skip("Skip CI")
|
||||
}
|
||||
v, err := BootTime()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if v == 0 {
|
||||
t.Errorf("Could not get boot time %v", v)
|
||||
}
|
||||
if v < 946652400 {
|
||||
t.Errorf("Invalid Boottime, older than 2000-01-01")
|
||||
}
|
||||
t.Logf("first boot time: %d", v)
|
||||
|
||||
v2, err := BootTime()
|
||||
if v != v2 {
|
||||
t.Errorf("cached boot time is different")
|
||||
}
|
||||
t.Logf("second boot time: %d", v2)
|
||||
}
|
||||
|
||||
func TestUsers(t *testing.T) {
|
||||
v, err := Users()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
empty := UserStat{}
|
||||
if len(v) == 0 {
|
||||
t.Fatal("Users is empty")
|
||||
}
|
||||
for _, u := range v {
|
||||
if u == empty {
|
||||
t.Errorf("Could not Users %v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostInfoStat_String(t *testing.T) {
|
||||
v := InfoStat{
|
||||
Hostname: "test",
|
||||
Uptime: 3000,
|
||||
Procs: 100,
|
||||
OS: "linux",
|
||||
Platform: "ubuntu",
|
||||
BootTime: 1447040000,
|
||||
HostID: "edfd25ff-3c9c-b1a4-e660-bd826495ad35",
|
||||
}
|
||||
e := `{"hostname":"test","uptime":3000,"bootTime":1447040000,"procs":100,"os":"linux","platform":"ubuntu","platformFamily":"","platformVersion":"","kernelVersion":"","virtualizationSystem":"","virtualizationRole":"","hostid":"edfd25ff-3c9c-b1a4-e660-bd826495ad35"}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("HostInfoStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserStat_String(t *testing.T) {
|
||||
v := UserStat{
|
||||
User: "user",
|
||||
Terminal: "term",
|
||||
Host: "host",
|
||||
Started: 100,
|
||||
}
|
||||
e := `{"user":"user","terminal":"term","host":"host","started":100}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("UserStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostGuid(t *testing.T) {
|
||||
hi, err := Info()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if hi.HostID == "" {
|
||||
t.Error("Host id is empty")
|
||||
} else {
|
||||
t.Logf("Host id value: %v", hi.HostID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemperatureStat_String(t *testing.T) {
|
||||
v := TemperatureStat{
|
||||
SensorKey: "CPU",
|
||||
Temperature: 1.1,
|
||||
}
|
||||
s := `{"sensorKey":"CPU","sensorTemperature":1.1}`
|
||||
if s != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("TemperatureStat string is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualization(t *testing.T) {
|
||||
system, role, err := Virtualization()
|
||||
if err != nil {
|
||||
t.Errorf("Virtualization() failed, %v", err)
|
||||
}
|
||||
if system == "" || role == "" {
|
||||
t.Errorf("Virtualization() retuns empty system or role: %s, %s", system, role)
|
||||
}
|
||||
|
||||
t.Logf("Virtualization(): %s, %s", system, role)
|
||||
}
|
||||
|
||||
func TestKernelVersion(t *testing.T) {
|
||||
version, err := KernelVersion()
|
||||
if err != nil {
|
||||
t.Errorf("KernelVersion() failed, %v", err)
|
||||
}
|
||||
if version == "" {
|
||||
t.Errorf("KernelVersion() retuns empty: %s", version)
|
||||
}
|
||||
|
||||
t.Logf("KernelVersion(): %s", version)
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
@ -31,6 +32,10 @@ type Win32_OperatingSystem struct {
|
|||
}
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return InfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
}
|
||||
|
@ -43,7 +48,7 @@ func Info() (*InfoStat, error) {
|
|||
}
|
||||
|
||||
{
|
||||
platform, family, version, err := PlatformInformation()
|
||||
platform, family, version, err := PlatformInformationWithContext(ctx)
|
||||
if err == nil {
|
||||
ret.Platform = platform
|
||||
ret.PlatformFamily = family
|
||||
|
@ -107,9 +112,13 @@ func getMachineGuid() (string, error) {
|
|||
}
|
||||
|
||||
func GetOSInfo() (Win32_OperatingSystem, error) {
|
||||
return GetOSInfoWithContext(context.Background())
|
||||
}
|
||||
|
||||
func GetOSInfoWithContext(ctx context.Context) (Win32_OperatingSystem, error) {
|
||||
var dst []Win32_OperatingSystem
|
||||
q := wmi.CreateQuery(&dst, "")
|
||||
err := wmi.Query(q, &dst)
|
||||
err := common.WMIQueryWithContext(ctx, q, &dst)
|
||||
if err != nil {
|
||||
return Win32_OperatingSystem{}, err
|
||||
}
|
||||
|
@ -120,8 +129,12 @@ func GetOSInfo() (Win32_OperatingSystem, error) {
|
|||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return UptimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
||||
if osInfo == nil {
|
||||
_, err := GetOSInfo()
|
||||
_, err := GetOSInfoWithContext(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -139,6 +152,10 @@ func bootTime(up uint64) uint64 {
|
|||
var cachedBootTime uint64
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
return BootTimeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
||||
t := atomic.LoadUint64(&cachedBootTime)
|
||||
if t != 0 {
|
||||
return t, nil
|
||||
|
@ -153,8 +170,12 @@ func BootTime() (uint64, error) {
|
|||
}
|
||||
|
||||
func PlatformInformation() (platform string, family string, version string, err error) {
|
||||
return PlatformInformationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) {
|
||||
if osInfo == nil {
|
||||
_, err = GetOSInfo()
|
||||
_, err = GetOSInfoWithContext(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -180,20 +201,36 @@ func PlatformInformation() (platform string, family string, version string, err
|
|||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
return UsersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
||||
var ret []UserStat
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func SensorsTemperatures() ([]TemperatureStat, error) {
|
||||
return SensorsTemperaturesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
||||
return []TemperatureStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
return VirtualizationWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
||||
return "", "", common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func KernelVersion() (string, error) {
|
||||
return KernelVersionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
||||
_, _, version, err := PlatformInformation()
|
||||
return version, err
|
||||
}
|
||||
|
|
|
@ -316,6 +316,10 @@ func HostEtc(combineWith ...string) string {
|
|||
return GetEnv("HOST_ETC", "/etc", combineWith...)
|
||||
}
|
||||
|
||||
func HostVar(combineWith ...string) string {
|
||||
return GetEnv("HOST_VAR", "/var", combineWith...)
|
||||
}
|
||||
|
||||
// https://gist.github.com/kylelemons/1525278
|
||||
func Pipeline(cmds ...*exec.Cmd) ([]byte, []byte, error) {
|
||||
// Require at least one command
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadlines(t *testing.T) {
|
||||
ret, err := ReadLines("common_test.go")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !strings.Contains(ret[0], "package common") {
|
||||
t.Error("could not read correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadLinesOffsetN(t *testing.T) {
|
||||
ret, err := ReadLinesOffsetN("common_test.go", 2, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(ret[0])
|
||||
if !strings.Contains(ret[0], `import (`) {
|
||||
t.Error("could not read correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntToString(t *testing.T) {
|
||||
src := []int8{65, 66, 67}
|
||||
dst := IntToString(src)
|
||||
if dst != "ABC" {
|
||||
t.Error("could not convert")
|
||||
}
|
||||
}
|
||||
func TestByteToString(t *testing.T) {
|
||||
src := []byte{65, 66, 67}
|
||||
dst := ByteToString(src)
|
||||
if dst != "ABC" {
|
||||
t.Error("could not convert")
|
||||
}
|
||||
|
||||
src = []byte{0, 65, 66, 67}
|
||||
dst = ByteToString(src)
|
||||
if dst != "ABC" {
|
||||
t.Error("could not convert")
|
||||
}
|
||||
}
|
||||
|
||||
func TestmustParseInt32(t *testing.T) {
|
||||
ret := mustParseInt32("11111")
|
||||
if ret != int32(11111) {
|
||||
t.Error("could not parse")
|
||||
}
|
||||
}
|
||||
func TestmustParseUint64(t *testing.T) {
|
||||
ret := mustParseUint64("11111")
|
||||
if ret != uint64(11111) {
|
||||
t.Error("could not parse")
|
||||
}
|
||||
}
|
||||
func TestmustParseFloat64(t *testing.T) {
|
||||
ret := mustParseFloat64("11111.11")
|
||||
if ret != float64(11111.11) {
|
||||
t.Error("could not parse")
|
||||
}
|
||||
ret = mustParseFloat64("11111")
|
||||
if ret != float64(11111) {
|
||||
t.Error("could not parse")
|
||||
}
|
||||
}
|
||||
func TestStringsContains(t *testing.T) {
|
||||
target, err := ReadLines("common_test.go")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !StringsContains(target, "func TestStringsContains(t *testing.T) {") {
|
||||
t.Error("cloud not test correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathExists(t *testing.T) {
|
||||
if !PathExists("common_test.go") {
|
||||
t.Error("exists but return not exists")
|
||||
}
|
||||
if PathExists("should_not_exists.go") {
|
||||
t.Error("not exists but return exists")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostEtc(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("windows doesn't have etc")
|
||||
}
|
||||
p := HostEtc("mtab")
|
||||
if p != "/etc/mtab" {
|
||||
t.Errorf("invalid HostEtc, %s", p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSysctrlEnv(t *testing.T) {
|
||||
// Append case
|
||||
env := getSysctrlEnv([]string{"FOO=bar"})
|
||||
if !reflect.DeepEqual(env, []string{"FOO=bar", "LC_ALL=C"}) {
|
||||
t.Errorf("unexpected append result from getSysctrlEnv: %q", env)
|
||||
}
|
||||
|
||||
// Replace case
|
||||
env = getSysctrlEnv([]string{"FOO=bar", "LC_ALL=en_US.UTF-8"})
|
||||
if !reflect.DeepEqual(env, []string{"FOO=bar", "LC_ALL=C"}) {
|
||||
t.Errorf("unexpected replace result from getSysctrlEnv: %q", env)
|
||||
}
|
||||
|
||||
// Test against real env
|
||||
env = getSysctrlEnv(os.Environ())
|
||||
found := false
|
||||
for _, v := range env {
|
||||
if v == "LC_ALL=C" {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(v, "LC_ALL") {
|
||||
t.Fatalf("unexpected LC_ALL value: %q", v)
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("unexpected real result from getSysctrlEnv: %q", env)
|
||||
}
|
||||
}
|
|
@ -3,8 +3,10 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"unsafe"
|
||||
|
||||
"github.com/StackExchange/wmi"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
|
@ -48,6 +50,7 @@ var (
|
|||
Modkernel32 = windows.NewLazyDLL("kernel32.dll")
|
||||
ModNt = windows.NewLazyDLL("ntdll.dll")
|
||||
ModPdh = windows.NewLazyDLL("pdh.dll")
|
||||
ModPsapi = windows.NewLazyDLL("psapi.dll")
|
||||
|
||||
ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
|
||||
ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")
|
||||
|
@ -109,3 +112,24 @@ func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, err
|
|||
Counter: counter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
|
||||
func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
|
||||
if _, ok := ctx.Deadline(); !ok {
|
||||
ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
|
||||
defer cancel()
|
||||
ctx = ctxTimeout
|
||||
}
|
||||
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
errChan <- wmi.Query(query, dst, connectServerArgs...)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case err := <-errChan:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package mem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -28,6 +29,10 @@ func getHwMemsize() (uint64, error) {
|
|||
|
||||
// SwapMemory returns swapinfo.
|
||||
func SwapMemory() (*SwapMemoryStat, error) {
|
||||
return SwapMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
||||
var ret *SwapMemoryStat
|
||||
|
||||
swapUsage, err := common.DoSysctrl("vm.swapusage")
|
||||
|
|
|
@ -9,6 +9,7 @@ package mem
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
|
@ -17,6 +18,10 @@ import (
|
|||
|
||||
// VirtualMemory returns VirtualmemoryStat.
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
count := C.mach_msg_type_number_t(C.HOST_VM_INFO_COUNT)
|
||||
var vmstat C.vm_statistics_data_t
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
package mem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -68,6 +69,10 @@ func parseVMStat(out string, vms *VirtualMemoryStat) error {
|
|||
|
||||
// VirtualMemory returns VirtualmemoryStat.
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
ret := &VirtualMemoryStat{}
|
||||
|
||||
total, err := getHwMemsize()
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// +build darwin
|
||||
|
||||
package mem
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestVirtualMemoryDarwin(t *testing.T) {
|
||||
v, err := VirtualMemory()
|
||||
assert.Nil(t, err)
|
||||
|
||||
outBytes, err := invoke.Command("/usr/sbin/sysctl", "hw.memsize")
|
||||
assert.Nil(t, err)
|
||||
outString := string(outBytes)
|
||||
outString = strings.TrimSpace(outString)
|
||||
outParts := strings.Split(outString, " ")
|
||||
actualTotal, err := strconv.ParseInt(outParts[1], 10, 64)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, uint64(actualTotal), v.Total)
|
||||
|
||||
assert.True(t, v.Available > 0)
|
||||
assert.Equal(t, v.Available, v.Free+v.Inactive, "%v", v)
|
||||
|
||||
assert.True(t, v.Used > 0)
|
||||
assert.True(t, v.Used < v.Total)
|
||||
|
||||
assert.True(t, v.UsedPercent > 0)
|
||||
assert.True(t, v.UsedPercent < 100)
|
||||
|
||||
assert.True(t, v.Free > 0)
|
||||
assert.True(t, v.Free < v.Available)
|
||||
|
||||
assert.True(t, v.Active > 0)
|
||||
assert.True(t, v.Active < v.Total)
|
||||
|
||||
assert.True(t, v.Inactive > 0)
|
||||
assert.True(t, v.Inactive < v.Total)
|
||||
|
||||
assert.True(t, v.Wired > 0)
|
||||
assert.True(t, v.Wired < v.Total)
|
||||
}
|
|
@ -2,12 +2,24 @@
|
|||
|
||||
package mem
|
||||
|
||||
import "github.com/shirou/gopsutil/internal/common"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func SwapMemory() (*SwapMemoryStat, error) {
|
||||
return SwapMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -3,79 +3,62 @@
|
|||
package mem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
pageSize, err := common.DoSysctrl("vm.stats.vm.v_page_size")
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
pageSize, err := unix.SysctlUint32("vm.stats.vm.v_page_size")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, err := strconv.ParseUint(pageSize[0], 10, 64)
|
||||
pageCount, err := unix.SysctlUint32("vm.stats.vm.v_page_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
free, err := unix.SysctlUint32("vm.stats.vm.v_free_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
active, err := unix.SysctlUint32("vm.stats.vm.v_active_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inactive, err := unix.SysctlUint32("vm.stats.vm.v_inactive_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cached, err := unix.SysctlUint32("vm.stats.vm.v_cache_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffers, err := unix.SysctlUint32("vfs.bufspace")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wired, err := unix.SysctlUint32("vm.stats.vm.v_wire_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageCount, err := common.DoSysctrl("vm.stats.vm.v_page_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
free, err := common.DoSysctrl("vm.stats.vm.v_free_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
active, err := common.DoSysctrl("vm.stats.vm.v_active_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inactive, err := common.DoSysctrl("vm.stats.vm.v_inactive_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cache, err := common.DoSysctrl("vm.stats.vm.v_cache_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer, err := common.DoSysctrl("vfs.bufspace")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wired, err := common.DoSysctrl("vm.stats.vm.v_wire_count")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsed := make([]uint64, 0, 7)
|
||||
vv := []string{
|
||||
pageCount[0],
|
||||
free[0],
|
||||
active[0],
|
||||
inactive[0],
|
||||
cache[0],
|
||||
buffer[0],
|
||||
wired[0],
|
||||
}
|
||||
for _, target := range vv {
|
||||
t, err := strconv.ParseUint(target, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsed = append(parsed, t)
|
||||
}
|
||||
|
||||
p := uint64(pageSize)
|
||||
ret := &VirtualMemoryStat{
|
||||
Total: parsed[0] * p,
|
||||
Free: parsed[1] * p,
|
||||
Active: parsed[2] * p,
|
||||
Inactive: parsed[3] * p,
|
||||
Cached: parsed[4] * p,
|
||||
Buffers: parsed[5],
|
||||
Wired: parsed[6] * p,
|
||||
Total: uint64(pageCount) * p,
|
||||
Free: uint64(free) * p,
|
||||
Active: uint64(active) * p,
|
||||
Inactive: uint64(inactive) * p,
|
||||
Cached: uint64(cached) * p,
|
||||
Buffers: uint64(buffers),
|
||||
Wired: uint64(wired) * p,
|
||||
}
|
||||
|
||||
ret.Available = ret.Inactive + ret.Cached + ret.Free
|
||||
|
@ -88,6 +71,10 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
|
|||
// Return swapinfo
|
||||
// FreeBSD can have multiple swap devices. but use only first device
|
||||
func SwapMemory() (*SwapMemoryStat, error) {
|
||||
return SwapMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
||||
swapinfo, err := exec.LookPath("swapinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package mem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -11,6 +12,10 @@ import (
|
|||
)
|
||||
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
filename := common.HostProc("meminfo")
|
||||
lines, _ := common.ReadLines(filename)
|
||||
// flag if MemAvailable is in /proc/meminfo (kernel 3.14+)
|
||||
|
@ -72,6 +77,10 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
|
|||
}
|
||||
|
||||
func SwapMemory() (*SwapMemoryStat, error) {
|
||||
return SwapMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
||||
sysinfo := &unix.Sysinfo_t{}
|
||||
|
||||
if err := unix.Sysinfo(sysinfo); err != nil {
|
||||
|
|
|
@ -4,14 +4,20 @@ package mem
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"os/exec"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func GetPageSize() (uint64, error) {
|
||||
return GetPageSizeWithContext(context.Background())
|
||||
}
|
||||
|
||||
func GetPageSizeWithContext(ctx context.Context) (uint64, error) {
|
||||
mib := []int32{CTLVm, VmUvmexp}
|
||||
buf, length, err := common.CallSyscall(mib)
|
||||
if err != nil {
|
||||
|
@ -30,6 +36,10 @@ func GetPageSize() (uint64, error) {
|
|||
}
|
||||
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
mib := []int32{CTLVm, VmUvmexp}
|
||||
buf, length, err := common.CallSyscall(mib)
|
||||
if err != nil {
|
||||
|
@ -80,6 +90,10 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
|
|||
|
||||
// Return swapctl summary info
|
||||
func SwapMemory() (*SwapMemoryStat, error) {
|
||||
return SwapMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
||||
swapctl, err := exec.LookPath("swapctl")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package mem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
@ -14,6 +15,10 @@ import (
|
|||
// VirtualMemory for Solaris is a minimal implementation which only returns
|
||||
// what Nomad needs. It does take into account global vs zone, however.
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
result := &VirtualMemoryStat{}
|
||||
|
||||
zoneName, err := zoneName()
|
||||
|
@ -39,6 +44,10 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
|
|||
}
|
||||
|
||||
func SwapMemory() (*SwapMemoryStat, error) {
|
||||
return SwapMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package mem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestVirtual_memory(t *testing.T) {
|
||||
if runtime.GOOS == "solaris" {
|
||||
t.Skip("Only .Total is supported on Solaris")
|
||||
}
|
||||
|
||||
v, err := VirtualMemory()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
empty := &VirtualMemoryStat{}
|
||||
if v == empty {
|
||||
t.Errorf("error %v", v)
|
||||
}
|
||||
|
||||
assert.True(t, v.Total > 0)
|
||||
assert.True(t, v.Available > 0)
|
||||
assert.True(t, v.Used > 0)
|
||||
|
||||
assert.Equal(t, v.Total, v.Available+v.Used,
|
||||
"Total should be computable from available + used: %v", v)
|
||||
|
||||
assert.True(t, v.Free > 0)
|
||||
assert.True(t, v.Available > v.Free,
|
||||
"Free should be a subset of Available: %v", v)
|
||||
|
||||
assert.InDelta(t, v.UsedPercent,
|
||||
100*float64(v.Used)/float64(v.Total), 0.1,
|
||||
"UsedPercent should be how many percent of Total is Used: %v", v)
|
||||
}
|
||||
|
||||
func TestSwap_memory(t *testing.T) {
|
||||
v, err := SwapMemory()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
empty := &SwapMemoryStat{}
|
||||
if v == empty {
|
||||
t.Errorf("error %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMemoryStat_String(t *testing.T) {
|
||||
v := VirtualMemoryStat{
|
||||
Total: 10,
|
||||
Available: 20,
|
||||
Used: 30,
|
||||
UsedPercent: 30.1,
|
||||
Free: 40,
|
||||
}
|
||||
e := `{"total":10,"available":20,"used":30,"usedPercent":30.1,"free":40,"active":0,"inactive":0,"wired":0,"buffers":0,"cached":0,"writeback":0,"dirty":0,"writebacktmp":0,"shared":0,"slab":0,"pagetables":0,"swapcached":0}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("VirtualMemoryStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSwapMemoryStat_String(t *testing.T) {
|
||||
v := SwapMemoryStat{
|
||||
Total: 10,
|
||||
Used: 30,
|
||||
Free: 40,
|
||||
UsedPercent: 30.1,
|
||||
}
|
||||
e := `{"total":10,"used":30,"free":40,"usedPercent":30.1,"sin":0,"sout":0}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("SwapMemoryStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
package mem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
|
||||
var (
|
||||
procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
|
||||
procGetPerformanceInfo = common.ModPsapi.NewProc("GetPerformanceInfo")
|
||||
)
|
||||
|
||||
type memoryStatusEx struct {
|
||||
|
@ -26,6 +28,10 @@ type memoryStatusEx struct {
|
|||
}
|
||||
|
||||
func VirtualMemory() (*VirtualMemoryStat, error) {
|
||||
return VirtualMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
||||
var memInfo memoryStatusEx
|
||||
memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
|
||||
mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
|
||||
|
@ -43,8 +49,43 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
type performanceInformation struct {
|
||||
cb uint32
|
||||
commitTotal uint64
|
||||
commitLimit uint64
|
||||
commitPeak uint64
|
||||
physicalTotal uint64
|
||||
physicalAvailable uint64
|
||||
systemCache uint64
|
||||
kernelTotal uint64
|
||||
kernelPaged uint64
|
||||
kernelNonpaged uint64
|
||||
pageSize uint64
|
||||
handleCount uint32
|
||||
processCount uint32
|
||||
threadCount uint32
|
||||
}
|
||||
|
||||
func SwapMemory() (*SwapMemoryStat, error) {
|
||||
ret := &SwapMemoryStat{}
|
||||
return SwapMemoryWithContext(context.Background())
|
||||
}
|
||||
|
||||
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
||||
var perfInfo performanceInformation
|
||||
perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
|
||||
mem, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
|
||||
if mem == 0 {
|
||||
return nil, windows.GetLastError()
|
||||
}
|
||||
tot := perfInfo.commitLimit * perfInfo.pageSize
|
||||
used := perfInfo.commitTotal * perfInfo.pageSize
|
||||
free := tot - used
|
||||
ret := &SwapMemoryStat{
|
||||
Total: tot,
|
||||
Used: used,
|
||||
Free: free,
|
||||
UsedPercent: float64(used / tot),
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
@ -111,6 +112,10 @@ func (n InterfaceAddr) String() string {
|
|||
}
|
||||
|
||||
func Interfaces() ([]InterfaceStat, error) {
|
||||
return InterfacesWithContext(context.Background())
|
||||
}
|
||||
|
||||
func InterfacesWithContext(ctx context.Context) ([]InterfaceStat, error) {
|
||||
is, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
@ -164,6 +165,10 @@ func (min mapInterfaceNameUsage) notTruncated() []string {
|
|||
// lo0 16384 ::1/128 ::1 869107 - 169411755 869107 - 169411755 - -
|
||||
// lo0 16384 127 127.0.0.1 869107 - 169411755 869107 - 169411755 - -
|
||||
func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), pernic)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
|
||||
var (
|
||||
ret []IOCountersStat
|
||||
retIndex int
|
||||
|
@ -251,10 +256,18 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
|||
|
||||
// NetIOCountersByFile is an method which is added just a compatibility for linux.
|
||||
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCountersByFileWithContext(context.Background(), pernic, filename)
|
||||
}
|
||||
|
||||
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCounters(pernic)
|
||||
}
|
||||
|
||||
func FilterCounters() ([]FilterStat, error) {
|
||||
return FilterCountersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
|
||||
return nil, errors.New("NetFilterCounters not implemented for darwin")
|
||||
}
|
||||
|
||||
|
@ -263,5 +276,9 @@ func FilterCounters() ([]FilterStat, error) {
|
|||
// just the protocols in the list are returned.
|
||||
// Not Implemented for Darwin
|
||||
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
||||
return ProtoCountersWithContext(context.Background(), protocols)
|
||||
}
|
||||
|
||||
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
|
||||
return nil, errors.New("NetProtoCounters not implemented for darwin")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
assert "github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
netstatTruncated = `Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop
|
||||
lo0 16384 <Link#1> 31241 0 3769823 31241 0 3769823 0 0
|
||||
lo0 16384 ::1/128 ::1 31241 - 3769823 31241 - 3769823 - -
|
||||
lo0 16384 127 127.0.0.1 31241 - 3769823 31241 - 3769823 - -
|
||||
lo0 16384 fe80::1%lo0 fe80:1::1 31241 - 3769823 31241 - 3769823 - -
|
||||
gif0* 1280 <Link#2> 0 0 0 0 0 0 0 0
|
||||
stf0* 1280 <Link#3> 0 0 0 0 0 0 0 0
|
||||
utun8 1500 <Link#88> 286 0 27175 0 0 0 0 0
|
||||
utun8 1500 <Link#90> 286 0 29554 0 0 0 0 0
|
||||
utun8 1500 <Link#92> 286 0 29244 0 0 0 0 0
|
||||
utun8 1500 <Link#93> 286 0 28267 0 0 0 0 0
|
||||
utun8 1500 <Link#95> 286 0 28593 0 0 0 0 0`
|
||||
netstatNotTruncated = `Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop
|
||||
lo0 16384 <Link#1> 27190978 0 12824763793 27190978 0 12824763793 0 0
|
||||
lo0 16384 ::1/128 ::1 27190978 - 12824763793 27190978 - 12824763793 - -
|
||||
lo0 16384 127 127.0.0.1 27190978 - 12824763793 27190978 - 12824763793 - -
|
||||
lo0 16384 fe80::1%lo0 fe80:1::1 27190978 - 12824763793 27190978 - 12824763793 - -
|
||||
gif0* 1280 <Link#2> 0 0 0 0 0 0 0 0
|
||||
stf0* 1280 <Link#3> 0 0 0 0 0 0 0 0
|
||||
en0 1500 <Link#4> a8:66:7f:dd:ee:ff 5708989 0 7295722068 3494252 0 379533492 0 230
|
||||
en0 1500 fe80::aa66: fe80:4::aa66:7fff 5708989 - 7295722068 3494252 - 379533492 - -`
|
||||
)
|
||||
|
||||
func TestparseNetstatLineHeader(t *testing.T) {
|
||||
stat, linkIkd, err := parseNetstatLine(`Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop`)
|
||||
assert.Nil(t, linkIkd)
|
||||
assert.Nil(t, stat)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, errNetstatHeader, err)
|
||||
}
|
||||
|
||||
func assertLoopbackStat(t *testing.T, err error, stat *IOCountersStat) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 869107, stat.PacketsRecv)
|
||||
assert.Equal(t, 0, stat.Errin)
|
||||
assert.Equal(t, 169411755, stat.BytesRecv)
|
||||
assert.Equal(t, 869108, stat.PacketsSent)
|
||||
assert.Equal(t, 1, stat.Errout)
|
||||
assert.Equal(t, 169411756, stat.BytesSent)
|
||||
}
|
||||
|
||||
func TestparseNetstatLineLink(t *testing.T) {
|
||||
stat, linkID, err := parseNetstatLine(
|
||||
`lo0 16384 <Link#1> 869107 0 169411755 869108 1 169411756 0 0`,
|
||||
)
|
||||
assertLoopbackStat(t, err, stat)
|
||||
assert.NotNil(t, linkID)
|
||||
assert.Equal(t, uint(1), *linkID)
|
||||
}
|
||||
|
||||
func TestparseNetstatLineIPv6(t *testing.T) {
|
||||
stat, linkID, err := parseNetstatLine(
|
||||
`lo0 16384 ::1/128 ::1 869107 - 169411755 869108 1 169411756 - -`,
|
||||
)
|
||||
assertLoopbackStat(t, err, stat)
|
||||
assert.Nil(t, linkID)
|
||||
}
|
||||
|
||||
func TestparseNetstatLineIPv4(t *testing.T) {
|
||||
stat, linkID, err := parseNetstatLine(
|
||||
`lo0 16384 127 127.0.0.1 869107 - 169411755 869108 1 169411756 - -`,
|
||||
)
|
||||
assertLoopbackStat(t, err, stat)
|
||||
assert.Nil(t, linkID)
|
||||
}
|
||||
|
||||
func TestParseNetstatOutput(t *testing.T) {
|
||||
nsInterfaces, err := parseNetstatOutput(netstatNotTruncated)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, nsInterfaces, 8)
|
||||
for index := range nsInterfaces {
|
||||
assert.NotNil(t, nsInterfaces[index].stat, "Index %d", index)
|
||||
}
|
||||
|
||||
assert.NotNil(t, nsInterfaces[0].linkID)
|
||||
assert.Equal(t, uint(1), *nsInterfaces[0].linkID)
|
||||
|
||||
assert.Nil(t, nsInterfaces[1].linkID)
|
||||
assert.Nil(t, nsInterfaces[2].linkID)
|
||||
assert.Nil(t, nsInterfaces[3].linkID)
|
||||
|
||||
assert.NotNil(t, nsInterfaces[4].linkID)
|
||||
assert.Equal(t, uint(2), *nsInterfaces[4].linkID)
|
||||
|
||||
assert.NotNil(t, nsInterfaces[5].linkID)
|
||||
assert.Equal(t, uint(3), *nsInterfaces[5].linkID)
|
||||
|
||||
assert.NotNil(t, nsInterfaces[6].linkID)
|
||||
assert.Equal(t, uint(4), *nsInterfaces[6].linkID)
|
||||
|
||||
assert.Nil(t, nsInterfaces[7].linkID)
|
||||
|
||||
mapUsage := newMapInterfaceNameUsage(nsInterfaces)
|
||||
assert.False(t, mapUsage.isTruncated())
|
||||
assert.Len(t, mapUsage.notTruncated(), 4)
|
||||
}
|
||||
|
||||
func TestParseNetstatTruncated(t *testing.T) {
|
||||
nsInterfaces, err := parseNetstatOutput(netstatTruncated)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, nsInterfaces, 11)
|
||||
for index := range nsInterfaces {
|
||||
assert.NotNil(t, nsInterfaces[index].stat, "Index %d", index)
|
||||
}
|
||||
|
||||
const truncatedIface = "utun8"
|
||||
|
||||
assert.NotNil(t, nsInterfaces[6].linkID)
|
||||
assert.Equal(t, uint(88), *nsInterfaces[6].linkID)
|
||||
assert.Equal(t, truncatedIface, nsInterfaces[6].stat.Name)
|
||||
|
||||
assert.NotNil(t, nsInterfaces[7].linkID)
|
||||
assert.Equal(t, uint(90), *nsInterfaces[7].linkID)
|
||||
assert.Equal(t, truncatedIface, nsInterfaces[7].stat.Name)
|
||||
|
||||
assert.NotNil(t, nsInterfaces[8].linkID)
|
||||
assert.Equal(t, uint(92), *nsInterfaces[8].linkID)
|
||||
assert.Equal(t, truncatedIface, nsInterfaces[8].stat.Name)
|
||||
|
||||
assert.NotNil(t, nsInterfaces[9].linkID)
|
||||
assert.Equal(t, uint(93), *nsInterfaces[9].linkID)
|
||||
assert.Equal(t, truncatedIface, nsInterfaces[9].stat.Name)
|
||||
|
||||
assert.NotNil(t, nsInterfaces[10].linkID)
|
||||
assert.Equal(t, uint(95), *nsInterfaces[10].linkID)
|
||||
assert.Equal(t, truncatedIface, nsInterfaces[10].stat.Name)
|
||||
|
||||
mapUsage := newMapInterfaceNameUsage(nsInterfaces)
|
||||
assert.True(t, mapUsage.isTruncated())
|
||||
assert.Equal(t, 3, len(mapUsage.notTruncated()), "en0, gif0 and stf0")
|
||||
}
|
|
@ -2,24 +2,48 @@
|
|||
|
||||
package net
|
||||
|
||||
import "github.com/shirou/gopsutil/internal/common"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), pernic)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
|
||||
return []IOCountersStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func FilterCounters() ([]FilterStat, error) {
|
||||
return FilterCountersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
|
||||
return []FilterStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
||||
return ProtoCountersWithContext(context.Background(), protocols)
|
||||
}
|
||||
|
||||
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
|
||||
return []ProtoCountersStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Connections(kind string) ([]ConnectionStat, error) {
|
||||
return ConnectionsWithContext(context.Background(), kind)
|
||||
}
|
||||
|
||||
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
|
||||
return []ConnectionStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
|
||||
return ConnectionsMaxWithContext(context.Background(), kind, max)
|
||||
}
|
||||
|
||||
func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
|
||||
return []ConnectionStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
@ -12,6 +13,10 @@ import (
|
|||
)
|
||||
|
||||
func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), pernic)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
|
||||
netstat, err := exec.LookPath("/usr/bin/netstat")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -92,10 +97,18 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
|||
|
||||
// NetIOCountersByFile is an method which is added just a compatibility for linux.
|
||||
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCountersByFileWithContext(context.Background(), pernic, filename)
|
||||
}
|
||||
|
||||
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCounters(pernic)
|
||||
}
|
||||
|
||||
func FilterCounters() ([]FilterStat, error) {
|
||||
return FilterCountersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
|
||||
return nil, errors.New("NetFilterCounters not implemented for freebsd")
|
||||
}
|
||||
|
||||
|
@ -104,5 +117,9 @@ func FilterCounters() ([]FilterStat, error) {
|
|||
// just the protocols in the list are returned.
|
||||
// Not Implemented for FreeBSD
|
||||
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
||||
return ProtoCountersWithContext(context.Background(), protocols)
|
||||
}
|
||||
|
||||
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
|
||||
return nil, errors.New("NetProtoCounters not implemented for freebsd")
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package net
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -23,11 +24,19 @@ import (
|
|||
// every network interface installed on the system is returned
|
||||
// separately.
|
||||
func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), pernic)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
|
||||
filename := common.HostProc("net/dev")
|
||||
return IOCountersByFile(pernic, filename)
|
||||
}
|
||||
|
||||
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCountersByFileWithContext(context.Background(), pernic, filename)
|
||||
}
|
||||
|
||||
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
lines, err := common.ReadLines(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -132,6 +141,10 @@ var netProtocols = []string{
|
|||
// Available protocols:
|
||||
// ip,icmp,icmpmsg,tcp,udp,udplite
|
||||
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
||||
return ProtoCountersWithContext(context.Background(), protocols)
|
||||
}
|
||||
|
||||
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
|
||||
if len(protocols) == 0 {
|
||||
protocols = netProtocols
|
||||
}
|
||||
|
@ -191,6 +204,10 @@ func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
|||
// the currently in use conntrack count and the max.
|
||||
// If the file does not exist or is invalid it will return nil.
|
||||
func FilterCounters() ([]FilterStat, error) {
|
||||
return FilterCountersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
|
||||
countfile := common.HostProc("sys/net/netfilter/nf_conntrack_count")
|
||||
maxfile := common.HostProc("sys/net/netfilter/nf_conntrack_max")
|
||||
|
||||
|
@ -294,17 +311,29 @@ type connTmp struct {
|
|||
|
||||
// Return a list of network connections opened.
|
||||
func Connections(kind string) ([]ConnectionStat, error) {
|
||||
return ConnectionsWithContext(context.Background(), kind)
|
||||
}
|
||||
|
||||
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
|
||||
return ConnectionsPid(kind, 0)
|
||||
}
|
||||
|
||||
// Return a list of network connections opened returning at most `max`
|
||||
// connections for each running process.
|
||||
func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
|
||||
return ConnectionsMaxWithContext(context.Background(), kind, max)
|
||||
}
|
||||
|
||||
func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
|
||||
return ConnectionsPidMax(kind, 0, max)
|
||||
}
|
||||
|
||||
// Return a list of network connections opened by a process.
|
||||
func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
|
||||
return ConnectionsPidWithContext(context.Background(), kind, pid)
|
||||
}
|
||||
|
||||
func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
|
||||
tmap, ok := netConnectionKindMap[kind]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid kind, %s", kind)
|
||||
|
@ -322,13 +351,17 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
|
|||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cound not get pid(s), %d", pid)
|
||||
return nil, fmt.Errorf("cound not get pid(s), %d: %s", pid, err)
|
||||
}
|
||||
return statsFromInodes(root, pid, tmap, inodes)
|
||||
}
|
||||
|
||||
// Return up to `max` network connections opened by a process.
|
||||
func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) {
|
||||
return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max)
|
||||
}
|
||||
|
||||
func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
|
||||
tmap, ok := netConnectionKindMap[kind]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid kind, %s", kind)
|
||||
|
@ -459,6 +492,10 @@ func getProcInodes(root string, pid int32, max int) (map[string][]inodeMap, erro
|
|||
// FIXME: Import process occures import cycle.
|
||||
// move to common made other platform breaking. Need consider.
|
||||
func Pids() ([]int32, error) {
|
||||
return PidsWithContext(context.Background())
|
||||
}
|
||||
|
||||
func PidsWithContext(ctx context.Context) ([]int32, error) {
|
||||
var ret []int32
|
||||
|
||||
d, err := os.Open(common.HostProc())
|
||||
|
@ -541,6 +578,10 @@ func getProcInodesAll(root string, max int) (map[string][]inodeMap, error) {
|
|||
for _, pid := range pids {
|
||||
t, err := getProcInodes(root, pid, max)
|
||||
if err != nil {
|
||||
// skip if permission error or no longer exists
|
||||
if os.IsPermission(err) || os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
if len(t) == 0 {
|
||||
|
@ -588,6 +629,10 @@ func decodeAddress(family uint32, src string) (Addr, error) {
|
|||
|
||||
// Reverse reverses array of bytes.
|
||||
func Reverse(s []byte) []byte {
|
||||
return ReverseWithContext(context.Background(), s)
|
||||
}
|
||||
|
||||
func ReverseWithContext(ctx context.Context, s []byte) []byte {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIOCountersByFileParsing(t *testing.T) {
|
||||
// Prpare a temporary file, which will be read during the test
|
||||
tmpfile, err := ioutil.TempFile("", "proc_dev_net")
|
||||
defer os.Remove(tmpfile.Name()) // clean up
|
||||
|
||||
assert.Nil(t, err, "Temporary file creation failed: ", err)
|
||||
|
||||
cases := [4][2]string{
|
||||
[2]string{"eth0: ", "eth1: "},
|
||||
[2]string{"eth0:0: ", "eth1:0: "},
|
||||
[2]string{"eth0:", "eth1:"},
|
||||
[2]string{"eth0:0:", "eth1:0:"},
|
||||
}
|
||||
for _, testCase := range cases {
|
||||
err = tmpfile.Truncate(0)
|
||||
assert.Nil(t, err, "Temporary file truncating problem: ", err)
|
||||
|
||||
// Parse interface name for assertion
|
||||
interface0 := strings.TrimSpace(testCase[0])
|
||||
interface0 = interface0[:len(interface0)-1]
|
||||
|
||||
interface1 := strings.TrimSpace(testCase[1])
|
||||
interface1 = interface1[:len(interface1)-1]
|
||||
|
||||
// Replace the interfaces from the test case
|
||||
proc := []byte(fmt.Sprintf("Inter-| Receive | Transmit\n face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n %s1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\n %s100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600\n", testCase[0], testCase[1]))
|
||||
|
||||
// Write /proc/net/dev sample output
|
||||
_, err = tmpfile.Write(proc)
|
||||
assert.Nil(t, err, "Temporary file writing failed: ", err)
|
||||
|
||||
counters, err := IOCountersByFile(true, tmpfile.Name())
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, counters)
|
||||
assert.Equal(t, 2, len(counters))
|
||||
assert.Equal(t, interface0, counters[0].Name)
|
||||
assert.Equal(t, 1, int(counters[0].BytesRecv))
|
||||
assert.Equal(t, 2, int(counters[0].PacketsRecv))
|
||||
assert.Equal(t, 3, int(counters[0].Errin))
|
||||
assert.Equal(t, 4, int(counters[0].Dropin))
|
||||
assert.Equal(t, 5, int(counters[0].Fifoin))
|
||||
assert.Equal(t, 9, int(counters[0].BytesSent))
|
||||
assert.Equal(t, 10, int(counters[0].PacketsSent))
|
||||
assert.Equal(t, 11, int(counters[0].Errout))
|
||||
assert.Equal(t, 12, int(counters[0].Dropout))
|
||||
assert.Equal(t, 13, int(counters[0].Fifoout))
|
||||
assert.Equal(t, interface1, counters[1].Name)
|
||||
assert.Equal(t, 100, int(counters[1].BytesRecv))
|
||||
assert.Equal(t, 200, int(counters[1].PacketsRecv))
|
||||
assert.Equal(t, 300, int(counters[1].Errin))
|
||||
assert.Equal(t, 400, int(counters[1].Dropin))
|
||||
assert.Equal(t, 500, int(counters[1].Fifoin))
|
||||
assert.Equal(t, 900, int(counters[1].BytesSent))
|
||||
assert.Equal(t, 1000, int(counters[1].PacketsSent))
|
||||
assert.Equal(t, 1100, int(counters[1].Errout))
|
||||
assert.Equal(t, 1200, int(counters[1].Dropout))
|
||||
assert.Equal(t, 1300, int(counters[1].Fifoout))
|
||||
}
|
||||
|
||||
err = tmpfile.Close()
|
||||
assert.Nil(t, err, "Temporary file closing failed: ", err)
|
||||
}
|
||||
|
||||
func TestGetProcInodesAll(t *testing.T) {
|
||||
if os.Getenv("CIRCLECI") == "true" {
|
||||
t.Skip("Skip CI")
|
||||
}
|
||||
|
||||
root := common.HostProc("")
|
||||
v, err := getProcInodesAll(root, 0)
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, v)
|
||||
}
|
||||
|
||||
func TestConnectionsMax(t *testing.T) {
|
||||
if os.Getenv("CIRCLECI") == "true" {
|
||||
t.Skip("Skip CI")
|
||||
}
|
||||
|
||||
max := 10
|
||||
v, err := ConnectionsMax("tcp", max)
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, v)
|
||||
|
||||
cxByPid := map[int32]int{}
|
||||
for _, cx := range v {
|
||||
if cx.Pid > 0 {
|
||||
cxByPid[cx.Pid]++
|
||||
}
|
||||
}
|
||||
for _, c := range cxByPid {
|
||||
assert.True(t, c <= max)
|
||||
}
|
||||
}
|
||||
|
||||
type AddrTest struct {
|
||||
IP string
|
||||
Port int
|
||||
Error bool
|
||||
}
|
||||
|
||||
func TestDecodeAddress(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
addr := map[string]AddrTest{
|
||||
"0500000A:0016": {
|
||||
IP: "10.0.0.5",
|
||||
Port: 22,
|
||||
},
|
||||
"0100007F:D1C2": {
|
||||
IP: "127.0.0.1",
|
||||
Port: 53698,
|
||||
},
|
||||
"11111:0035": {
|
||||
Error: true,
|
||||
},
|
||||
"0100007F:BLAH": {
|
||||
Error: true,
|
||||
},
|
||||
"0085002452100113070057A13F025401:0035": {
|
||||
IP: "2400:8500:1301:1052:a157:7:154:23f",
|
||||
Port: 53,
|
||||
},
|
||||
"00855210011307F025401:0035": {
|
||||
Error: true,
|
||||
},
|
||||
}
|
||||
|
||||
for src, dst := range addr {
|
||||
family := syscall.AF_INET
|
||||
if len(src) > 13 {
|
||||
family = syscall.AF_INET6
|
||||
}
|
||||
addr, err := decodeAddress(uint32(family), src)
|
||||
if dst.Error {
|
||||
assert.NotNil(err, src)
|
||||
} else {
|
||||
assert.Nil(err, src)
|
||||
assert.Equal(dst.IP, addr.IP, src)
|
||||
assert.Equal(dst.Port, int(addr.Port), src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
src := []byte{0x01, 0x02, 0x03}
|
||||
assert.Equal(t, []byte{0x03, 0x02, 0x01}, Reverse(src))
|
||||
}
|
|
@ -3,14 +3,20 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
|
||||
|
||||
func ParseNetstat(output string, mode string,
|
||||
iocs map[string]IOCountersStat) error {
|
||||
lines := strings.Split(output, "\n")
|
||||
|
@ -92,7 +98,11 @@ func ParseNetstat(output string, mode string,
|
|||
}
|
||||
|
||||
func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
||||
netstat, err := exec.LookPath("/usr/bin/netstat")
|
||||
return IOCountersWithContext(context.Background(), pernic)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
|
||||
netstat, err := exec.LookPath("netstat")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -131,10 +141,18 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
|||
|
||||
// NetIOCountersByFile is an method which is added just a compatibility for linux.
|
||||
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCountersByFileWithContext(context.Background(), pernic, filename)
|
||||
}
|
||||
|
||||
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCounters(pernic)
|
||||
}
|
||||
|
||||
func FilterCounters() ([]FilterStat, error) {
|
||||
return FilterCountersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
|
||||
return nil, errors.New("NetFilterCounters not implemented for openbsd")
|
||||
}
|
||||
|
||||
|
@ -143,11 +161,152 @@ func FilterCounters() ([]FilterStat, error) {
|
|||
// just the protocols in the list are returned.
|
||||
// Not Implemented for OpenBSD
|
||||
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
||||
return ProtoCountersWithContext(context.Background(), protocols)
|
||||
}
|
||||
|
||||
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
|
||||
return nil, errors.New("NetProtoCounters not implemented for openbsd")
|
||||
}
|
||||
|
||||
// Return a list of network connections opened.
|
||||
// Not Implemented for OpenBSD
|
||||
func Connections(kind string) ([]ConnectionStat, error) {
|
||||
return nil, errors.New("Connections not implemented for openbsd")
|
||||
func parseNetstatLine(line string) (ConnectionStat, error) {
|
||||
f := strings.Fields(line)
|
||||
if len(f) < 5 {
|
||||
return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
|
||||
}
|
||||
|
||||
var netType, netFamily uint32
|
||||
switch f[0] {
|
||||
case "tcp":
|
||||
netType = syscall.SOCK_STREAM
|
||||
netFamily = syscall.AF_INET
|
||||
case "udp":
|
||||
netType = syscall.SOCK_DGRAM
|
||||
netFamily = syscall.AF_INET
|
||||
case "tcp6":
|
||||
netType = syscall.SOCK_STREAM
|
||||
netFamily = syscall.AF_INET6
|
||||
case "udp6":
|
||||
netType = syscall.SOCK_DGRAM
|
||||
netFamily = syscall.AF_INET6
|
||||
default:
|
||||
return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
|
||||
}
|
||||
|
||||
laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
|
||||
if err != nil {
|
||||
return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
|
||||
}
|
||||
|
||||
n := ConnectionStat{
|
||||
Fd: uint32(0), // not supported
|
||||
Family: uint32(netFamily),
|
||||
Type: uint32(netType),
|
||||
Laddr: laddr,
|
||||
Raddr: raddr,
|
||||
Pid: int32(0), // not supported
|
||||
}
|
||||
if len(f) == 6 {
|
||||
n.Status = f[5]
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) {
|
||||
parse := func(l string) (Addr, error) {
|
||||
matches := portMatch.FindStringSubmatch(l)
|
||||
if matches == nil {
|
||||
return Addr{}, fmt.Errorf("wrong addr, %s", l)
|
||||
}
|
||||
host := matches[1]
|
||||
port := matches[2]
|
||||
if host == "*" {
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
host = "0.0.0.0"
|
||||
case syscall.AF_INET6:
|
||||
host = "::"
|
||||
default:
|
||||
return Addr{}, fmt.Errorf("unknown family, %d", family)
|
||||
}
|
||||
}
|
||||
lport, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return Addr{}, err
|
||||
}
|
||||
return Addr{IP: host, Port: uint32(lport)}, nil
|
||||
}
|
||||
|
||||
laddr, err = parse(local)
|
||||
if remote != "*.*" { // remote addr exists
|
||||
raddr, err = parse(remote)
|
||||
if err != nil {
|
||||
return laddr, raddr, err
|
||||
}
|
||||
}
|
||||
|
||||
return laddr, raddr, err
|
||||
}
|
||||
|
||||
// Return a list of network connections opened.
|
||||
func Connections(kind string) ([]ConnectionStat, error) {
|
||||
return ConnectionsWithContext(context.Background(), kind)
|
||||
}
|
||||
|
||||
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
|
||||
var ret []ConnectionStat
|
||||
|
||||
args := []string{"-na"}
|
||||
switch strings.ToLower(kind) {
|
||||
default:
|
||||
fallthrough
|
||||
case "":
|
||||
fallthrough
|
||||
case "all":
|
||||
fallthrough
|
||||
case "inet":
|
||||
// nothing to add
|
||||
case "inet4":
|
||||
args = append(args, "-finet")
|
||||
case "inet6":
|
||||
args = append(args, "-finet6")
|
||||
case "tcp":
|
||||
args = append(args, "-ptcp")
|
||||
case "tcp4":
|
||||
args = append(args, "-ptcp", "-finet")
|
||||
case "tcp6":
|
||||
args = append(args, "-ptcp", "-finet6")
|
||||
case "udp":
|
||||
args = append(args, "-pudp")
|
||||
case "udp4":
|
||||
args = append(args, "-pudp", "-finet")
|
||||
case "udp6":
|
||||
args = append(args, "-pudp", "-finet6")
|
||||
case "unix":
|
||||
return ret, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
netstat, err := exec.LookPath("netstat")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := invoke.Command(netstat, args...)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
for _, line := range lines {
|
||||
if !(strings.HasPrefix(line, "tcp") || strings.HasPrefix(line, "udp")) {
|
||||
continue
|
||||
}
|
||||
n, err := parseNetstatLine(line)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ret = append(ret, n)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
func TestAddrString(t *testing.T) {
|
||||
v := Addr{IP: "192.168.0.1", Port: 8000}
|
||||
|
||||
s := fmt.Sprintf("%v", v)
|
||||
if s != "{\"ip\":\"192.168.0.1\",\"port\":8000}" {
|
||||
t.Errorf("Addr string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetIOCountersStatString(t *testing.T) {
|
||||
v := IOCountersStat{
|
||||
Name: "test",
|
||||
BytesSent: 100,
|
||||
}
|
||||
e := `{"name":"test","bytesSent":100,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("NetIOCountersStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetProtoCountersStatString(t *testing.T) {
|
||||
v := ProtoCountersStat{
|
||||
Protocol: "tcp",
|
||||
Stats: map[string]int64{
|
||||
"MaxConn": -1,
|
||||
"ActiveOpens": 4000,
|
||||
"PassiveOpens": 3000,
|
||||
},
|
||||
}
|
||||
e := `{"protocol":"tcp","stats":{"ActiveOpens":4000,"MaxConn":-1,"PassiveOpens":3000}}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("NetProtoCountersStat string is invalid: %v", v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNetConnectionStatString(t *testing.T) {
|
||||
v := ConnectionStat{
|
||||
Fd: 10,
|
||||
Family: 10,
|
||||
Type: 10,
|
||||
Uids: []int32{10, 10},
|
||||
}
|
||||
e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","uids":[10,10],"pid":0}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("NetConnectionStat string is invalid: %v", v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNetIOCountersAll(t *testing.T) {
|
||||
v, err := IOCounters(false)
|
||||
per, err := IOCounters(true)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get NetIOCounters: %v", err)
|
||||
}
|
||||
if len(v) != 1 {
|
||||
t.Errorf("Could not get NetIOCounters: %v", v)
|
||||
}
|
||||
if v[0].Name != "all" {
|
||||
t.Errorf("Invalid NetIOCounters: %v", v)
|
||||
}
|
||||
var pr uint64
|
||||
for _, p := range per {
|
||||
pr += p.PacketsRecv
|
||||
}
|
||||
if v[0].PacketsRecv != pr {
|
||||
t.Errorf("invalid sum value: %v, %v", v[0].PacketsRecv, pr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetIOCountersPerNic(t *testing.T) {
|
||||
v, err := IOCounters(true)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get NetIOCounters: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Errorf("Could not get NetIOCounters: %v", v)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.Name == "" {
|
||||
t.Errorf("Invalid NetIOCounters: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNetIOCountersAll(t *testing.T) {
|
||||
n := []IOCountersStat{
|
||||
{
|
||||
Name: "a",
|
||||
BytesRecv: 10,
|
||||
PacketsRecv: 10,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
BytesRecv: 10,
|
||||
PacketsRecv: 10,
|
||||
Errin: 10,
|
||||
},
|
||||
}
|
||||
ret, err := getIOCountersAll(n)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(ret) != 1 {
|
||||
t.Errorf("invalid return count")
|
||||
}
|
||||
if ret[0].Name != "all" {
|
||||
t.Errorf("invalid return name")
|
||||
}
|
||||
if ret[0].BytesRecv != 20 {
|
||||
t.Errorf("invalid count bytesrecv")
|
||||
}
|
||||
if ret[0].Errin != 10 {
|
||||
t.Errorf("invalid count errin")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetInterfaces(t *testing.T) {
|
||||
v, err := Interfaces()
|
||||
if err != nil {
|
||||
t.Errorf("Could not get NetInterfaceStat: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Errorf("Could not get NetInterfaceStat: %v", err)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.Name == "" {
|
||||
t.Errorf("Invalid NetInterface: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetProtoCountersStatsAll(t *testing.T) {
|
||||
v, err := ProtoCounters(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.Protocol == "" {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
if len(vv.Stats) == 0 {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetProtoCountersStats(t *testing.T) {
|
||||
v, err := ProtoCounters([]string{"tcp", "ip"})
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
if len(v) != 2 {
|
||||
t.Fatalf("Go incorrect number of NetProtoCounters: %v", err)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.Protocol != "tcp" && vv.Protocol != "ip" {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
if len(vv.Stats) == 0 {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetConnections(t *testing.T) {
|
||||
if ci := os.Getenv("CI"); ci != "" { // skip if test on drone.io
|
||||
return
|
||||
}
|
||||
|
||||
v, err := Connections("inet")
|
||||
if err != nil {
|
||||
t.Errorf("could not get NetConnections: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Errorf("could not get NetConnections: %v", v)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.Family == 0 {
|
||||
t.Errorf("invalid NetConnections: %v", vv)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNetFilterCounters(t *testing.T) {
|
||||
if ci := os.Getenv("CI"); ci != "" { // skip if test on drone.io
|
||||
return
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
// some test environment has not the path.
|
||||
if !common.PathExists("/proc/sys/net/netfilter/nf_conntrackCount") {
|
||||
t.SkipNow()
|
||||
}
|
||||
}
|
||||
|
||||
v, err := FilterCounters()
|
||||
if err != nil {
|
||||
t.Errorf("could not get NetConnections: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Errorf("could not get NetConnections: %v", v)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.ConnTrackMax == 0 {
|
||||
t.Errorf("nf_conntrackMax needs to be greater than zero: %v", vv)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
|
@ -10,17 +11,29 @@ import (
|
|||
|
||||
// Return a list of network connections opened.
|
||||
func Connections(kind string) ([]ConnectionStat, error) {
|
||||
return ConnectionsWithContext(context.Background(), kind)
|
||||
}
|
||||
|
||||
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
|
||||
return ConnectionsPid(kind, 0)
|
||||
}
|
||||
|
||||
// Return a list of network connections opened returning at most `max`
|
||||
// connections for each running process.
|
||||
func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
|
||||
return ConnectionsMaxWithContext(context.Background(), kind, max)
|
||||
}
|
||||
|
||||
func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
|
||||
return []ConnectionStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
// Return a list of network connections opened by a process.
|
||||
func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
|
||||
return ConnectionsPidWithContext(context.Background(), kind, pid)
|
||||
}
|
||||
|
||||
func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
|
||||
var ret []ConnectionStat
|
||||
|
||||
args := []string{"-i"}
|
||||
|
@ -75,5 +88,9 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
|
|||
|
||||
// Return up to `max` network connections opened by a process.
|
||||
func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) {
|
||||
return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max)
|
||||
}
|
||||
|
||||
func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
|
||||
return []ConnectionStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
|
@ -30,6 +31,10 @@ const (
|
|||
)
|
||||
|
||||
func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
||||
return IOCountersWithContext(context.Background(), pernic)
|
||||
}
|
||||
|
||||
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
|
||||
ifs, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -66,11 +71,19 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
|||
|
||||
// NetIOCountersByFile is an method which is added just a compatibility for linux.
|
||||
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCountersByFileWithContext(context.Background(), pernic, filename)
|
||||
}
|
||||
|
||||
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
|
||||
return IOCounters(pernic)
|
||||
}
|
||||
|
||||
// Return a list of network connections opened by a process
|
||||
func Connections(kind string) ([]ConnectionStat, error) {
|
||||
return ConnectionsWithContext(context.Background(), kind)
|
||||
}
|
||||
|
||||
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
|
||||
var ret []ConnectionStat
|
||||
|
||||
return ret, common.ErrNotImplementedError
|
||||
|
@ -79,10 +92,18 @@ func Connections(kind string) ([]ConnectionStat, error) {
|
|||
// Return a list of network connections opened returning at most `max`
|
||||
// connections for each running process.
|
||||
func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
|
||||
return ConnectionsMaxWithContext(context.Background(), kind, max)
|
||||
}
|
||||
|
||||
func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
|
||||
return []ConnectionStat{}, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func FilterCounters() ([]FilterStat, error) {
|
||||
return FilterCountersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
|
||||
return nil, errors.New("NetFilterCounters not implemented for windows")
|
||||
}
|
||||
|
||||
|
@ -91,5 +112,9 @@ func FilterCounters() ([]FilterStat, error) {
|
|||
// just the protocols in the list are returned.
|
||||
// Not Implemented for Windows
|
||||
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
||||
return ProtoCountersWithContext(context.Background(), protocols)
|
||||
}
|
||||
|
||||
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
|
||||
return nil, errors.New("NetProtoCounters not implemented for windows")
|
||||
}
|
||||
|
|
10
vendor/github.com/shirou/gopsutil/process/expected/darwin/%2Fbin%2Fps-x-opid_fail
generated
vendored
10
vendor/github.com/shirou/gopsutil/process/expected/darwin/%2Fbin%2Fps-x-opid_fail
generated
vendored
|
@ -1,10 +0,0 @@
|
|||
PID
|
||||
245
|
||||
247
|
||||
248
|
||||
249
|
||||
254
|
||||
262
|
||||
264
|
||||
265
|
||||
267
|
|
@ -0,0 +1,20 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package process
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func Test_SendSignal(t *testing.T) {
|
||||
checkPid := os.Getpid()
|
||||
|
||||
p, _ := NewProcess(int32(checkPid))
|
||||
err := p.SendSignal(unix.SIGCONT)
|
||||
if err != nil {
|
||||
t.Errorf("send signal %v", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,446 @@
|
|||
package process
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
func testGetProcess() Process {
|
||||
checkPid := os.Getpid() // process.test
|
||||
ret, _ := NewProcess(int32(checkPid))
|
||||
return *ret
|
||||
}
|
||||
|
||||
func Test_Pids(t *testing.T) {
|
||||
ret, err := Pids()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if len(ret) == 0 {
|
||||
t.Errorf("could not get pids %v", ret)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Pids_Fail(t *testing.T) {
|
||||
if runtime.GOOS != "darwin" {
|
||||
t.Skip("darwin only")
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
invoke = common.FakeInvoke{Suffix: "fail"}
|
||||
ret, err := Pids()
|
||||
invoke = common.Invoke{}
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if len(ret) != 9 {
|
||||
t.Errorf("wrong getted pid nums: %v/%d", ret, len(ret))
|
||||
}
|
||||
}
|
||||
func Test_Pid_exists(t *testing.T) {
|
||||
checkPid := os.Getpid()
|
||||
|
||||
ret, err := PidExists(int32(checkPid))
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
|
||||
if ret == false {
|
||||
t.Errorf("could not get process exists: %v", ret)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_NewProcess(t *testing.T) {
|
||||
checkPid := os.Getpid()
|
||||
|
||||
ret, err := NewProcess(int32(checkPid))
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
empty := &Process{}
|
||||
if runtime.GOOS != "windows" { // Windows pid is 0
|
||||
if empty == ret {
|
||||
t.Errorf("error %v", ret)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_Process_memory_maps(t *testing.T) {
|
||||
checkPid := os.Getpid()
|
||||
|
||||
ret, err := NewProcess(int32(checkPid))
|
||||
|
||||
mmaps, err := ret.MemoryMaps(false)
|
||||
if err != nil {
|
||||
t.Errorf("memory map get error %v", err)
|
||||
}
|
||||
empty := MemoryMapsStat{}
|
||||
for _, m := range *mmaps {
|
||||
if m == empty {
|
||||
t.Errorf("memory map get error %v", m)
|
||||
}
|
||||
}
|
||||
}
|
||||
func Test_Process_MemoryInfo(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
v, err := p.MemoryInfo()
|
||||
if err != nil {
|
||||
t.Errorf("geting memory info error %v", err)
|
||||
}
|
||||
empty := MemoryInfoStat{}
|
||||
if v == nil || *v == empty {
|
||||
t.Errorf("could not get memory info %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_CmdLine(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
v, err := p.Cmdline()
|
||||
if err != nil {
|
||||
t.Errorf("geting cmdline error %v", err)
|
||||
}
|
||||
if !strings.Contains(v, "process.test") {
|
||||
t.Errorf("invalid cmd line %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_CmdLineSlice(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
v, err := p.CmdlineSlice()
|
||||
if err != nil {
|
||||
t.Fatalf("geting cmdline slice error %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(v, os.Args) {
|
||||
t.Errorf("returned cmdline slice not as expected:\nexp: %v\ngot: %v", os.Args, v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_Ppid(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
v, err := p.Ppid()
|
||||
if err != nil {
|
||||
t.Errorf("geting ppid error %v", err)
|
||||
}
|
||||
if v == 0 {
|
||||
t.Errorf("return value is 0 %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_Status(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
v, err := p.Status()
|
||||
if err != nil {
|
||||
t.Errorf("geting status error %v", err)
|
||||
}
|
||||
if v != "R" && v != "S" {
|
||||
t.Errorf("could not get state %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_Terminal(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
_, err := p.Terminal()
|
||||
if err != nil {
|
||||
t.Errorf("geting terminal error %v", err)
|
||||
}
|
||||
|
||||
/*
|
||||
if v == "" {
|
||||
t.Errorf("could not get terminal %v", v)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
func Test_Process_IOCounters(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
v, err := p.IOCounters()
|
||||
if err != nil {
|
||||
t.Errorf("geting iocounter error %v", err)
|
||||
return
|
||||
}
|
||||
empty := &IOCountersStat{}
|
||||
if v == empty {
|
||||
t.Errorf("error %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_NumCtx(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
_, err := p.NumCtxSwitches()
|
||||
if err != nil {
|
||||
t.Errorf("geting numctx error %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_Nice(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
n, err := p.Nice()
|
||||
if err != nil {
|
||||
t.Errorf("geting nice error %v", err)
|
||||
}
|
||||
if n != 0 && n != 20 && n != 8 {
|
||||
t.Errorf("invalid nice: %d", n)
|
||||
}
|
||||
}
|
||||
func Test_Process_NumThread(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
n, err := p.NumThreads()
|
||||
if err != nil {
|
||||
t.Errorf("geting NumThread error %v", err)
|
||||
}
|
||||
if n < 0 {
|
||||
t.Errorf("invalid NumThread: %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_Threads(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
n, err := p.NumThreads()
|
||||
if err != nil {
|
||||
t.Errorf("geting NumThread error %v", err)
|
||||
}
|
||||
if n < 0 {
|
||||
t.Errorf("invalid NumThread: %d", n)
|
||||
}
|
||||
|
||||
ts, err := p.Threads()
|
||||
if err != nil {
|
||||
t.Errorf("geting Threads error %v", err)
|
||||
}
|
||||
if len(ts) != int(n) {
|
||||
t.Errorf("unexpected number of threads: %v vs %v", len(ts), n)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_Name(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
n, err := p.Name()
|
||||
if err != nil {
|
||||
t.Errorf("geting name error %v", err)
|
||||
}
|
||||
if !strings.Contains(n, "process.test") {
|
||||
t.Errorf("invalid Exe %s", n)
|
||||
}
|
||||
}
|
||||
func Test_Process_Exe(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
n, err := p.Exe()
|
||||
if err != nil {
|
||||
t.Errorf("geting Exe error %v", err)
|
||||
}
|
||||
if !strings.Contains(n, "process.test") {
|
||||
t.Errorf("invalid Exe %s", n)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_CpuPercent(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
percent, err := p.Percent(0)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
duration := time.Duration(1000) * time.Microsecond
|
||||
time.Sleep(duration)
|
||||
percent, err = p.Percent(0)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
|
||||
numcpu := runtime.NumCPU()
|
||||
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
|
||||
if percent < 0.0 {
|
||||
t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_CpuPercentLoop(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
numcpu := runtime.NumCPU()
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
duration := time.Duration(100) * time.Microsecond
|
||||
percent, err := p.Percent(duration)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
|
||||
if percent < 0.0 {
|
||||
t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Process_CreateTime(t *testing.T) {
|
||||
if os.Getenv("CIRCLECI") == "true" {
|
||||
t.Skip("Skip CI")
|
||||
}
|
||||
|
||||
p := testGetProcess()
|
||||
|
||||
c, err := p.CreateTime()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
|
||||
if c < 1420000000 {
|
||||
t.Errorf("process created time is wrong.")
|
||||
}
|
||||
|
||||
gotElapsed := time.Since(time.Unix(int64(c/1000), 0))
|
||||
maxElapsed := time.Duration(5 * time.Second)
|
||||
|
||||
if gotElapsed >= maxElapsed {
|
||||
t.Errorf("this process has not been running for %v", gotElapsed)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Parent(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
c, err := p.Parent()
|
||||
if err != nil {
|
||||
t.Fatalf("error %v", err)
|
||||
}
|
||||
if c == nil {
|
||||
t.Fatalf("could not get parent")
|
||||
}
|
||||
if c.Pid == 0 {
|
||||
t.Fatalf("wrong parent pid")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Connections(t *testing.T) {
|
||||
p := testGetProcess()
|
||||
|
||||
c, err := p.Connections()
|
||||
if err != nil {
|
||||
t.Fatalf("error %v", err)
|
||||
}
|
||||
// TODO:
|
||||
// Since go test open no conneciton, ret is empty.
|
||||
// should invoke child process or other solutions.
|
||||
if len(c) != 0 {
|
||||
t.Fatalf("wrong connections")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Children(t *testing.T) {
|
||||
p, err := NewProcess(1)
|
||||
if err != nil {
|
||||
t.Fatalf("new process error %v", err)
|
||||
}
|
||||
|
||||
c, err := p.Children()
|
||||
if err != nil {
|
||||
t.Fatalf("error %v", err)
|
||||
}
|
||||
if len(c) == 0 {
|
||||
t.Fatalf("children is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Username(t *testing.T) {
|
||||
myPid := os.Getpid()
|
||||
currentUser, _ := user.Current()
|
||||
myUsername := currentUser.Username
|
||||
|
||||
process, _ := NewProcess(int32(myPid))
|
||||
pidUsername, _ := process.Username()
|
||||
assert.Equal(t, myUsername, pidUsername)
|
||||
|
||||
t.Log(pidUsername)
|
||||
}
|
||||
|
||||
func Test_CPUTimes(t *testing.T) {
|
||||
pid := os.Getpid()
|
||||
process, err := NewProcess(int32(pid))
|
||||
assert.Nil(t, err)
|
||||
|
||||
spinSeconds := 0.2
|
||||
cpuTimes0, err := process.Times()
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Spin for a duration of spinSeconds
|
||||
t0 := time.Now()
|
||||
tGoal := t0.Add(time.Duration(spinSeconds*1000) * time.Millisecond)
|
||||
assert.Nil(t, err)
|
||||
for time.Now().Before(tGoal) {
|
||||
// This block intentionally left blank
|
||||
}
|
||||
|
||||
cpuTimes1, err := process.Times()
|
||||
assert.Nil(t, err)
|
||||
|
||||
if cpuTimes0 == nil || cpuTimes1 == nil {
|
||||
t.FailNow()
|
||||
}
|
||||
measuredElapsed := cpuTimes1.Total() - cpuTimes0.Total()
|
||||
message := fmt.Sprintf("Measured %fs != spun time of %fs\ncpuTimes0=%v\ncpuTimes1=%v",
|
||||
measuredElapsed, spinSeconds, cpuTimes0, cpuTimes1)
|
||||
assert.True(t, measuredElapsed > float64(spinSeconds)/5, message)
|
||||
assert.True(t, measuredElapsed < float64(spinSeconds)*5, message)
|
||||
}
|
||||
|
||||
func Test_OpenFiles(t *testing.T) {
|
||||
pid := os.Getpid()
|
||||
p, err := NewProcess(int32(pid))
|
||||
assert.Nil(t, err)
|
||||
|
||||
v, err := p.OpenFiles()
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, v) // test always open files.
|
||||
|
||||
for _, vv := range v {
|
||||
assert.NotEqual(t, "", vv.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Kill(t *testing.T) {
|
||||
var cmd *exec.Cmd
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd = exec.Command("choice", "/C", "YN", "/D", "Y", "/t", "3")
|
||||
} else {
|
||||
cmd = exec.Command("sleep", "3")
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
assert.NotNil(t, cmd.Run())
|
||||
wg.Done()
|
||||
}()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
p, err := NewProcess(int32(cmd.Process.Pid))
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, p.Kill())
|
||||
wg.Wait()
|
||||
}
|
|
@ -400,7 +400,7 @@ func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error)
|
|||
}
|
||||
|
||||
// User and kernel times are represented as a FILETIME structure
|
||||
// wich contains a 64-bit value representing the number of
|
||||
// which contains a 64-bit value representing the number of
|
||||
// 100-nanosecond intervals since January 1, 1601 (UTC):
|
||||
// http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
|
||||
// To convert it into a float representing the seconds that the
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Hand Writing
|
||||
// - all pointer in ExternProc to uint64
|
||||
|
||||
// +build ignore
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
// +godefs map struct_in_addr [4]byte /* in_addr */
|
||||
// +godefs map struct_in6_addr [16]byte /* in6_addr */
|
||||
// +godefs map struct_ [16]byte /* in6_addr */
|
||||
|
||||
package process
|
||||
|
||||
/*
|
||||
#define __DARWIN_UNIX03 0
|
||||
#define KERNEL
|
||||
#define _DARWIN_USE_64_BIT_INODE
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/message.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/_types/_timeval.h>
|
||||
#include <sys/appleapiopts.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <bsm/audit.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
union sockaddr_all {
|
||||
struct sockaddr s1; // this one gets used for fields
|
||||
struct sockaddr_in s2; // these pad it out
|
||||
struct sockaddr_in6 s3;
|
||||
struct sockaddr_un s4;
|
||||
struct sockaddr_dl s5;
|
||||
};
|
||||
|
||||
struct sockaddr_any {
|
||||
struct sockaddr addr;
|
||||
char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
|
||||
};
|
||||
|
||||
struct ucred_queue {
|
||||
struct ucred *tqe_next;
|
||||
struct ucred **tqe_prev;
|
||||
TRACEBUF
|
||||
};
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
)
|
||||
|
||||
// Time
|
||||
|
||||
type Timespec C.struct_timespec
|
||||
|
||||
type Timeval C.struct_timeval
|
||||
|
||||
// Processes
|
||||
|
||||
type Rusage C.struct_rusage
|
||||
|
||||
type Rlimit C.struct_rlimit
|
||||
|
||||
type UGid_t C.gid_t
|
||||
|
||||
type KinfoProc C.struct_kinfo_proc
|
||||
|
||||
type Eproc C.struct_eproc
|
||||
|
||||
type Proc C.struct_proc
|
||||
|
||||
type Session C.struct_session
|
||||
|
||||
type ucred C.struct_ucred
|
||||
|
||||
type Uucred C.struct__ucred
|
||||
|
||||
type Upcred C.struct__pcred
|
||||
|
||||
type Vmspace C.struct_vmspace
|
||||
|
||||
type Sigacts C.struct_sigacts
|
||||
|
||||
type ExternProc C.struct_extern_proc
|
||||
|
||||
type Itimerval C.struct_itimerval
|
||||
|
||||
type Vnode C.struct_vnode
|
||||
|
||||
type Pgrp C.struct_pgrp
|
||||
|
||||
type UserStruct C.struct_user
|
||||
|
||||
type Au_session C.struct_au_session
|
||||
|
||||
type Posix_cred C.struct_posix_cred
|
||||
|
||||
type Label C.struct_label
|
||||
|
||||
type AuditinfoAddr C.struct_auditinfo_addr
|
||||
type AuMask C.struct_au_mask
|
||||
type AuTidAddr C.struct_au_tid_addr
|
||||
|
||||
// TAILQ(ucred)
|
||||
type UcredQueue C.struct_ucred_queue
|
|
@ -0,0 +1,95 @@
|
|||
// +build ignore
|
||||
|
||||
// We still need editing by hands.
|
||||
// go tool cgo -godefs types_freebsd.go | sed 's/\*int64/int64/' | sed 's/\*byte/int64/' > process_freebsd_amd64.go
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
// +godefs map struct_pargs int64 /* pargs */
|
||||
// +godefs map struct_proc int64 /* proc */
|
||||
// +godefs map struct_user int64 /* user */
|
||||
// +godefs map struct_vnode int64 /* vnode */
|
||||
// +godefs map struct_vnode int64 /* vnode */
|
||||
// +godefs map struct_filedesc int64 /* filedesc */
|
||||
// +godefs map struct_vmspace int64 /* vmspace */
|
||||
// +godefs map struct_pcb int64 /* pcb */
|
||||
// +godefs map struct_thread int64 /* thread */
|
||||
// +godefs map struct___sigset [16]byte /* sigset */
|
||||
|
||||
package process
|
||||
|
||||
/*
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
CTLKern = 1 // "high kernel": proc, limits
|
||||
KernProc = 14 // struct: process entries
|
||||
KernProcPID = 1 // by process id
|
||||
KernProcProc = 8 // only return procs
|
||||
KernProcPathname = 12 // path to executable
|
||||
KernProcArgs = 7 // get/set arguments/proctitle
|
||||
)
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
)
|
||||
|
||||
const (
|
||||
sizeOfKinfoVmentry = C.sizeof_struct_kinfo_vmentry
|
||||
sizeOfKinfoProc = C.sizeof_struct_kinfo_proc
|
||||
)
|
||||
|
||||
// from sys/proc.h
|
||||
const (
|
||||
SIDL = 1 /* Process being created by fork. */
|
||||
SRUN = 2 /* Currently runnable. */
|
||||
SSLEEP = 3 /* Sleeping on an address. */
|
||||
SSTOP = 4 /* Process debugging or suspension. */
|
||||
SZOMB = 5 /* Awaiting collection by parent. */
|
||||
SWAIT = 6 /* Waiting for interrupt. */
|
||||
SLOCK = 7 /* Blocked on a lock. */
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
)
|
||||
|
||||
// Time
|
||||
|
||||
type Timespec C.struct_timespec
|
||||
|
||||
type Timeval C.struct_timeval
|
||||
|
||||
// Processes
|
||||
|
||||
type Rusage C.struct_rusage
|
||||
|
||||
type Rlimit C.struct_rlimit
|
||||
|
||||
type KinfoProc C.struct_kinfo_proc
|
||||
|
||||
type Priority C.struct_priority
|
||||
|
||||
type KinfoVmentry C.struct_kinfo_vmentry
|
|
@ -0,0 +1,103 @@
|
|||
// +build ignore
|
||||
|
||||
// We still need editing by hands.
|
||||
// go tool cgo -godefs types_openbsd.go | sed 's/\*int64/int64/' | sed 's/\*byte/int64/' > process_openbsd_amd64.go
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
// +godefs map struct_pargs int64 /* pargs */
|
||||
// +godefs map struct_proc int64 /* proc */
|
||||
// +godefs map struct_user int64 /* user */
|
||||
// +godefs map struct_vnode int64 /* vnode */
|
||||
// +godefs map struct_vnode int64 /* vnode */
|
||||
// +godefs map struct_filedesc int64 /* filedesc */
|
||||
// +godefs map struct_vmspace int64 /* vmspace */
|
||||
// +godefs map struct_pcb int64 /* pcb */
|
||||
// +godefs map struct_thread int64 /* thread */
|
||||
// +godefs map struct___sigset [16]byte /* sigset */
|
||||
|
||||
package process
|
||||
|
||||
/*
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
CTLKern = 1 // "high kernel": proc, limits
|
||||
KernProc = 66 // struct: process entries
|
||||
KernProcAll = 0
|
||||
KernProcPID = 1 // by process id
|
||||
KernProcProc = 8 // only return procs
|
||||
KernProcPathname = 12 // path to executable
|
||||
KernProcArgs = 55 // get/set arguments/proctitle
|
||||
KernProcArgv = 1
|
||||
KernProcEnv = 3
|
||||
)
|
||||
|
||||
const (
|
||||
ArgMax = 256 * 1024 // sys/syslimits.h:#define ARG_MAX
|
||||
)
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
)
|
||||
|
||||
const (
|
||||
sizeOfKinfoVmentry = C.sizeof_struct_kinfo_vmentry
|
||||
sizeOfKinfoProc = C.sizeof_struct_kinfo_proc
|
||||
)
|
||||
|
||||
// from sys/proc.h
|
||||
const (
|
||||
SIDL = 1 /* Process being created by fork. */
|
||||
SRUN = 2 /* Currently runnable. */
|
||||
SSLEEP = 3 /* Sleeping on an address. */
|
||||
SSTOP = 4 /* Process debugging or suspension. */
|
||||
SZOMB = 5 /* Awaiting collection by parent. */
|
||||
SDEAD = 6 /* Thread is almost gone */
|
||||
SONPROC = 7 /* Thread is currently on a CPU. */
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
)
|
||||
|
||||
// Time
|
||||
|
||||
type Timespec C.struct_timespec
|
||||
|
||||
type Timeval C.struct_timeval
|
||||
|
||||
// Processes
|
||||
|
||||
type Rusage C.struct_rusage
|
||||
|
||||
type Rlimit C.struct_rlimit
|
||||
|
||||
type KinfoProc C.struct_kinfo_proc
|
||||
|
||||
type Priority C.struct_priority
|
||||
|
||||
type KinfoVmentry C.struct_kinfo_vmentry
|
|
@ -223,13 +223,13 @@
|
|||
{"path":"github.com/ryanuber/columnize","checksumSHA1":"M57Rrfc8Z966p+IBtQ91QOcUtcg=","comment":"v2.0.1-8-g983d3a5","revision":"abc90934186a77966e2beeac62ed966aac0561d5","revisionTime":"2017-07-03T20:58:27Z"},
|
||||
{"path":"github.com/sean-/seed","checksumSHA1":"tnMZLo/kR9Kqx6GtmWwowtTLlA8=","revision":"e2103e2c35297fb7e17febb81e49b312087a2372","revisionTime":"2017-03-13T16:33:22Z"},
|
||||
{"path":"github.com/sethgrid/pester","checksumSHA1":"8Lm8nsMCFz4+gr9EvQLqK8+w+Ks=","revision":"8053687f99650573b28fb75cddf3f295082704d7","revisionTime":"2016-04-29T17:20:22Z"},
|
||||
{"path":"github.com/shirou/gopsutil/cpu","checksumSHA1":"T2ThCk35wXAZGh37nrgA07199dA=","revision":"1c211f0807a3436707409fa313599dd8c7a48664","revisionTime":"2017-08-17T03:45:37Z"},
|
||||
{"path":"github.com/shirou/gopsutil/disk","checksumSHA1":"T4uyVXPqCS5rj4vYLgv04as0Avw=","revision":"1c211f0807a3436707409fa313599dd8c7a48664","revisionTime":"2017-08-17T03:45:37Z"},
|
||||
{"path":"github.com/shirou/gopsutil/host","checksumSHA1":"YBXpUckp1TtJf2mfMLx/bpnm22Q=","revision":"1c211f0807a3436707409fa313599dd8c7a48664","revisionTime":"2017-08-17T03:45:37Z"},
|
||||
{"path":"github.com/shirou/gopsutil/internal/common","checksumSHA1":"jUWM0P4G1bHpO9CPS8gcr4rt1t0=","revision":"1c211f0807a3436707409fa313599dd8c7a48664","revisionTime":"2017-08-17T03:45:37Z"},
|
||||
{"path":"github.com/shirou/gopsutil/mem","checksumSHA1":"xIAuacHA0LNq1yM5Wd1q4lnbzxU=","revision":"1c211f0807a3436707409fa313599dd8c7a48664","revisionTime":"2017-08-17T03:45:37Z"},
|
||||
{"path":"github.com/shirou/gopsutil/net","checksumSHA1":"moxD+mq0dMHnbTeFyeEHK0Iq7i8=","revision":"1c211f0807a3436707409fa313599dd8c7a48664","revisionTime":"2017-08-17T03:45:37Z"},
|
||||
{"path":"github.com/shirou/gopsutil/process","checksumSHA1":"Ylp6t7kozHBFREv3tBcK4B1SMI4=","revision":"12ab94e8042b4639d3cbd6bdafd0be9be8a33e88","revisionTime":"2018-02-21T07:26:18Z"},
|
||||
{"path":"github.com/shirou/gopsutil/cpu","checksumSHA1":"k+PmW/6PFt0FVFTTnfMbWwrm9hU=","revision":"5776ff9c7c5d063d574ef53d740f75c68b448e53","revisionTime":"2018-02-27T22:58:47Z","tree":true},
|
||||
{"path":"github.com/shirou/gopsutil/disk","checksumSHA1":"4DZwA8Xf2Zs8vhIc9kx8TIBMmSY=","revision":"5776ff9c7c5d063d574ef53d740f75c68b448e53","revisionTime":"2018-02-27T22:58:47Z","tree":true},
|
||||
{"path":"github.com/shirou/gopsutil/host","checksumSHA1":"EwRUlC1p+bryrvxV3UqgDcauZ0U=","revision":"5776ff9c7c5d063d574ef53d740f75c68b448e53","revisionTime":"2018-02-27T22:58:47Z","tree":true},
|
||||
{"path":"github.com/shirou/gopsutil/internal/common","checksumSHA1":"S31u6j9yi6MOblZ1x83k/HDuNtA=","revision":"5776ff9c7c5d063d574ef53d740f75c68b448e53","revisionTime":"2018-02-27T22:58:47Z","tree":true},
|
||||
{"path":"github.com/shirou/gopsutil/mem","checksumSHA1":"1u1St5K2LtEcQsh5ySmvoTZ8k0I=","revision":"5776ff9c7c5d063d574ef53d740f75c68b448e53","revisionTime":"2018-02-27T22:58:47Z","tree":true},
|
||||
{"path":"github.com/shirou/gopsutil/net","checksumSHA1":"ME2P9hiaHO/YdVrNInDmb/dB6us=","revision":"5776ff9c7c5d063d574ef53d740f75c68b448e53","revisionTime":"2018-02-27T22:58:47Z","tree":true},
|
||||
{"path":"github.com/shirou/gopsutil/process","checksumSHA1":"JuBAKUuSyR7RdJELt6tQMn79Y6w=","revision":"5776ff9c7c5d063d574ef53d740f75c68b448e53","revisionTime":"2018-02-27T22:58:47Z","tree":true},
|
||||
{"path":"github.com/shirou/w32","checksumSHA1":"Nve7SpDmjsv6+rhkXAkfg/UQx94=","revision":"bb4de0191aa41b5507caa14b0650cdbddcd9280b","revisionTime":"2016-09-30T03:27:40Z"},
|
||||
{"path":"github.com/skratchdot/open-golang/open","checksumSHA1":"h/HMhokbQHTdLUbruoBBTee+NYw=","revision":"75fb7ed4208cf72d323d7d02fd1a5964a7a9073c","revisionTime":"2016-03-02T14:40:31Z"},
|
||||
{"path":"github.com/spf13/pflag","checksumSHA1":"Q52Y7t0lEtk/wcDn5q7tS7B+jqs=","revision":"7aff26db30c1be810f9de5038ec5ef96ac41fd7c","revisionTime":"2017-08-24T17:57:12Z"},
|
||||
|
|
Loading…
Reference in New Issue