Vendored gopsutil to fix partial vendoring

This commit is contained in:
Charlie Voiselle 2018-03-05 19:52:43 -05:00
parent 0dd9606817
commit 192176b89e
73 changed files with 3499 additions and 356 deletions

61
vendor/github.com/shirou/gopsutil/LICENSE generated vendored Normal file
View File

@ -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.

View File

@ -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)
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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++ {

View File

@ -0,0 +1,9 @@
package cpu
type cpuTimes struct {
User uint32
Nice uint32
Sys uint32
Intr uint32
Idle uint32
}

View File

@ -0,0 +1,9 @@
package cpu
type cpuTimes struct {
User uint64
Nice uint64
Sys uint64
Intr uint64
Idle uint64
}

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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{}

View File

@ -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)

View File

@ -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)
}
}
}

145
vendor/github.com/shirou/gopsutil/cpu/cpu_test.go generated vendored Normal file
View File

@ -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)
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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")
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

127
vendor/github.com/shirou/gopsutil/disk/disk_solaris.go generated vendored Normal file
View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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,

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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 {

150
vendor/github.com/shirou/gopsutil/host/host_test.go generated vendored Normal file
View File

@ -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)
}

View File

@ -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
}

View File

@ -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

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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")

View File

@ -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

View File

@ -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()

View File

@ -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)
}

View File

@ -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
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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
}

77
vendor/github.com/shirou/gopsutil/mem/mem_test.go generated vendored Normal file
View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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")
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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]
}

163
vendor/github.com/shirou/gopsutil/net/net_linux_test.go generated vendored Normal file
View File

@ -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))
}

View File

@ -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
}

229
vendor/github.com/shirou/gopsutil/net/net_test.go generated vendored Normal file
View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -1,10 +0,0 @@
PID
245
247
248
249
254
262
264
265
267

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

14
vendor/vendor.json vendored
View File

@ -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"},