Add perf test suite infrastructure, and a perf test for csv-import (#2384)

You can run these yourself using the -perf flag, e.g.

> noms serve &
> go test -v -perf http://localhost:8000 ./samples/go/csv/csv-import
> noms ds http://localhost:8000

Though you'll need to go-get github.com/attic-labs/testdata.

Note that all of this only records test results, it doesn't have any
concept of failing perf (unless test assertsions themselves fail). It
will be the job of some other Noms client (work in progress) to do that.

I will be setting this up to run continuously momentarily.
This commit is contained in:
Ben Kalman
2016-08-18 15:49:21 -07:00
committed by GitHub
parent 15d80f9afd
commit 064c398dec
108 changed files with 13573 additions and 11 deletions

View File

@@ -21,7 +21,7 @@ type connectionState struct {
cs http.ConnState
}
type remoteDatabaseServer struct {
type RemoteDatabaseServer struct {
cs chunks.ChunkStore
port int
l *net.Listener
@@ -31,21 +31,21 @@ type remoteDatabaseServer struct {
Ready func()
}
func NewRemoteDatabaseServer(cs chunks.ChunkStore, port int) *remoteDatabaseServer {
func NewRemoteDatabaseServer(cs chunks.ChunkStore, port int) *RemoteDatabaseServer {
dataVersion := cs.Version()
d.PanicIfTrue(constants.NomsVersion != dataVersion, "SDK version %s is incompatible with data of version %s", constants.NomsVersion, dataVersion)
return &remoteDatabaseServer{
return &RemoteDatabaseServer{
cs, port, nil, make(chan *connectionState, 16), false, func() {},
}
}
// Port is the actual port used. This may be different than the port passed in to NewRemoteDatabaseServer.
func (s *remoteDatabaseServer) Port() int {
func (s *RemoteDatabaseServer) Port() int {
return s.port
}
// Run blocks while the remoteDatabaseServer is listening. Running on a separate go routine is supported.
func (s *remoteDatabaseServer) Run() {
// Run blocks while the RemoteDatabaseServer is listening. Running on a separate go routine is supported.
func (s *RemoteDatabaseServer) Run() {
l, err := net.Listen("tcp", fmt.Sprintf(":%d", s.port))
d.Chk.NoError(err)
@@ -95,7 +95,7 @@ func (s *remoteDatabaseServer) Run() {
srv.Serve(l)
}
func (s *remoteDatabaseServer) makeHandle(hndlr Handler) httprouter.Handle {
func (s *RemoteDatabaseServer) makeHandle(hndlr Handler) httprouter.Handle {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
hndlr(w, req, ps, s.cs)
}
@@ -104,7 +104,7 @@ func (s *remoteDatabaseServer) makeHandle(hndlr Handler) httprouter.Handle {
func noopHandle(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
}
func (s *remoteDatabaseServer) corsHandle(f httprouter.Handle) httprouter.Handle {
func (s *RemoteDatabaseServer) corsHandle(f httprouter.Handle) httprouter.Handle {
// TODO: Implement full pre-flighting?
// See: http://www.html5rocks.com/static/images/cors_server_flowchart.png
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
@@ -118,7 +118,7 @@ func (s *remoteDatabaseServer) corsHandle(f httprouter.Handle) httprouter.Handle
}
}
func (s *remoteDatabaseServer) connState(c net.Conn, cs http.ConnState) {
func (s *RemoteDatabaseServer) connState(c net.Conn, cs http.ConnState) {
if s.closing {
d.Chk.True(cs == http.StateClosed)
return
@@ -126,8 +126,8 @@ func (s *remoteDatabaseServer) connState(c net.Conn, cs http.ConnState) {
s.csChan <- &connectionState{c, cs}
}
// Will cause the remoteDatabaseServer to stop listening and an existing call to Run() to continue.
func (s *remoteDatabaseServer) Stop() {
// Will cause the RemoteDatabaseServer to stop listening and an existing call to Run() to continue.
func (s *RemoteDatabaseServer) Stop() {
s.closing = true
(*s.l).Close()
(s.cs).Close()

409
go/perf/suite/suite.go Normal file
View File

@@ -0,0 +1,409 @@
// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0
// Package suite implements a performance test suite for Noms, intended for measuring and reporting long running tests.
//
// Usage is similar to testify's suite:
//
// 1. Define a test suite struct which inherits from `suite.PerfSuite`.
// 2. Define methods on that struct that start with the word "Test", optionally followed by digits, then followed a non-empty capitalized string.
// 3. Call `suite.Run` with an instance of that struct.
// 4. Run `go test` with the `-perf <path to noms db>` flag. Use `-perf.repeat` to set how many times tests are repeated.
//
// `PerfSuite` also supports testify/suite style `Setup/TearDown` methods.
// - `Setup/TearDownSuite` is called exactly once.
// - `Setup/TearDownRep` is called once for each repetition of the test runs, i.e. `-perf.repeat` times.
// - `Setup/TearDownTest` is called for every test.
//
// Test results are written to Noms, along with a soup of the environment they were recorded in.
//
// Test names are derived from that "non-empty capitalized string": `"Test"` is ommitted because it's redundant, and leading digits are omitted to allow for manual test ordering. For example:
//
// ```
// > cat ./samples/go/csv/csv-import/perf_test.go
// type perfSuite {
// suite.PerfSuite
// }
//
// func (s *perfSuite) TestFoo() { ... }
// func (s *perfSuite) TestZoo() { ... }
// func (s *perfSuite) Test01Qux() { ... }
// func (s *perfSuite) Test02Bar() { ... }
//
// func TestPerf(t *testing.T) {
// suite.Run("csv-import", t, &perfSuite{})
// }
//
// > go test -v ./samples/go/csv/... -perf http://localhost:8000 -perf.repeat 3
// (perf) RUN(1/3) Test01Qux (recorded as "Qux")
// (perf) PASS: Test01Qux (5s, paused 15s, total 20s)
// (perf) RUN(1/3) Test02Bar (recorded as "Bar")
// (perf) PASS: Test02Bar (15s, paused 2s, total 17s)
// (perf) RUN(1/3) TestFoo (recorded as "Foo")
// (perf) PASS: TestFoo (10s, paused 1s, total 11s)
// (perf) RUN(1/3) TestZoo (recorded as "Zoo")
// (perf) PASS: TestZoo (1s, paused 42s, total 43s)
// ...
//
// > noms show http://localhost:8000::csv-import
// {
// environment: ...
// tests: [{
// "Bar": {elapsed: 15s, paused: 2s, total: 17s},
// "Foo": {elapsed: 10s, paused: 1s, total: 11s},
// "Qux": {elapsed: 5s, paused: 15s, total: 20s},
// "Zoo": {elapsed: 1s, paused: 42s, total: 43s},
// }, ...]
// ...
// }
// ```
package suite
import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"reflect"
"regexp"
"strings"
"testing"
"time"
"github.com/attic-labs/noms/go/chunks"
"github.com/attic-labs/noms/go/datas"
"github.com/attic-labs/noms/go/dataset"
"github.com/attic-labs/noms/go/marshal"
"github.com/attic-labs/noms/go/spec"
"github.com/attic-labs/noms/go/types"
"github.com/attic-labs/testify/assert"
testifySuite "github.com/attic-labs/testify/suite"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/mem"
)
var (
perfFlag = flag.String("perf", "", "The database to write perf tests to. If this isn't specified, perf tests are skipped. If you want a dry run, use \"mem\" as a database")
perfRepeatFlag = flag.Int("perf.repeat", 1, "The number of times to repeat each perf test")
perfMemFlag = flag.Bool("perf.mem", false, "Back the test database with a memory store, not leveldb. This will affect test timing, but it's provided in case you're low on disk space")
testNamePattern = regexp.MustCompile("^Test[0-9]*([A-Z].*$)")
)
// PerfSuite is the core of the perf testing suite. See package documentation for details.
type PerfSuite struct {
// T is the `testing.T` instance set when the suite is passed into `Run`.
T *testing.T
// W is the `io.Writer` to write test output, which only outputs if the verbose flag is set.
W io.Writer
// AtticLabs is the path to the attic-labs directory (e.g. /path/to/go/src/github.com/attic-labs).
AtticLabs string
// Database is a Noms database that tests can use for reading and writing. State is persisted across a single Run of a suite.
Database datas.Database
// DatabaseSpec is the Noms spec of `Database` (typically a localhost URL).
DatabaseSpec string
tempFiles []*os.File
tempDirs []string
paused time.Duration
}
// SetupRepSuite has a SetupRep method, which runs every repetition of the test, i.e. `-perf.repeat` times in total.
type SetupRepSuite interface {
SetupRep()
}
// TearDownRepSuite has a TearDownRep method, which runs every repetition of the test, i.e. `-perf.repeat` times in total.
type TearDownRepSuite interface {
TearDownRep()
}
type perfSuiteT interface {
Suite() *PerfSuite
}
type timeInfo struct {
elapsed, paused, total time.Duration
}
type testRep map[string]timeInfo
type nopWriter struct{}
func (r nopWriter) Write(p []byte) (int, error) {
return len(p), nil
}
// Run runs `suiteT` and writes results to dataset `datasetID` in the database given by the `-perf` command line flag.
func Run(datasetID string, t *testing.T, suiteT perfSuiteT) {
if *perfFlag == "" {
return
}
assert := assert.New(t)
// Piggy-back off the go test -v flag.
verboseFlag := flag.Lookup("test.v")
assert.NotNil(verboseFlag)
verbose := verboseFlag.Value.(flag.Getter).Get().(bool)
suite := suiteT.Suite()
suite.T = t
if verbose {
suite.W = os.Stdout
} else {
suite.W = nopWriter{}
}
gopath := os.Getenv("GOPATH")
assert.NotEmpty(gopath)
suite.AtticLabs = path.Join(gopath, "src", "github.com", "attic-labs")
// Clean up temporary directories/files last.
defer func() {
for _, f := range suite.tempFiles {
os.Remove(f.Name())
}
for _, d := range suite.tempDirs {
os.RemoveAll(d)
}
}()
// This is the database the perf test results are written to.
db, err := spec.GetDatabase(*perfFlag)
assert.NoError(err)
// This is the temporary database for tests to use.
//
// * Why not use a local database + memory store?
// Firstly, because the spec would be "mem", and the spec library doesn't know how to reuse stores.
// Secondly, because it's an unrealistic performance measurement.
//
// * Why use a remote (HTTP) database?
// It's more realistic to exercise the HTTP stack, even if it's just talking over localhost.
//
// * Why provide an option for leveldb vs memory underlying store?
// Again, leveldb is more realistic than memory, and in common cases disk space > memory space.
// However, on this developer's laptop, there is actually very little disk space, and a lot of memory;
// plus making the test run a little bit faster locally is nice.
var chunkStore chunks.ChunkStore
if *perfMemFlag {
chunkStore = chunks.NewMemoryStore()
} else {
ldbDir := suite.TempDir("suite.suite")
chunkStore = chunks.NewLevelDBStoreUseFlags(ldbDir, "")
}
server := datas.NewRemoteDatabaseServer(chunkStore, 0)
portChan := make(chan int)
server.Ready = func() { portChan <- server.Port() }
go server.Run()
defer server.Stop()
port := <-portChan
suite.DatabaseSpec = fmt.Sprintf("http://localhost:%d", port)
suite.Database = datas.NewRemoteDatabase(suite.DatabaseSpec, "")
// List of test runs, each a map of test name => timing info.
testReps := make([]testRep, *perfRepeatFlag)
defer func() {
reps := make([]types.Value, *perfRepeatFlag)
for i, rep := range testReps {
timesSlice := types.ValueSlice{}
for name, info := range rep {
timesSlice = append(timesSlice, types.String(name), types.NewStruct("", types.StructData{
"elapsed": types.Number(info.elapsed.Nanoseconds()),
"paused": types.Number(info.paused.Nanoseconds()),
"total": types.Number(info.total.Nanoseconds()),
}))
}
reps[i] = types.NewMap(timesSlice...)
}
record := types.NewStruct("", map[string]types.Value{
"environment": suite.getEnvironment(),
"nomsRevision": types.String(suite.getGitHead(path.Join(suite.AtticLabs, "noms"))),
"testdataRevision": types.String(suite.getGitHead(path.Join(suite.AtticLabs, "testdata"))),
"reps": types.NewList(reps...),
})
ds := dataset.NewDataset(db, datasetID)
var err error
ds, err = ds.CommitValue(record)
assert.NoError(err)
assert.NoError(db.Close())
}()
if t, ok := suiteT.(testifySuite.SetupAllSuite); ok {
t.SetupSuite()
}
for repIdx := 0; repIdx < *perfRepeatFlag; repIdx++ {
testReps[repIdx] = testRep{}
if t, ok := suiteT.(SetupRepSuite); ok {
t.SetupRep()
}
for t, mIdx := reflect.TypeOf(suiteT), 0; mIdx < t.NumMethod(); mIdx++ {
m := t.Method(mIdx)
parts := testNamePattern.FindStringSubmatch(m.Name)
if parts == nil {
continue
}
if t, ok := suiteT.(testifySuite.SetupTestSuite); ok {
t.SetupTest()
}
recordName := parts[1]
if verbose {
fmt.Printf("(perf) RUN(%d/%d) %s (as \"%s\")\n", repIdx+1, *perfRepeatFlag, m.Name, recordName)
}
start := time.Now()
suite.paused = 0
err := callSafe(m.Name, m.Func, suiteT)
total := time.Since(start)
elapsed := total - suite.paused
if verbose && err == nil {
fmt.Printf("(perf) PASS: %s (%s, paused for %s, total %s)\n", m.Name, elapsed, suite.paused, total)
} else if err != nil {
fmt.Printf("(perf) FAIL: %s (%s, paused for %s, total %s)\n", m.Name, elapsed, suite.paused, total)
fmt.Println(err)
}
testReps[repIdx][recordName] = timeInfo{elapsed, suite.paused, total}
if t, ok := suiteT.(testifySuite.TearDownTestSuite); ok {
t.TearDownTest()
}
}
if t, ok := suiteT.(TearDownRepSuite); ok {
t.TearDownRep()
}
}
if t, ok := suiteT.(testifySuite.TearDownAllSuite); ok {
t.TearDownSuite()
}
}
func (suite *PerfSuite) Suite() *PerfSuite {
return suite
}
// NewAssert returns the `assert.Assertions` instance for this test.
func (suite *PerfSuite) NewAssert() *assert.Assertions {
return assert.New(suite.T)
}
// TempFile creates a temporary file, which will be automatically cleaned up by the perf test suite.
func (suite *PerfSuite) TempFile(prefix string) *os.File {
f, err := ioutil.TempFile("", prefix)
assert.NoError(suite.T, err)
suite.tempFiles = append(suite.tempFiles, f)
return f
}
// TempDir creates a temporary directory, which will be automatically cleaned up by the perf test suite.
func (suite *PerfSuite) TempDir(prefix string) string {
d, err := ioutil.TempDir("", prefix)
assert.NoError(suite.T, err)
suite.tempDirs = append(suite.tempDirs, d)
return d
}
// Pause pauses the test timer while `fn` is executing. Useful for omitting long setup code (e.g. copying files) from the test elapsed time.
func (suite *PerfSuite) Pause(fn func()) {
start := time.Now()
fn()
suite.paused += time.Since(start)
}
func callSafe(name string, fun reflect.Value, args ...interface{}) (err interface{}) {
defer func() {
if r := recover(); r != nil {
err = r
}
}()
funArgs := make([]reflect.Value, len(args))
for i, arg := range args {
funArgs[i] = reflect.ValueOf(arg)
}
fun.Call(funArgs)
return
}
func (suite *PerfSuite) getEnvironment() types.Struct {
assert := suite.NewAssert()
cpuInfos, err := cpu.Info()
assert.NoError(err)
cpus := make([]types.Value, 0, 2*len(cpuInfos))
for i, c := range cpuInfos {
cm, err := marshal.Marshal(c)
assert.NoError(err)
cpus = append(cpus, types.Number(i), cm)
}
vmStat, err := mem.VirtualMemory()
assert.NoError(err)
mem, err := marshal.Marshal(*vmStat)
assert.NoError(err)
hostInfo, err := host.Info()
assert.NoError(err)
host, err := marshal.Marshal(*hostInfo)
assert.NoError(err)
partitionStats, err := disk.Partitions(false)
assert.NoError(err)
partitions := make([]types.Value, 0, 2*len(partitionStats))
diskUsages := make([]types.Value, 0, 2*len(partitionStats))
for _, p := range partitionStats {
pm, err := marshal.Marshal(p)
assert.NoError(err)
partitions = append(partitions, types.String(p.Device), pm)
du, err := disk.Usage(p.Mountpoint)
assert.NoError(err)
dum, err := marshal.Marshal(*du)
assert.NoError(err)
diskUsages = append(diskUsages, types.String(p.Mountpoint), dum)
}
return types.NewStruct("", types.StructData{
"diskUsages": types.NewMap(diskUsages...),
"cpus": types.NewMap(cpus...),
"mem": mem,
"host": host,
"partitions": types.NewMap(partitions...),
})
}
func (suite *PerfSuite) getGitHead(dir string) string {
stdout := &bytes.Buffer{}
cmd := exec.Command("git", "rev-parse", "HEAD")
cmd.Stdout = stdout
cmd.Dir = dir
if err := cmd.Run(); err != nil {
return ""
}
return strings.TrimSpace(stdout.String())
}

200
go/perf/suite/suite_test.go Normal file
View File

@@ -0,0 +1,200 @@
// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0
package suite
import (
"io/ioutil"
"os"
"testing"
"time"
"github.com/attic-labs/noms/go/spec"
"github.com/attic-labs/noms/go/types"
"github.com/attic-labs/testify/assert"
)
type testSuite struct {
PerfSuite
tempFileName, tempDir string
setupTest, tearDownTest int
setupRep, tearDownRep int
setupSuite, tearDownSuite int
}
// This is the only test that does anything interesting. The others are just to test naming.
func (s *testSuite) TestInterestingStuff() {
assert := s.NewAssert()
assert.NotNil(s.T)
assert.NotNil(s.W)
assert.NotEqual("", s.AtticLabs)
assert.NotEqual("", s.DatabaseSpec)
val := types.Bool(true)
r := s.Database.WriteValue(val)
assert.True(s.Database.ReadValue(r.TargetHash()).Equals(val))
s.Pause(func() {
s.waitForSmidge()
})
s.tempFileName = s.TempFile("suite.suite_test").Name()
s.tempDir = s.TempDir("suite.suite_test")
}
func (s *testSuite) TestFoo() {
s.waitForSmidge()
}
func (s *testSuite) TestBar() {
s.waitForSmidge()
}
func (s *testSuite) Test01Abc() {
s.waitForSmidge()
}
func (s *testSuite) Test02Def() {
s.waitForSmidge()
}
func (s *testSuite) testNothing() {
s.waitForSmidge()
}
func (s *testSuite) Testimate() {
s.waitForSmidge()
}
func (s *testSuite) SetupTest() {
s.setupTest++
}
func (s *testSuite) TearDownTest() {
s.tearDownTest++
}
func (s *testSuite) SetupRep() {
s.setupRep++
}
func (s *testSuite) TearDownRep() {
s.tearDownRep++
}
func (s *testSuite) SetupSuite() {
s.setupSuite++
}
func (s *testSuite) TearDownSuite() {
s.tearDownSuite++
}
func (s *testSuite) waitForSmidge() {
// Tests should call this to make sure the measurement shows up as > 0, not that it shows up as a millisecond.
<-time.After(time.Millisecond)
}
func TestSuite(t *testing.T) {
runTestSuite(t, false)
}
func TestSuiteWithMem(t *testing.T) {
runTestSuite(t, true)
}
func runTestSuite(t *testing.T, mem bool) {
assert := assert.New(t)
// Write test results to our own temporary LDB database.
ldbDir, err := ioutil.TempDir("", "suite.TestSuite")
assert.NoError(err)
defer os.RemoveAll(ldbDir)
perfFlagVal := *perfFlag
perfRepeatFlagVal := *perfRepeatFlag
perfMemFlagVal := *perfMemFlag
*perfFlag = ldbDir
*perfRepeatFlag = 3
*perfMemFlag = mem
defer func() {
*perfFlag = perfFlagVal
*perfRepeatFlag = perfRepeatFlagVal
*perfMemFlag = perfMemFlagVal
}()
s := &testSuite{}
Run("ds", t, s)
expectedTests := []string{"Abc", "Bar", "Def", "Foo", "InterestingStuff"}
// The temp file and dir should have been cleaned up.
_, err = os.Stat(s.tempFileName)
assert.NotNil(err)
_, err = os.Stat(s.tempDir)
assert.NotNil(err)
// The correct number of Setup/TearDown calls should have been run.
assert.Equal(1, s.setupSuite)
assert.Equal(1, s.tearDownSuite)
assert.Equal(*perfRepeatFlag, s.setupRep)
assert.Equal(*perfRepeatFlag, s.tearDownRep)
assert.Equal(*perfRepeatFlag*len(expectedTests), s.setupTest)
assert.Equal(*perfRepeatFlag*len(expectedTests), s.tearDownTest)
// The results should have been written to the "ds" dataset.
ds, err := spec.GetDataset(ldbDir + "::ds")
assert.NoError(err)
head := ds.HeadValue().(types.Struct)
// These tests mostly assert that the structure of the results is correct. Specific values are hard.
getOrFail := func(s types.Struct, f string) types.Value {
val, ok := s.MaybeGet(f)
assert.True(ok)
return val
}
env, ok := getOrFail(head, "environment").(types.Struct)
assert.True(ok)
getOrFail(env, "diskUsages")
getOrFail(env, "cpus")
getOrFail(env, "mem")
getOrFail(env, "host")
getOrFail(env, "partitions")
nomsRevision := getOrFail(head, "nomsRevision")
assert.True(ok)
assert.True(string(nomsRevision.(types.String)) != "")
getOrFail(head, "testdataRevision")
reps, ok := getOrFail(head, "reps").(types.List)
assert.True(ok)
assert.Equal(*perfRepeatFlag, int(reps.Len()))
reps.IterAll(func(rep types.Value, _ uint64) {
i := 0
rep.(types.Map).IterAll(func(k, timesVal types.Value) {
assert.True(i < len(expectedTests))
assert.Equal(expectedTests[i], string(k.(types.String)))
times := timesVal.(types.Struct)
assert.True(getOrFail(times, "elapsed").(types.Number) > 0)
assert.True(getOrFail(times, "total").(types.Number) > 0)
paused := getOrFail(times, "paused").(types.Number)
if k == types.String("InterestingStuff") {
assert.True(paused > 0)
} else {
assert.True(paused == 0)
}
i++
})
assert.Equal(i, len(expectedTests))
})
}

View File

@@ -0,0 +1,91 @@
// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0
package main
import (
"fmt"
"io"
"os"
"os/exec"
"path"
"path/filepath"
"testing"
"github.com/attic-labs/noms/go/dataset"
"github.com/attic-labs/noms/go/hash"
"github.com/attic-labs/noms/go/perf/suite"
"github.com/attic-labs/noms/go/types"
"github.com/attic-labs/testify/assert"
humanize "github.com/dustin/go-humanize"
)
// CSV perf suites require the testdata directory to be checked out at $GOPATH/src/github.com/attic-labs/testdata (i.e. ../testdata relative to the noms directory).
// TODO: Add ny-vehicle-registrations test when CSV importing is faster (testdata/ny-vehicle-registrations/20150218.*).
type perfSuite struct {
suite.PerfSuite
csvImportExe string
sfcBlobHash hash.Hash
}
func (s *perfSuite) SetupSuite() {
// Trick the temp file logic into creating a unique path for the csv-import binary.
f := s.TempFile("csv-import.perf_test")
f.Close()
os.Remove(f.Name())
s.csvImportExe = f.Name()
err := exec.Command("go", "build", "-o", s.csvImportExe, "github.com/attic-labs/noms/samples/go/csv/csv-import").Run()
assert.NoError(s.T, err)
}
func (s *perfSuite) Test01ImportSfCrimeBlobFromTestdata() {
assert := s.NewAssert()
var raw []io.Reader
s.Pause(func() {
// The raw data is split into a bunch of files foo.a, foo.b, etc.
glob, err := filepath.Glob(path.Join(s.AtticLabs, "testdata", "sf-crime", "2016-07-28.*"))
assert.NoError(err)
raw = make([]io.Reader, len(glob))
for i, m := range glob {
r, err := os.Open(m)
assert.NoError(err)
raw[i] = r
}
})
defer s.Pause(func() {
for _, r := range raw {
assert.NoError(r.(io.ReadCloser).Close())
}
})
blob := types.NewBlob(io.MultiReader(raw...))
fmt.Fprintf(s.W, "csv/raw is %s\n", humanize.Bytes(blob.Len()))
ds := dataset.NewDataset(s.Database, "csv/raw")
_, err := ds.CommitValue(blob)
assert.NoError(err)
}
func (s *perfSuite) Test02ImportSfCrimeCSVFromBlob() {
assert := s.NewAssert()
blobSpec := fmt.Sprintf("%s::csv/raw.value", s.DatabaseSpec)
destSpec := fmt.Sprintf("%s::csv", s.DatabaseSpec)
importCmd := exec.Command(s.csvImportExe, "-p", blobSpec, destSpec)
importCmd.Stdout = s.W
importCmd.Stderr = os.Stderr
assert.NoError(importCmd.Run())
}
func TestPerf(t *testing.T) {
suite.Run("csv-import", t, &perfSuite{})
}

2
vendor/github.com/shirou/gopsutil/.version generated vendored Normal file
View File

@@ -0,0 +1,2 @@
http://github.com/shirou/gopsutil
e997d2e3dbc8b756de46d61e390ddc54837d63b1

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.

18
vendor/github.com/shirou/gopsutil/Makefile generated vendored Normal file
View File

@@ -0,0 +1,18 @@
.PHONY: help check
.DEFAULT_GOAL := help
SUBPKGS=cpu disk docker host internal load mem net process
help: ## Show help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
check: ## Check
errcheck -ignore="Close|Run|Write" ./...
golint ./... | egrep -v 'underscores|HttpOnly|should have comment|comment on exported|CamelCase|VM|UID'
build_test: ## test only buildable
GOOS=linux go test ./... | grep -v "exec format error"
GOOS=freebsd go test ./... | grep -v "exec format error"
CGO_ENABLED=0 GOOS=darwin go test ./... | grep -v "exec format error"
CGO_ENABLED=1 GOOS=darwin go test ./... | grep -v "exec format error"
GOOS=windows go test ./...| grep -v "exec format error"

300
vendor/github.com/shirou/gopsutil/README.rst generated vendored Normal file
View File

@@ -0,0 +1,300 @@
gopsutil: psutil for golang
==============================
.. image:: https://circleci.com/gh/shirou/gopsutil.svg?&style=shield
:target: https://circleci.com/gh/shirou/gopsutil
.. image:: https://coveralls.io/repos/shirou/gopsutil/badge.svg?branch=master
:target: https://coveralls.io/r/shirou/gopsutil?branch=master
.. image:: https://godoc.org/github.com/shirou/gopsutil?status.svg
:target: http://godoc.org/github.com/shirou/gopsutil
This is a port of psutil (http://pythonhosted.org/psutil/). The challenge is porting all
psutil functions on some architectures.
.. highlights:: Breaking Changes!
Breaking changes is introduced at v2. See `issue 174 <https://github.com/shirou/gopsutil/issues/174>`_ .
Migrating to v2
-------------------------
On gopsutil itself, `v2migration.sh <https://github.com/shirou/gopsutil/blob/v2/v2migration.sh>`_ is used for migration. It can not be commonly used, but it may help you with migration.
Available Architectures
------------------------------------
- FreeBSD i386/amd64
- Linux i386/amd64/arm(raspberry pi)
- Windows/amd64
- Darwin/amd64
All works are implemented without cgo by porting c struct to golang struct.
Usage
---------
Note: gopsutil v2 breaks compatibility. If you want to stay with compatibility, please use v1 branch and vendoring.
.. code:: go
package main
import (
"fmt"
"github.com/shirou/gopsutil/mem"
)
func main() {
v, _ := mem.VirtualMemory()
// almost every return value is a struct
fmt.Printf("Total: %v, Free:%v, UsedPercent:%f%%\n", v.Total, v.Free, v.UsedPercent)
// convert to JSON. String() is also implemented
fmt.Println(v)
}
The output is below.
::
Total: 3179569152, Free:284233728, UsedPercent:84.508194%
{"total":3179569152,"available":492572672,"used":2895335424,"usedPercent":84.50819439828305, (snip...)}
You can set an alternative location to :code:`/proc` by setting the :code:`HOST_PROC` environment variable.
You can set an alternative location to :code:`/sys` by setting the :code:`HOST_SYS` environment variable.
You can set an alternative location to :code:`/etc` by setting the :code:`HOST_ETC` environment variable.
Documentation
------------------------
see http://godoc.org/github.com/shirou/gopsutil
Requirements
-----------------
- go1.5 or above is required.
More Info
--------------------
Several methods have been added which are not present in psutil, but will provide useful information.
- host/HostInfo() (linux)
- Hostname
- Uptime
- Procs
- OS (ex: "linux")
- Platform (ex: "ubuntu", "arch")
- PlatformFamily (ex: "debian")
- PlatformVersion (ex: "Ubuntu 13.10")
- VirtualizationSystem (ex: "LXC")
- VirtualizationRole (ex: "guest"/"host")
- cpu/CPUInfo() (linux, freebsd)
- CPU (ex: 0, 1, ...)
- VendorID (ex: "GenuineIntel")
- Family
- Model
- Stepping
- PhysicalID
- CoreID
- Cores (ex: 2)
- ModelName (ex: "Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz")
- Mhz
- CacheSize
- Flags (ex: "fpu vme de pse tsc msr pae mce cx8 ...")
- load/LoadAvg() (linux, freebsd)
- Load1
- Load5
- Load15
- docker/GetDockerIDList() (linux only)
- container id list ([]string)
- docker/CgroupCPU() (linux only)
- user
- system
- docker/CgroupMem() (linux only)
- various status
- net_protocols (linux only)
- system wide stats on network protocols (i.e IP, TCP, UDP, etc.)
- sourced from /proc/net/snmp
- iptables nf_conntrack (linux only)
- system wide stats on netfilter conntrack module
- sourced from /proc/sys/net/netfilter/nf_conntrack_count
Some codes are ported from Ohai. many thanks.
Current Status
------------------
- x: work
- b: almost works, but something is broken
================= ====== ======= ====== =======
name Linux FreeBSD MacOSX Windows
cpu_times x x x x
cpu_count x x x x
cpu_percent x x x x
cpu_times_percent x x x x
virtual_memory x x x x
swap_memory x x x
disk_partitions x x x x
disk_io_counters x x
disk_usage x x x x
net_io_counters x x b x
boot_time x x x x
users x x x x
pids x x x x
pid_exists x x x x
net_connections x x
net_protocols x
net_if_addrs
net_if_stats
netfilter_conntrack x
================= ====== ======= ====== =======
Process class
^^^^^^^^^^^^^^^
================ ===== ======= ====== =======
name Linux FreeBSD MacOSX Windows
pid x x x x
ppid x x x x
name x x x x
cmdline x x x
create_time x
status x x x
cwd x
exe x x x
uids x x x
gids x x x
terminal x x x
io_counters x x x
nice x x x x
num_fds x
num_ctx_switches x
num_threads x x x x
cpu_times x
memory_info x x x x
memory_info_ex x
memory_maps x
open_files x
send_signal x x x
suspend x x x
resume x x x
terminate x x x
kill x x x
username x
ionice
rlimit
num_handlres
threads
cpu_percent x x
cpu_affinity
memory_percent
parent x x
children x x x
connections x x
is_running
================ ===== ======= ====== =======
Original Metrics
^^^^^^^^^^^^^^^^^^^
================== ===== ======= ====== =======
item Linux FreeBSD MacOSX Windows
**HostInfo**
hostname x x x x
uptime x x x
proces x x
os x x x x
platform x x x
platformfamily x x x
virtualization x
**CPU**
VendorID x x x x
Family x x x x
Model x x x x
Stepping x x x x
PhysicalID x
CoreID x
Cores x x
ModelName x x x x
**LoadAvg**
Load1 x x x
Load5 x x x
Load15 x x x
**GetDockerID**
container id x no no no
**CgroupsCPU**
user x no no no
system x no no no
**CgroupsMem**
various x no no no
================== ===== ======= ====== =======
- future work
- process_iter
- wait_procs
- Process class
- as_dict
- wait
License
------------
New BSD License (same as psutil)
Related Works
-----------------------
I have been influenced by the following great works:
- psutil: http://pythonhosted.org/psutil/
- dstat: https://github.com/dagwieers/dstat
- gosigar: https://github.com/cloudfoundry/gosigar/
- goprocinfo: https://github.com/c9s/goprocinfo
- go-ps: https://github.com/mitchellh/go-ps
- ohai: https://github.com/opscode/ohai/
- bosun: https://github.com/bosun-monitor/bosun/tree/master/cmd/scollector/collectors
- mackerel: https://github.com/mackerelio/mackerel-agent/tree/master/metrics
How to Contribute
---------------------------
1. Fork it
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create new Pull Request
My English is terrible, so documentation or correcting comments are also
welcome.

11
vendor/github.com/shirou/gopsutil/circle.yml generated vendored Normal file
View File

@@ -0,0 +1,11 @@
machine:
timezone:
Asia/Tokyo
test:
override:
- GOOS=linux GOARCH=amd64 go test -v ./...
- GOOS=linux GOARCH=386 go get -v ./...
- GOOS=linux GOARCH=arm GOARM=7 go get -v ./...
- GOOS=freebsd GOARCH=amd64 go get -v ./...
- GOOS=windows GOARCH=amd64 go get -v ./...
- GOOS=darwin GOARCH=amd64 go get -v ./...

26
vendor/github.com/shirou/gopsutil/coverall.sh generated vendored Normal file
View File

@@ -0,0 +1,26 @@
#/bin/sh
# see http://www.songmu.jp/riji/entry/2015-01-15-goveralls-multi-package.html
set -e
# cleanup
cleanup() {
if [ $tmpprof != "" ] && [ -f $tmpprof ]; then
rm -f $tmpprof
fi
exit
}
trap cleanup INT QUIT TERM EXIT
# メインの処理
prof=${1:-".profile.cov"}
echo "mode: count" > $prof
gopath1=$(echo $GOPATH | cut -d: -f1)
for pkg in $(go list ./...); do
tmpprof=$gopath1/src/$pkg/profile.tmp
go test -covermode=count -coverprofile=$tmpprof $pkg
if [ -f $tmpprof ]; then
cat $tmpprof | tail -n +2 >> $prof
rm $tmpprof
fi
done

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

@@ -0,0 +1,93 @@
package cpu
import (
"encoding/json"
"runtime"
"strconv"
"strings"
"sync"
"github.com/shirou/gopsutil/internal/common"
)
type TimesStat struct {
CPU string `json:"cpu"`
User float64 `json:"user"`
System float64 `json:"system"`
Idle float64 `json:"idle"`
Nice float64 `json:"nice"`
Iowait float64 `json:"iowait"`
Irq float64 `json:"irq"`
Softirq float64 `json:"softirq"`
Steal float64 `json:"steal"`
Guest float64 `json:"guest"`
GuestNice float64 `json:"guestNice"`
Stolen float64 `json:"stolen"`
}
type InfoStat struct {
CPU int32 `json:"cpu"`
VendorID string `json:"vendorId"`
Family string `json:"family"`
Model string `json:"model"`
Stepping int32 `json:"stepping"`
PhysicalID string `json:"physicalId"`
CoreID string `json:"coreId"`
Cores int32 `json:"cores"`
ModelName string `json:"modelName"`
Mhz float64 `json:"mhz"`
CacheSize int32 `json:"cacheSize"`
Flags []string `json:"flags"`
}
type lastPercent struct {
sync.Mutex
lastCPUTimes []TimesStat
lastPerCPUTimes []TimesStat
}
var lastCPUPercent lastPercent
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
lastCPUPercent.Lock()
lastCPUPercent.lastCPUTimes, _ = Times(false)
lastCPUPercent.lastPerCPUTimes, _ = Times(true)
lastCPUPercent.Unlock()
}
func Counts(logical bool) (int, error) {
return runtime.NumCPU(), nil
}
func (c TimesStat) String() string {
v := []string{
`"cpu":"` + c.CPU + `"`,
`"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
`"system":` + strconv.FormatFloat(c.System, 'f', 1, 64),
`"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),
`"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),
`"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),
`"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),
`"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
`"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
`"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
`"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
`"stolen":` + strconv.FormatFloat(c.Stolen, 'f', 1, 64),
}
return `{` + strings.Join(v, ",") + `}`
}
// Total returns the total number of seconds in a CPUTimesStat
func (c TimesStat) Total() float64 {
total := c.User + c.System + c.Nice + c.Iowait + c.Irq + c.Softirq + c.Steal +
c.Guest + c.GuestNice + c.Idle + c.Stolen
return total
}
func (c InfoStat) String() string {
s, _ := json.Marshal(c)
return string(s)
}

106
vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,106 @@
// +build darwin
package cpu
import (
"os/exec"
"strconv"
"strings"
)
// sys/resource.h
const (
CPUser = 0
CPNice = 1
CPSys = 2
CPIntr = 3
CPIdle = 4
CPUStates = 5
)
// default value. from time.h
var ClocksPerSec = float64(128)
func Times(percpu bool) ([]TimesStat, error) {
if percpu {
return perCPUTimes()
}
return allCPUTimes()
}
// Returns only one CPUInfoStat on FreeBSD
func Info() ([]InfoStat, error) {
var ret []InfoStat
sysctl, err := exec.LookPath("/usr/sbin/sysctl")
if err != nil {
return ret, err
}
out, err := invoke.Command(sysctl, "machdep.cpu")
if err != nil {
return ret, err
}
c := InfoStat{}
for _, line := range strings.Split(string(out), "\n") {
values := strings.Fields(line)
if len(values) < 1 {
continue
}
t, err := strconv.ParseInt(values[1], 10, 64)
// err is not checked here because some value is string.
if strings.HasPrefix(line, "machdep.cpu.brand_string") {
c.ModelName = strings.Join(values[1:], " ")
} else if strings.HasPrefix(line, "machdep.cpu.family") {
c.Family = values[1]
} else if strings.HasPrefix(line, "machdep.cpu.model") {
c.Model = values[1]
} else if strings.HasPrefix(line, "machdep.cpu.stepping") {
if err != nil {
return ret, err
}
c.Stepping = int32(t)
} else if strings.HasPrefix(line, "machdep.cpu.features") {
for _, v := range values[1:] {
c.Flags = append(c.Flags, strings.ToLower(v))
}
} else if strings.HasPrefix(line, "machdep.cpu.leaf7_features") {
for _, v := range values[1:] {
c.Flags = append(c.Flags, strings.ToLower(v))
}
} else if strings.HasPrefix(line, "machdep.cpu.extfeatures") {
for _, v := range values[1:] {
c.Flags = append(c.Flags, strings.ToLower(v))
}
} else if strings.HasPrefix(line, "machdep.cpu.core_count") {
if err != nil {
return ret, err
}
c.Cores = int32(t)
} else if strings.HasPrefix(line, "machdep.cpu.cache.size") {
if err != nil {
return ret, err
}
c.CacheSize = int32(t)
} else if strings.HasPrefix(line, "machdep.cpu.vendor") {
c.VendorID = values[1]
}
}
// Use the rated frequency of the CPU. This is a static value and does not
// account for low power or Turbo Boost modes.
out, err = invoke.Command(sysctl, "hw.cpufrequency")
if err != nil {
return ret, err
}
values := strings.Fields(string(out))
mhz, err := strconv.ParseFloat(values[1], 64)
if err != nil {
return ret, err
}
c.Mhz = mhz / 1000000.0
return append(ret, c), nil
}

109
vendor/github.com/shirou/gopsutil/cpu/cpu_darwin_cgo.go generated vendored Normal file
View File

@@ -0,0 +1,109 @@
// +build darwin
// +build cgo
package cpu
/*
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#if TARGET_OS_MAC
#include <libproc.h>
#endif
#include <mach/processor_info.h>
#include <mach/vm_map.h>
*/
import "C"
import (
"bytes"
"encoding/binary"
"fmt"
"unsafe"
)
// these CPU times for darwin is borrowed from influxdb/telegraf.
func perCPUTimes() ([]TimesStat, error) {
var (
count C.mach_msg_type_number_t
cpuload *C.processor_cpu_load_info_data_t
ncpu C.natural_t
)
status := C.host_processor_info(C.host_t(C.mach_host_self()),
C.PROCESSOR_CPU_LOAD_INFO,
&ncpu,
(*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
&count)
if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_processor_info error=%d", status)
}
// jump through some cgo casting hoops and ensure we properly free
// the memory that cpuload points to
target := C.vm_map_t(C.mach_task_self_)
address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))
// the body of struct processor_cpu_load_info
// aka processor_cpu_load_info_data_t
var cpu_ticks [C.CPU_STATE_MAX]uint32
// copy the cpuload array to a []byte buffer
// where we can binary.Read the data
size := int(ncpu) * binary.Size(cpu_ticks)
buf := C.GoBytes(unsafe.Pointer(cpuload), C.int(size))
bbuf := bytes.NewBuffer(buf)
var ret []TimesStat
for i := 0; i < int(ncpu); i++ {
err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
if err != nil {
return nil, err
}
c := TimesStat{
CPU: fmt.Sprintf("cpu%d", i),
User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
Nice: float64(cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
Idle: float64(cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
}
ret = append(ret, c)
}
return ret, nil
}
func allCPUTimes() ([]TimesStat, error) {
var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
var cpuload C.host_cpu_load_info_data_t
status := C.host_statistics(C.host_t(C.mach_host_self()),
C.HOST_CPU_LOAD_INFO,
C.host_info_t(unsafe.Pointer(&cpuload)),
&count)
if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_statistics error=%d", status)
}
c := TimesStat{
CPU: "cpu-total",
User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
Nice: float64(cpuload.cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
}
return []TimesStat{c}, nil
}

View File

@@ -0,0 +1,14 @@
// +build darwin
// +build !cgo
package cpu
import "github.com/shirou/gopsutil/internal/common"
func perCPUTimes() ([]TimesStat, error) {
return []TimesStat{}, common.ErrNotImplementedError
}
func allCPUTimes() ([]TimesStat, error) {
return []TimesStat{}, common.ErrNotImplementedError
}

154
vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go generated vendored Normal file
View File

@@ -0,0 +1,154 @@
package cpu
import (
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
// sys/resource.h
const (
CPUser = 0
CPNice = 1
CPSys = 2
CPIntr = 3
CPIdle = 4
CPUStates = 5
)
var ClocksPerSec = float64(128)
func init() {
getconf, err := exec.LookPath("/usr/bin/getconf")
if err != nil {
return
}
out, err := invoke.Command(getconf, "CLK_TCK")
// ignore errors
if err == nil {
i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
if err == nil {
ClocksPerSec = float64(i)
}
}
}
func Times(percpu bool) ([]TimesStat, error) {
var ret []TimesStat
var sysctlCall string
var ncpu int
if percpu {
sysctlCall = "kern.cp_times"
ncpu, _ = Counts(true)
} else {
sysctlCall = "kern.cp_time"
ncpu = 1
}
cpuTimes, err := common.DoSysctrl(sysctlCall)
if err != nil {
return ret, 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
}
// 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) {
const dmesgBoot = "/var/run/dmesg.boot"
lines, _ := common.ReadLines(dmesgBoot)
c := InfoStat{}
var vals []string
var err error
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)
}
c.CPU = int32(c.Mhz)
if vals, err = common.DoSysctrl("hw.ncpu"); 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)
if vals, err = common.DoSysctrl("hw.model"); err != nil {
return nil, err
}
c.ModelName = strings.Join(vals, " ")
for _, line := range lines {
if matches := regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Family\s*=\s*(.+)\s+Model\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`).FindStringSubmatch(line); matches != nil {
c.VendorID = matches[1]
c.Family = matches[3]
c.Model = matches[4]
t, err := strconv.ParseInt(matches[5], 10, 32)
if err != nil {
return nil, fmt.Errorf("Unable to parse FreeBSD CPU stepping information from %q: %v", line, err)
}
c.Stepping = int32(t)
} else if matches := regexp.MustCompile(`Features=.+<(.+)>`).FindStringSubmatch(line); matches != nil {
for _, v := range strings.Split(matches[1], ",") {
c.Flags = append(c.Flags, strings.ToLower(v))
}
} else if matches := regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`).FindStringSubmatch(line); matches != nil {
for _, v := range strings.Split(matches[1], ",") {
c.Flags = append(c.Flags, strings.ToLower(v))
}
}
}
return []InfoStat{c}, nil
}

244
vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go generated vendored Normal file
View File

@@ -0,0 +1,244 @@
// +build linux
package cpu
import (
"errors"
"fmt"
"os/exec"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
var cpu_tick = float64(100)
func init() {
getconf, err := exec.LookPath("/usr/bin/getconf")
if err != nil {
return
}
out, err := invoke.Command(getconf, "CLK_TCK")
// ignore errors
if err == nil {
i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
if err == nil {
cpu_tick = float64(i)
}
}
}
func Times(percpu bool) ([]TimesStat, error) {
filename := common.HostProc("stat")
var lines = []string{}
if percpu {
var startIdx uint = 1
for {
linen, _ := common.ReadLinesOffsetN(filename, startIdx, 1)
line := linen[0]
if !strings.HasPrefix(line, "cpu") {
break
}
lines = append(lines, line)
startIdx++
}
} else {
lines, _ = common.ReadLinesOffsetN(filename, 0, 1)
}
ret := make([]TimesStat, 0, len(lines))
for _, line := range lines {
ct, err := parseStatLine(line)
if err != nil {
continue
}
ret = append(ret, *ct)
}
return ret, nil
}
func sysCPUPath(cpu int32, relPath string) string {
return common.HostSys(fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath)
}
func finishCPUInfo(c *InfoStat) error {
if c.Mhz == 0 {
lines, err := common.ReadLines(sysCPUPath(c.CPU, "cpufreq/cpuinfo_max_freq"))
if err == nil {
value, err := strconv.ParseFloat(lines[0], 64)
if err != nil {
return err
}
c.Mhz = value
}
}
if len(c.CoreID) == 0 {
lines, err := common.ReadLines(sysCPUPath(c.CPU, "topology/coreId"))
if err == nil {
c.CoreID = lines[0]
}
}
return nil
}
// CPUInfo on linux will return 1 item per physical thread.
//
// CPUs have three levels of counting: sockets, cores, threads.
// Cores with HyperThreading count as having 2 threads per core.
// Sockets often come with many physical CPU cores.
// 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) {
filename := common.HostProc("cpuinfo")
lines, _ := common.ReadLines(filename)
var ret []InfoStat
c := InfoStat{CPU: -1, Cores: 1}
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) < 2 {
continue
}
key := strings.TrimSpace(fields[0])
value := strings.TrimSpace(fields[1])
switch key {
case "processor":
if c.CPU >= 0 {
err := finishCPUInfo(&c)
if err != nil {
return ret, err
}
ret = append(ret, c)
}
c = InfoStat{Cores: 1}
t, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return ret, err
}
c.CPU = int32(t)
case "vendorId", "vendor_id":
c.VendorID = value
case "cpu family":
c.Family = value
case "model":
c.Model = value
case "model name":
c.ModelName = value
case "stepping":
t, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return ret, err
}
c.Stepping = int32(t)
case "cpu MHz":
t, err := strconv.ParseFloat(value, 64)
if err != nil {
return ret, err
}
c.Mhz = t
case "cache size":
t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64)
if err != nil {
return ret, err
}
c.CacheSize = int32(t)
case "physical id":
c.PhysicalID = value
case "core id":
c.CoreID = value
case "flags", "Features":
c.Flags = strings.FieldsFunc(value, func(r rune) bool {
return r == ',' || r == ' '
})
}
}
if c.CPU >= 0 {
err := finishCPUInfo(&c)
if err != nil {
return ret, err
}
ret = append(ret, c)
}
return ret, nil
}
func parseStatLine(line string) (*TimesStat, error) {
fields := strings.Fields(line)
if strings.HasPrefix(fields[0], "cpu") == false {
// return CPUTimesStat{}, e
return nil, errors.New("not contain cpu")
}
cpu := fields[0]
if cpu == "cpu" {
cpu = "cpu-total"
}
user, err := strconv.ParseFloat(fields[1], 64)
if err != nil {
return nil, err
}
nice, err := strconv.ParseFloat(fields[2], 64)
if err != nil {
return nil, err
}
system, err := strconv.ParseFloat(fields[3], 64)
if err != nil {
return nil, err
}
idle, err := strconv.ParseFloat(fields[4], 64)
if err != nil {
return nil, err
}
iowait, err := strconv.ParseFloat(fields[5], 64)
if err != nil {
return nil, err
}
irq, err := strconv.ParseFloat(fields[6], 64)
if err != nil {
return nil, err
}
softirq, err := strconv.ParseFloat(fields[7], 64)
if err != nil {
return nil, err
}
ct := &TimesStat{
CPU: cpu,
User: float64(user) / cpu_tick,
Nice: float64(nice) / cpu_tick,
System: float64(system) / cpu_tick,
Idle: float64(idle) / cpu_tick,
Iowait: float64(iowait) / cpu_tick,
Irq: float64(irq) / cpu_tick,
Softirq: float64(softirq) / cpu_tick,
}
if len(fields) > 8 { // Linux >= 2.6.11
steal, err := strconv.ParseFloat(fields[8], 64)
if err != nil {
return nil, err
}
ct.Steal = float64(steal) / cpu_tick
}
if len(fields) > 9 { // Linux >= 2.6.24
guest, err := strconv.ParseFloat(fields[9], 64)
if err != nil {
return nil, err
}
ct.Guest = float64(guest) / cpu_tick
}
if len(fields) > 10 { // Linux >= 3.2.0
guestNice, err := strconv.ParseFloat(fields[10], 64)
if err != nil {
return nil, err
}
ct.GuestNice = float64(guestNice) / cpu_tick
}
return ct, nil
}

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

90
vendor/github.com/shirou/gopsutil/cpu/cpu_unix.go generated vendored Normal file
View File

@@ -0,0 +1,90 @@
// +build linux freebsd darwin
package cpu
import (
"fmt"
"time"
)
func getAllBusy(t TimesStat) (float64, float64) {
busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen
return busy + t.Idle, busy
}
func calculateBusy(t1, t2 TimesStat) float64 {
t1All, t1Busy := getAllBusy(t1)
t2All, t2Busy := getAllBusy(t2)
if t2Busy <= t1Busy {
return 0
}
if t2All <= t1All {
return 1
}
return (t2Busy - t1Busy) / (t2All - t1All) * 100
}
func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
// Make sure the CPU measurements have the same length.
if len(t1) != len(t2) {
return nil, fmt.Errorf(
"received two CPU counts: %d != %d",
len(t1), len(t2),
)
}
ret := make([]float64, len(t1))
for i, t := range t2 {
ret[i] = calculateBusy(t1[i], t)
}
return ret, nil
}
//Percent calculates the percentage of cpu used either per CPU or combined.
//If an interval of 0 is given it will compare the current cpu times against the last call.
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
if interval <= 0 {
return percentUsedFromLastCall(percpu)
}
// Get CPU usage at the start of the interval.
cpuTimes1, err := Times(percpu)
if err != nil {
return nil, err
}
time.Sleep(interval)
// And at the end of the interval.
cpuTimes2, err := Times(percpu)
if err != nil {
return nil, err
}
return calculateAllBusy(cpuTimes1, cpuTimes2)
}
func percentUsedFromLastCall(percpu bool) ([]float64, error) {
cpuTimes, err := Times(percpu)
if err != nil {
return nil, err
}
lastCPUPercent.Lock()
defer lastCPUPercent.Unlock()
var lastTimes []TimesStat
if percpu {
lastTimes = lastCPUPercent.lastPerCPUTimes
lastCPUPercent.lastPerCPUTimes = cpuTimes
} else {
lastTimes = lastCPUPercent.lastCPUTimes
lastCPUPercent.lastCPUTimes = cpuTimes
}
if lastTimes == nil {
return nil, fmt.Errorf("Error getting times for cpu percent. LastTimes was nil")
}
return calculateAllBusy(lastTimes, cpuTimes)
}

105
vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go generated vendored Normal file
View File

@@ -0,0 +1,105 @@
// +build windows
package cpu
import (
"fmt"
"syscall"
"time"
"unsafe"
"github.com/StackExchange/wmi"
"github.com/shirou/gopsutil/internal/common"
)
type Win32_Processor struct {
LoadPercentage *uint16
Family uint16
Manufacturer string
Name string
NumberOfLogicalProcessors uint32
ProcessorID *string
Stepping *string
MaxClockSpeed uint32
}
// TODO: Get percpu
func Times(percpu bool) ([]TimesStat, error) {
var ret []TimesStat
var lpIdleTime common.FILETIME
var lpKernelTime common.FILETIME
var lpUserTime common.FILETIME
r, _, _ := common.ProcGetSystemTimes.Call(
uintptr(unsafe.Pointer(&lpIdleTime)),
uintptr(unsafe.Pointer(&lpKernelTime)),
uintptr(unsafe.Pointer(&lpUserTime)))
if r == 0 {
return ret, syscall.GetLastError()
}
LOT := float64(0.0000001)
HIT := (LOT * 4294967296.0)
idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime)))
user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime)))
kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))
system := (kernel - idle)
ret = append(ret, TimesStat{
Idle: float64(idle),
User: float64(user),
System: float64(system),
})
return ret, nil
}
func Info() ([]InfoStat, error) {
var ret []InfoStat
var dst []Win32_Processor
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
if err != nil {
return ret, err
}
var procID string
for i, l := range dst {
procID = ""
if l.ProcessorID != nil {
procID = *l.ProcessorID
}
cpu := InfoStat{
CPU: int32(i),
Family: fmt.Sprintf("%d", l.Family),
VendorID: l.Manufacturer,
ModelName: l.Name,
Cores: int32(l.NumberOfLogicalProcessors),
PhysicalID: procID,
Mhz: float64(l.MaxClockSpeed),
Flags: []string{},
}
ret = append(ret, cpu)
}
return ret, nil
}
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
var ret []float64
var dst []Win32_Processor
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
if err != nil {
return ret, err
}
for _, l := range dst {
// use range but windows can only get one percent.
if l.LoadPercentage == nil {
continue
}
ret = append(ret, float64(*l.LoadPercentage))
}
return ret, nil
}

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

@@ -0,0 +1,60 @@
package disk
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type UsageStat struct {
Path string `json:"path"`
Fstype string `json:"fstype"`
Total uint64 `json:"total"`
Free uint64 `json:"free"`
Used uint64 `json:"used"`
UsedPercent float64 `json:"usedPercent"`
InodesTotal uint64 `json:"inodesTotal"`
InodesUsed uint64 `json:"inodesUsed"`
InodesFree uint64 `json:"inodesFree"`
InodesUsedPercent float64 `json:"inodesUsedPercent"`
}
type PartitionStat struct {
Device string `json:"device"`
Mountpoint string `json:"mountpoint"`
Fstype string `json:"fstype"`
Opts string `json:"opts"`
}
type IOCountersStat struct {
ReadCount uint64 `json:"readCount"`
WriteCount uint64 `json:"writeCount"`
ReadBytes uint64 `json:"readBytes"`
WriteBytes uint64 `json:"writeBytes"`
ReadTime uint64 `json:"readTime"`
WriteTime uint64 `json:"writeTime"`
Name string `json:"name"`
IoTime uint64 `json:"ioTime"`
SerialNumber string `json:"serialNumber"`
}
func (d UsageStat) String() string {
s, _ := json.Marshal(d)
return string(s)
}
func (d PartitionStat) String() string {
s, _ := json.Marshal(d)
return string(s)
}
func (d IOCountersStat) String() string {
s, _ := json.Marshal(d)
return string(s)
}

111
vendor/github.com/shirou/gopsutil/disk/disk_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,111 @@
// +build darwin
package disk
import (
"path"
"syscall"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
)
func Partitions(all bool) ([]PartitionStat, error) {
var ret []PartitionStat
count, err := Getfsstat(nil, MntWait)
if err != nil {
return ret, err
}
fs := make([]Statfs_t, count)
_, err = Getfsstat(fs, MntWait)
for _, stat := range fs {
opts := "rw"
if stat.Flags&MntReadOnly != 0 {
opts = "ro"
}
if stat.Flags&MntSynchronous != 0 {
opts += ",sync"
}
if stat.Flags&MntNoExec != 0 {
opts += ",noexec"
}
if stat.Flags&MntNoSuid != 0 {
opts += ",nosuid"
}
if stat.Flags&MntUnion != 0 {
opts += ",union"
}
if stat.Flags&MntAsync != 0 {
opts += ",async"
}
if stat.Flags&MntSuidDir != 0 {
opts += ",suiddir"
}
if stat.Flags&MntSoftDep != 0 {
opts += ",softdep"
}
if stat.Flags&MntNoSymFollow != 0 {
opts += ",nosymfollow"
}
if stat.Flags&MntGEOMJournal != 0 {
opts += ",gjounalc"
}
if stat.Flags&MntMultilabel != 0 {
opts += ",multilabel"
}
if stat.Flags&MntACLs != 0 {
opts += ",acls"
}
if stat.Flags&MntNoATime != 0 {
opts += ",noattime"
}
if stat.Flags&MntClusterRead != 0 {
opts += ",nocluster"
}
if stat.Flags&MntClusterWrite != 0 {
opts += ",noclusterw"
}
if stat.Flags&MntNFS4ACLs != 0 {
opts += ",nfs4acls"
}
d := PartitionStat{
Device: common.IntToString(stat.Mntfromname[:]),
Mountpoint: common.IntToString(stat.Mntonname[:]),
Fstype: common.IntToString(stat.Fstypename[:]),
Opts: opts,
}
if all == false {
if !path.IsAbs(d.Device) || !common.PathExists(d.Device) {
continue
}
}
ret = append(ret, d)
}
return ret, nil
}
func IOCounters() (map[string]IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var _p0 unsafe.Pointer
var bufsize uintptr
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
}
r0, _, e1 := syscall.Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
n = int(r0)
if e1 != 0 {
err = e1
}
return
}
func getFsType(stat syscall.Statfs_t) string {
return common.IntToString(stat.Fstypename[:])
}

View File

@@ -0,0 +1,58 @@
// +build darwin
// +build amd64
package disk
const (
MntWait = 1
MfsNameLen = 15 /* length of fs type name, not inc. nul */
MNameLen = 90 /* length of buffer for returned name */
MFSTYPENAMELEN = 16 /* length of fs type name including null */
MAXPATHLEN = 1024
MNAMELEN = MAXPATHLEN
SYS_GETFSSTAT64 = 347
)
type Fsid struct{ val [2]int32 } /* file system id type */
type uid_t int32
// sys/mount.h
const (
MntReadOnly = 0x00000001 /* read only filesystem */
MntSynchronous = 0x00000002 /* filesystem written synchronously */
MntNoExec = 0x00000004 /* can't exec from filesystem */
MntNoSuid = 0x00000008 /* don't honor setuid bits on fs */
MntUnion = 0x00000020 /* union with underlying filesystem */
MntAsync = 0x00000040 /* filesystem written asynchronously */
MntSuidDir = 0x00100000 /* special handling of SUID on dirs */
MntSoftDep = 0x00200000 /* soft updates being done */
MntNoSymFollow = 0x00400000 /* do not follow symlinks */
MntGEOMJournal = 0x02000000 /* GEOM journal support enabled */
MntMultilabel = 0x04000000 /* MAC support for individual objects */
MntACLs = 0x08000000 /* ACL support enabled */
MntNoATime = 0x10000000 /* disable update of file access time */
MntClusterRead = 0x40000000 /* disable cluster read */
MntClusterWrite = 0x80000000 /* disable cluster write */
MntNFS4ACLs = 0x00000010
)
type Statfs_t struct {
Bsize uint32
Iosize int32
Blocks uint64
Bfree uint64
Bavail uint64
Files uint64
Ffree uint64
Fsid Fsid
Owner uint32
Type uint32
Flags uint32
Fssubtype uint32
Fstypename [16]int8
Mntonname [1024]int8
Mntfromname [1024]int8
Reserved [8]uint32
}

View File

@@ -0,0 +1,58 @@
// +build darwin
// +build arm64
package disk
const (
MntWait = 1
MfsNameLen = 15 /* length of fs type name, not inc. nul */
MNameLen = 90 /* length of buffer for returned name */
MFSTYPENAMELEN = 16 /* length of fs type name including null */
MAXPATHLEN = 1024
MNAMELEN = MAXPATHLEN
SYS_GETFSSTAT64 = 347
)
type Fsid struct{ val [2]int32 } /* file system id type */
type uid_t int32
// sys/mount.h
const (
MntReadOnly = 0x00000001 /* read only filesystem */
MntSynchronous = 0x00000002 /* filesystem written synchronously */
MntNoExec = 0x00000004 /* can't exec from filesystem */
MntNoSuid = 0x00000008 /* don't honor setuid bits on fs */
MntUnion = 0x00000020 /* union with underlying filesystem */
MntAsync = 0x00000040 /* filesystem written asynchronously */
MntSuidDir = 0x00100000 /* special handling of SUID on dirs */
MntSoftDep = 0x00200000 /* soft updates being done */
MntNoSymFollow = 0x00400000 /* do not follow symlinks */
MntGEOMJournal = 0x02000000 /* GEOM journal support enabled */
MntMultilabel = 0x04000000 /* MAC support for individual objects */
MntACLs = 0x08000000 /* ACL support enabled */
MntNoATime = 0x10000000 /* disable update of file access time */
MntClusterRead = 0x40000000 /* disable cluster read */
MntClusterWrite = 0x80000000 /* disable cluster write */
MntNFS4ACLs = 0x00000010
)
type Statfs_t struct {
Bsize uint32
Iosize int32
Blocks uint64
Bfree uint64
Bavail uint64
Files uint64
Ffree uint64
Fsid Fsid
Owner uint32
Type uint32
Flags uint32
Fssubtype uint32
Fstypename [16]int8
Mntonname [1024]int8
Mntfromname [1024]int8
Reserved [8]uint32
}

176
vendor/github.com/shirou/gopsutil/disk/disk_freebsd.go generated vendored Normal file
View File

@@ -0,0 +1,176 @@
// +build freebsd
package disk
import (
"bytes"
"encoding/binary"
"path"
"strconv"
"syscall"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
)
func Partitions(all bool) ([]PartitionStat, error) {
var ret []PartitionStat
// get length
count, err := syscall.Getfsstat(nil, MNT_WAIT)
if err != nil {
return ret, err
}
fs := make([]Statfs, count)
_, err = Getfsstat(fs, MNT_WAIT)
for _, stat := range fs {
opts := "rw"
if stat.Flags&MNT_RDONLY != 0 {
opts = "ro"
}
if stat.Flags&MNT_SYNCHRONOUS != 0 {
opts += ",sync"
}
if stat.Flags&MNT_NOEXEC != 0 {
opts += ",noexec"
}
if stat.Flags&MNT_NOSUID != 0 {
opts += ",nosuid"
}
if stat.Flags&MNT_UNION != 0 {
opts += ",union"
}
if stat.Flags&MNT_ASYNC != 0 {
opts += ",async"
}
if stat.Flags&MNT_SUIDDIR != 0 {
opts += ",suiddir"
}
if stat.Flags&MNT_SOFTDEP != 0 {
opts += ",softdep"
}
if stat.Flags&MNT_NOSYMFOLLOW != 0 {
opts += ",nosymfollow"
}
if stat.Flags&MNT_GJOURNAL != 0 {
opts += ",gjounalc"
}
if stat.Flags&MNT_MULTILABEL != 0 {
opts += ",multilabel"
}
if stat.Flags&MNT_ACLS != 0 {
opts += ",acls"
}
if stat.Flags&MNT_NOATIME != 0 {
opts += ",noattime"
}
if stat.Flags&MNT_NOCLUSTERR != 0 {
opts += ",nocluster"
}
if stat.Flags&MNT_NOCLUSTERW != 0 {
opts += ",noclusterw"
}
if stat.Flags&MNT_NFS4ACLS != 0 {
opts += ",nfs4acls"
}
d := PartitionStat{
Device: common.IntToString(stat.Mntfromname[:]),
Mountpoint: common.IntToString(stat.Mntonname[:]),
Fstype: common.IntToString(stat.Fstypename[:]),
Opts: opts,
}
if all == false {
if !path.IsAbs(d.Device) || !common.PathExists(d.Device) {
continue
}
}
ret = append(ret, d)
}
return ret, nil
}
func IOCounters() (map[string]IOCountersStat, error) {
// statinfo->devinfo->devstat
// /usr/include/devinfo.h
ret := make(map[string]IOCountersStat)
r, err := syscall.Sysctl("kern.devstat.all")
if err != nil {
return nil, err
}
buf := []byte(r)
length := len(buf)
count := int(uint64(length) / uint64(sizeOfDevstat))
buf = buf[8:] // devstat.all has version in the head.
// parse buf to Devstat
for i := 0; i < count; i++ {
b := buf[i*sizeOfDevstat : i*sizeOfDevstat+sizeOfDevstat]
d, err := parseDevstat(b)
if err != nil {
continue
}
un := strconv.Itoa(int(d.Unit_number))
name := common.IntToString(d.Device_name[:]) + un
ds := IOCountersStat{
ReadCount: d.Operations[DEVSTAT_READ],
WriteCount: d.Operations[DEVSTAT_WRITE],
ReadBytes: d.Bytes[DEVSTAT_READ],
WriteBytes: d.Bytes[DEVSTAT_WRITE],
ReadTime: uint64(d.Duration[DEVSTAT_READ].Compute() * 1000),
WriteTime: uint64(d.Duration[DEVSTAT_WRITE].Compute() * 1000),
IoTime: uint64(d.Busy_time.Compute() * 1000),
Name: name,
}
ret[name] = ds
}
return ret, nil
}
func (b Bintime) Compute() float64 {
BINTIME_SCALE := 5.42101086242752217003726400434970855712890625e-20
return float64(b.Sec) + float64(b.Frac)*BINTIME_SCALE
}
// BT2LD(time) ((long double)(time).sec + (time).frac * BINTIME_SCALE)
// 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) {
var _p0 unsafe.Pointer
var bufsize uintptr
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
bufsize = unsafe.Sizeof(Statfs{}) * uintptr(len(buf))
}
r0, _, e1 := syscall.Syscall(syscall.SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
n = int(r0)
if e1 != 0 {
err = e1
}
return
}
func parseDevstat(buf []byte) (Devstat, error) {
var ds Devstat
br := bytes.NewReader(buf)
// err := binary.Read(br, binary.LittleEndian, &ds)
err := common.Read(br, binary.LittleEndian, &ds)
if err != nil {
return ds, err
}
return ds, nil
}
func getFsType(stat syscall.Statfs_t) string {
return common.IntToString(stat.Fstypename[:])
}

View File

@@ -0,0 +1,112 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
package disk
const (
sizeofPtr = 0x4
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x4
sizeofLongLong = 0x8
sizeofLongDouble = 0x8
DEVSTAT_NO_DATA = 0x00
DEVSTAT_READ = 0x01
DEVSTAT_WRITE = 0x02
DEVSTAT_FREE = 0x03
MNT_RDONLY = 0x00000001
MNT_SYNCHRONOUS = 0x00000002
MNT_NOEXEC = 0x00000004
MNT_NOSUID = 0x00000008
MNT_UNION = 0x00000020
MNT_ASYNC = 0x00000040
MNT_SUIDDIR = 0x00100000
MNT_SOFTDEP = 0x00200000
MNT_NOSYMFOLLOW = 0x00400000
MNT_GJOURNAL = 0x02000000
MNT_MULTILABEL = 0x04000000
MNT_ACLS = 0x08000000
MNT_NOATIME = 0x10000000
MNT_NOCLUSTERR = 0x40000000
MNT_NOCLUSTERW = 0x80000000
MNT_NFS4ACLS = 0x00000010
MNT_WAIT = 1
MNT_NOWAIT = 2
MNT_LAZY = 3
MNT_SUSPEND = 4
)
const (
sizeOfDevstat = 0xf0
)
type (
_C_short int16
_C_int int32
_C_long int32
_C_long_long int64
_C_long_double int64
)
type Statfs struct {
Version uint32
Type uint32
Flags uint64
Bsize uint64
Iosize uint64
Blocks uint64
Bfree uint64
Bavail int64
Files uint64
Ffree int64
Syncwrites uint64
Asyncwrites uint64
Syncreads uint64
Asyncreads uint64
Spare [10]uint64
Namemax uint32
Owner uint32
Fsid Fsid
Charspare [80]int8
Fstypename [16]int8
Mntfromname [88]int8
Mntonname [88]int8
}
type Fsid struct {
Val [2]int32
}
type Devstat struct {
Sequence0 uint32
Allocated int32
Start_count uint32
End_count uint32
Busy_from Bintime
Dev_links _Ctype_struct___0
Device_number uint32
Device_name [16]int8
Unit_number int32
Bytes [4]uint64
Operations [4]uint64
Duration [4]Bintime
Busy_time Bintime
Creation_time Bintime
Block_size uint32
Tag_types [3]uint64
Flags uint32
Device_type uint32
Priority uint32
Id *byte
Sequence1 uint32
}
type Bintime struct {
Sec int32
Frac uint64
}
type _Ctype_struct___0 struct {
Empty uint32
}

View File

@@ -0,0 +1,115 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
package disk
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeofLongDouble = 0x8
DEVSTAT_NO_DATA = 0x00
DEVSTAT_READ = 0x01
DEVSTAT_WRITE = 0x02
DEVSTAT_FREE = 0x03
MNT_RDONLY = 0x00000001
MNT_SYNCHRONOUS = 0x00000002
MNT_NOEXEC = 0x00000004
MNT_NOSUID = 0x00000008
MNT_UNION = 0x00000020
MNT_ASYNC = 0x00000040
MNT_SUIDDIR = 0x00100000
MNT_SOFTDEP = 0x00200000
MNT_NOSYMFOLLOW = 0x00400000
MNT_GJOURNAL = 0x02000000
MNT_MULTILABEL = 0x04000000
MNT_ACLS = 0x08000000
MNT_NOATIME = 0x10000000
MNT_NOCLUSTERR = 0x40000000
MNT_NOCLUSTERW = 0x80000000
MNT_NFS4ACLS = 0x00000010
MNT_WAIT = 1
MNT_NOWAIT = 2
MNT_LAZY = 3
MNT_SUSPEND = 4
)
const (
sizeOfDevstat = 0x120
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
_C_long_double int64
)
type Statfs struct {
Version uint32
Type uint32
Flags uint64
Bsize uint64
Iosize uint64
Blocks uint64
Bfree uint64
Bavail int64
Files uint64
Ffree int64
Syncwrites uint64
Asyncwrites uint64
Syncreads uint64
Asyncreads uint64
Spare [10]uint64
Namemax uint32
Owner uint32
Fsid Fsid
Charspare [80]int8
Fstypename [16]int8
Mntfromname [88]int8
Mntonname [88]int8
}
type Fsid struct {
Val [2]int32
}
type Devstat struct {
Sequence0 uint32
Allocated int32
Start_count uint32
End_count uint32
Busy_from Bintime
Dev_links _Ctype_struct___0
Device_number uint32
Device_name [16]int8
Unit_number int32
Bytes [4]uint64
Operations [4]uint64
Duration [4]Bintime
Busy_time Bintime
Creation_time Bintime
Block_size uint32
Pad_cgo_0 [4]byte
Tag_types [3]uint64
Flags uint32
Device_type uint32
Priority uint32
Pad_cgo_1 [4]byte
ID *byte
Sequence1 uint32
Pad_cgo_2 [4]byte
}
type Bintime struct {
Sec int64
Frac uint64
}
type _Ctype_struct___0 struct {
Empty uint64
}

373
vendor/github.com/shirou/gopsutil/disk/disk_linux.go generated vendored Normal file
View File

@@ -0,0 +1,373 @@
// +build linux
package disk
import (
"fmt"
"os/exec"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
const (
SectorSize = 512
)
const (
// man statfs
ADFS_SUPER_MAGIC = 0xadf5
AFFS_SUPER_MAGIC = 0xADFF
BDEVFS_MAGIC = 0x62646576
BEFS_SUPER_MAGIC = 0x42465331
BFS_MAGIC = 0x1BADFACE
BINFMTFS_MAGIC = 0x42494e4d
BTRFS_SUPER_MAGIC = 0x9123683E
CGROUP_SUPER_MAGIC = 0x27e0eb
CIFS_MAGIC_NUMBER = 0xFF534D42
CODA_SUPER_MAGIC = 0x73757245
COH_SUPER_MAGIC = 0x012FF7B7
CRAMFS_MAGIC = 0x28cd3d45
DEBUGFS_MAGIC = 0x64626720
DEVFS_SUPER_MAGIC = 0x1373
DEVPTS_SUPER_MAGIC = 0x1cd1
EFIVARFS_MAGIC = 0xde5e81e4
EFS_SUPER_MAGIC = 0x00414A53
EXT_SUPER_MAGIC = 0x137D
EXT2_OLD_SUPER_MAGIC = 0xEF51
EXT2_SUPER_MAGIC = 0xEF53
EXT3_SUPER_MAGIC = 0xEF53
EXT4_SUPER_MAGIC = 0xEF53
FUSE_SUPER_MAGIC = 0x65735546
FUTEXFS_SUPER_MAGIC = 0xBAD1DEA
HFS_SUPER_MAGIC = 0x4244
HOSTFS_SUPER_MAGIC = 0x00c0ffee
HPFS_SUPER_MAGIC = 0xF995E849
HUGETLBFS_MAGIC = 0x958458f6
ISOFS_SUPER_MAGIC = 0x9660
JFFS2_SUPER_MAGIC = 0x72b6
JFS_SUPER_MAGIC = 0x3153464a
MINIX_SUPER_MAGIC = 0x137F /* orig. minix */
MINIX_SUPER_MAGIC2 = 0x138F /* 30 char minix */
MINIX2_SUPER_MAGIC = 0x2468 /* minix V2 */
MINIX2_SUPER_MAGIC2 = 0x2478 /* minix V2, 30 char names */
MINIX3_SUPER_MAGIC = 0x4d5a /* minix V3 fs, 60 char names */
MQUEUE_MAGIC = 0x19800202
MSDOS_SUPER_MAGIC = 0x4d44
NCP_SUPER_MAGIC = 0x564c
NFS_SUPER_MAGIC = 0x6969
NILFS_SUPER_MAGIC = 0x3434
NTFS_SB_MAGIC = 0x5346544e
OCFS2_SUPER_MAGIC = 0x7461636f
OPENPROM_SUPER_MAGIC = 0x9fa1
PIPEFS_MAGIC = 0x50495045
PROC_SUPER_MAGIC = 0x9fa0
PSTOREFS_MAGIC = 0x6165676C
QNX4_SUPER_MAGIC = 0x002f
QNX6_SUPER_MAGIC = 0x68191122
RAMFS_MAGIC = 0x858458f6
REISERFS_SUPER_MAGIC = 0x52654973
ROMFS_MAGIC = 0x7275
SELINUX_MAGIC = 0xf97cff8c
SMACK_MAGIC = 0x43415d53
SMB_SUPER_MAGIC = 0x517B
SOCKFS_MAGIC = 0x534F434B
SQUASHFS_MAGIC = 0x73717368
SYSFS_MAGIC = 0x62656572
SYSV2_SUPER_MAGIC = 0x012FF7B6
SYSV4_SUPER_MAGIC = 0x012FF7B5
TMPFS_MAGIC = 0x01021994
UDF_SUPER_MAGIC = 0x15013346
UFS_MAGIC = 0x00011954
USBDEVICE_SUPER_MAGIC = 0x9fa2
V9FS_MAGIC = 0x01021997
VXFS_SUPER_MAGIC = 0xa501FCF5
XENFS_SUPER_MAGIC = 0xabba1974
XENIX_SUPER_MAGIC = 0x012FF7B4
XFS_SUPER_MAGIC = 0x58465342
_XIAFS_SUPER_MAGIC = 0x012FD16D
AFS_SUPER_MAGIC = 0x5346414F
AUFS_SUPER_MAGIC = 0x61756673
ANON_INODE_FS_SUPER_MAGIC = 0x09041934
CEPH_SUPER_MAGIC = 0x00C36400
ECRYPTFS_SUPER_MAGIC = 0xF15F
FAT_SUPER_MAGIC = 0x4006
FHGFS_SUPER_MAGIC = 0x19830326
FUSEBLK_SUPER_MAGIC = 0x65735546
FUSECTL_SUPER_MAGIC = 0x65735543
GFS_SUPER_MAGIC = 0x1161970
GPFS_SUPER_MAGIC = 0x47504653
MTD_INODE_FS_SUPER_MAGIC = 0x11307854
INOTIFYFS_SUPER_MAGIC = 0x2BAD1DEA
ISOFS_R_WIN_SUPER_MAGIC = 0x4004
ISOFS_WIN_SUPER_MAGIC = 0x4000
JFFS_SUPER_MAGIC = 0x07C0
KAFS_SUPER_MAGIC = 0x6B414653
LUSTRE_SUPER_MAGIC = 0x0BD00BD0
NFSD_SUPER_MAGIC = 0x6E667364
PANFS_SUPER_MAGIC = 0xAAD7AAEA
RPC_PIPEFS_SUPER_MAGIC = 0x67596969
SECURITYFS_SUPER_MAGIC = 0x73636673
UFS_BYTESWAPPED_SUPER_MAGIC = 0x54190100
VMHGFS_SUPER_MAGIC = 0xBACBACBC
VZFS_SUPER_MAGIC = 0x565A4653
ZFS_SUPER_MAGIC = 0x2FC12FC1
)
// coreutils/src/stat.c
var fsTypeMap = map[int64]string{
ADFS_SUPER_MAGIC: "adfs", /* 0xADF5 local */
AFFS_SUPER_MAGIC: "affs", /* 0xADFF local */
AFS_SUPER_MAGIC: "afs", /* 0x5346414F remote */
ANON_INODE_FS_SUPER_MAGIC: "anon-inode FS", /* 0x09041934 local */
AUFS_SUPER_MAGIC: "aufs", /* 0x61756673 remote */
// AUTOFS_SUPER_MAGIC: "autofs", /* 0x0187 local */
BEFS_SUPER_MAGIC: "befs", /* 0x42465331 local */
BDEVFS_MAGIC: "bdevfs", /* 0x62646576 local */
BFS_MAGIC: "bfs", /* 0x1BADFACE local */
BINFMTFS_MAGIC: "binfmt_misc", /* 0x42494E4D local */
BTRFS_SUPER_MAGIC: "btrfs", /* 0x9123683E local */
CEPH_SUPER_MAGIC: "ceph", /* 0x00C36400 remote */
CGROUP_SUPER_MAGIC: "cgroupfs", /* 0x0027E0EB local */
CIFS_MAGIC_NUMBER: "cifs", /* 0xFF534D42 remote */
CODA_SUPER_MAGIC: "coda", /* 0x73757245 remote */
COH_SUPER_MAGIC: "coh", /* 0x012FF7B7 local */
CRAMFS_MAGIC: "cramfs", /* 0x28CD3D45 local */
DEBUGFS_MAGIC: "debugfs", /* 0x64626720 local */
DEVFS_SUPER_MAGIC: "devfs", /* 0x1373 local */
DEVPTS_SUPER_MAGIC: "devpts", /* 0x1CD1 local */
ECRYPTFS_SUPER_MAGIC: "ecryptfs", /* 0xF15F local */
EFS_SUPER_MAGIC: "efs", /* 0x00414A53 local */
EXT_SUPER_MAGIC: "ext", /* 0x137D local */
EXT2_SUPER_MAGIC: "ext2/ext3", /* 0xEF53 local */
EXT2_OLD_SUPER_MAGIC: "ext2", /* 0xEF51 local */
FAT_SUPER_MAGIC: "fat", /* 0x4006 local */
FHGFS_SUPER_MAGIC: "fhgfs", /* 0x19830326 remote */
FUSEBLK_SUPER_MAGIC: "fuseblk", /* 0x65735546 remote */
FUSECTL_SUPER_MAGIC: "fusectl", /* 0x65735543 remote */
FUTEXFS_SUPER_MAGIC: "futexfs", /* 0x0BAD1DEA local */
GFS_SUPER_MAGIC: "gfs/gfs2", /* 0x1161970 remote */
GPFS_SUPER_MAGIC: "gpfs", /* 0x47504653 remote */
HFS_SUPER_MAGIC: "hfs", /* 0x4244 local */
HPFS_SUPER_MAGIC: "hpfs", /* 0xF995E849 local */
HUGETLBFS_MAGIC: "hugetlbfs", /* 0x958458F6 local */
MTD_INODE_FS_SUPER_MAGIC: "inodefs", /* 0x11307854 local */
INOTIFYFS_SUPER_MAGIC: "inotifyfs", /* 0x2BAD1DEA local */
ISOFS_SUPER_MAGIC: "isofs", /* 0x9660 local */
ISOFS_R_WIN_SUPER_MAGIC: "isofs", /* 0x4004 local */
ISOFS_WIN_SUPER_MAGIC: "isofs", /* 0x4000 local */
JFFS_SUPER_MAGIC: "jffs", /* 0x07C0 local */
JFFS2_SUPER_MAGIC: "jffs2", /* 0x72B6 local */
JFS_SUPER_MAGIC: "jfs", /* 0x3153464A local */
KAFS_SUPER_MAGIC: "k-afs", /* 0x6B414653 remote */
LUSTRE_SUPER_MAGIC: "lustre", /* 0x0BD00BD0 remote */
MINIX_SUPER_MAGIC: "minix", /* 0x137F local */
MINIX_SUPER_MAGIC2: "minix (30 char.)", /* 0x138F local */
MINIX2_SUPER_MAGIC: "minix v2", /* 0x2468 local */
MINIX2_SUPER_MAGIC2: "minix v2 (30 char.)", /* 0x2478 local */
MINIX3_SUPER_MAGIC: "minix3", /* 0x4D5A local */
MQUEUE_MAGIC: "mqueue", /* 0x19800202 local */
MSDOS_SUPER_MAGIC: "msdos", /* 0x4D44 local */
NCP_SUPER_MAGIC: "novell", /* 0x564C remote */
NFS_SUPER_MAGIC: "nfs", /* 0x6969 remote */
NFSD_SUPER_MAGIC: "nfsd", /* 0x6E667364 remote */
NILFS_SUPER_MAGIC: "nilfs", /* 0x3434 local */
NTFS_SB_MAGIC: "ntfs", /* 0x5346544E local */
OPENPROM_SUPER_MAGIC: "openprom", /* 0x9FA1 local */
OCFS2_SUPER_MAGIC: "ocfs2", /* 0x7461636f remote */
PANFS_SUPER_MAGIC: "panfs", /* 0xAAD7AAEA remote */
PIPEFS_MAGIC: "pipefs", /* 0x50495045 remote */
PROC_SUPER_MAGIC: "proc", /* 0x9FA0 local */
PSTOREFS_MAGIC: "pstorefs", /* 0x6165676C local */
QNX4_SUPER_MAGIC: "qnx4", /* 0x002F local */
QNX6_SUPER_MAGIC: "qnx6", /* 0x68191122 local */
RAMFS_MAGIC: "ramfs", /* 0x858458F6 local */
REISERFS_SUPER_MAGIC: "reiserfs", /* 0x52654973 local */
ROMFS_MAGIC: "romfs", /* 0x7275 local */
RPC_PIPEFS_SUPER_MAGIC: "rpc_pipefs", /* 0x67596969 local */
SECURITYFS_SUPER_MAGIC: "securityfs", /* 0x73636673 local */
SELINUX_MAGIC: "selinux", /* 0xF97CFF8C local */
SMB_SUPER_MAGIC: "smb", /* 0x517B remote */
SOCKFS_MAGIC: "sockfs", /* 0x534F434B local */
SQUASHFS_MAGIC: "squashfs", /* 0x73717368 local */
SYSFS_MAGIC: "sysfs", /* 0x62656572 local */
SYSV2_SUPER_MAGIC: "sysv2", /* 0x012FF7B6 local */
SYSV4_SUPER_MAGIC: "sysv4", /* 0x012FF7B5 local */
TMPFS_MAGIC: "tmpfs", /* 0x01021994 local */
UDF_SUPER_MAGIC: "udf", /* 0x15013346 local */
UFS_MAGIC: "ufs", /* 0x00011954 local */
UFS_BYTESWAPPED_SUPER_MAGIC: "ufs", /* 0x54190100 local */
USBDEVICE_SUPER_MAGIC: "usbdevfs", /* 0x9FA2 local */
V9FS_MAGIC: "v9fs", /* 0x01021997 local */
VMHGFS_SUPER_MAGIC: "vmhgfs", /* 0xBACBACBC remote */
VXFS_SUPER_MAGIC: "vxfs", /* 0xA501FCF5 local */
VZFS_SUPER_MAGIC: "vzfs", /* 0x565A4653 local */
XENFS_SUPER_MAGIC: "xenfs", /* 0xABBA1974 local */
XENIX_SUPER_MAGIC: "xenix", /* 0x012FF7B4 local */
XFS_SUPER_MAGIC: "xfs", /* 0x58465342 local */
_XIAFS_SUPER_MAGIC: "xia", /* 0x012FD16D local */
ZFS_SUPER_MAGIC: "zfs", /* 0x2FC12FC1 local */
}
// Partitions returns disk partitions. If all is false, returns
// physical devices only (e.g. hard disks, cd-rom drives, USB keys)
// and ignore all others (e.g. memory partitions such as /dev/shm)
//
// should use setmntent(3) but this implement use /etc/mtab file
func Partitions(all bool) ([]PartitionStat, error) {
filename := common.HostEtc("mtab")
lines, err := common.ReadLines(filename)
if err != nil {
return nil, err
}
fs, err := getFileSystems()
if err != nil {
return nil, err
}
ret := make([]PartitionStat, 0, len(lines))
for _, line := range lines {
fields := strings.Fields(line)
d := PartitionStat{
Device: fields[0],
Mountpoint: fields[1],
Fstype: fields[2],
Opts: fields[3],
}
if all == false {
if d.Device == "none" || !common.StringsHas(fs, d.Fstype) {
continue
}
}
ret = append(ret, d)
}
return ret, nil
}
// getFileSystems returns supported filesystems from /proc/filesystems
func getFileSystems() ([]string, error) {
filename := common.HostProc("filesystems")
lines, err := common.ReadLines(filename)
if err != nil {
return nil, err
}
var ret []string
for _, line := range lines {
if !strings.HasPrefix(line, "nodev") {
ret = append(ret, strings.TrimSpace(line))
continue
}
t := strings.Split(line, "\t")
if len(t) != 2 || t[1] != "zfs" {
continue
}
ret = append(ret, strings.TrimSpace(t[1]))
}
return ret, nil
}
func IOCounters() (map[string]IOCountersStat, error) {
filename := common.HostProc("diskstats")
lines, err := common.ReadLines(filename)
if err != nil {
return nil, err
}
ret := make(map[string]IOCountersStat, 0)
empty := IOCountersStat{}
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) < 14 {
// malformed line in /proc/diskstats, avoid panic by ignoring.
continue
}
name := fields[2]
reads, err := strconv.ParseUint((fields[3]), 10, 64)
if err != nil {
return ret, err
}
rbytes, err := strconv.ParseUint((fields[5]), 10, 64)
if err != nil {
return ret, err
}
rtime, err := strconv.ParseUint((fields[6]), 10, 64)
if err != nil {
return ret, err
}
writes, err := strconv.ParseUint((fields[7]), 10, 64)
if err != nil {
return ret, err
}
wbytes, err := strconv.ParseUint((fields[9]), 10, 64)
if err != nil {
return ret, err
}
wtime, err := strconv.ParseUint((fields[10]), 10, 64)
if err != nil {
return ret, err
}
iotime, err := strconv.ParseUint((fields[12]), 10, 64)
if err != nil {
return ret, err
}
d := IOCountersStat{
ReadBytes: rbytes * SectorSize,
WriteBytes: wbytes * SectorSize,
ReadCount: reads,
WriteCount: writes,
ReadTime: rtime,
WriteTime: wtime,
IoTime: iotime,
}
if d == empty {
continue
}
d.Name = name
d.SerialNumber = GetDiskSerialNumber(name)
ret[name] = d
}
return ret, nil
}
// 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 {
n := fmt.Sprintf("--name=%s", name)
udevadm, err := exec.LookPath("/sbin/udevadm")
if err != nil {
return ""
}
out, err := invoke.Command(udevadm, "info", "--query=property", n)
// does not return error, just an empty string
if err != nil {
return ""
}
lines := strings.Split(string(out), "\n")
for _, line := range lines {
values := strings.Split(line, "=")
if len(values) < 2 || values[0] != "ID_SERIAL" {
// only get ID_SERIAL, not ID_SERIAL_SHORT
continue
}
return values[1]
}
return ""
}
func getFsType(stat syscall.Statfs_t) string {
t := int64(stat.Type)
ret, ok := fsTypeMap[t]
if !ok {
return ""
}
return ret
}

100
vendor/github.com/shirou/gopsutil/disk/disk_test.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
package disk
import (
"fmt"
"runtime"
"testing"
)
func TestDisk_usage(t *testing.T) {
path := "/"
if runtime.GOOS == "windows" {
path = "C:"
}
v, err := Usage(path)
if err != nil {
t.Errorf("error %v", err)
}
if v.Path != path {
t.Errorf("error %v", err)
}
}
func TestDisk_partitions(t *testing.T) {
ret, err := Partitions(false)
if err != nil || len(ret) == 0 {
t.Errorf("error %v", err)
}
empty := PartitionStat{}
if len(ret) == 0 {
t.Errorf("ret is empty")
}
for _, disk := range ret {
if disk == empty {
t.Errorf("Could not get device info %v", disk)
}
}
}
func TestDisk_io_counters(t *testing.T) {
ret, err := IOCounters()
if err != nil {
t.Errorf("error %v", err)
}
if len(ret) == 0 {
t.Errorf("ret is empty")
}
empty := IOCountersStat{}
for part, io := range ret {
if io == empty {
t.Errorf("io_counter error %v, %v", part, io)
}
}
}
func TestDiskUsageStat_String(t *testing.T) {
v := UsageStat{
Path: "/",
Total: 1000,
Free: 2000,
Used: 3000,
UsedPercent: 50.1,
InodesTotal: 4000,
InodesUsed: 5000,
InodesFree: 6000,
InodesUsedPercent: 49.1,
Fstype: "ext4",
}
e := `{"path":"/","fstype":"ext4","total":1000,"free":2000,"used":3000,"usedPercent":50.1,"inodesTotal":4000,"inodesUsed":5000,"inodesFree":6000,"inodesUsedPercent":49.1}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("DiskUsageStat string is invalid: %v", v)
}
}
func TestDiskPartitionStat_String(t *testing.T) {
v := PartitionStat{
Device: "sd01",
Mountpoint: "/",
Fstype: "ext4",
Opts: "ro",
}
e := `{"device":"sd01","mountpoint":"/","fstype":"ext4","opts":"ro"}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("DiskUsageStat string is invalid: %v", v)
}
}
func TestDiskIOCountersStat_String(t *testing.T) {
v := IOCountersStat{
Name: "sd01",
ReadCount: 100,
WriteCount: 200,
ReadBytes: 300,
WriteBytes: 400,
SerialNumber: "SERIAL",
}
e := `{"readCount":100,"writeCount":200,"readBytes":300,"writeBytes":400,"readTime":0,"writeTime":0,"name":"sd01","ioTime":0,"serialNumber":"SERIAL"}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("DiskUsageStat string is invalid: %v", v)
}
}

30
vendor/github.com/shirou/gopsutil/disk/disk_unix.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// +build freebsd linux darwin
package disk
import "syscall"
func Usage(path string) (*UsageStat, error) {
stat := syscall.Statfs_t{}
err := syscall.Statfs(path, &stat)
if err != nil {
return nil, err
}
bsize := stat.Bsize
ret := &UsageStat{
Path: path,
Fstype: getFsType(stat),
Total: (uint64(stat.Blocks) * uint64(bsize)),
Free: (uint64(stat.Bavail) * uint64(bsize)),
InodesTotal: (uint64(stat.Files)),
InodesFree: (uint64(stat.Ffree)),
}
ret.InodesUsed = (ret.InodesTotal - ret.InodesFree)
ret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0
ret.Used = (uint64(stat.Blocks) - uint64(stat.Bfree)) * uint64(bsize)
ret.UsedPercent = (float64(ret.Used) / float64(ret.Total)) * 100.0
return ret, nil
}

155
vendor/github.com/shirou/gopsutil/disk/disk_windows.go generated vendored Normal file
View File

@@ -0,0 +1,155 @@
// +build windows
package disk
import (
"bytes"
"syscall"
"unsafe"
"github.com/StackExchange/wmi"
"github.com/shirou/gopsutil/internal/common"
)
var (
procGetDiskFreeSpaceExW = common.Modkernel32.NewProc("GetDiskFreeSpaceExW")
procGetLogicalDriveStringsW = common.Modkernel32.NewProc("GetLogicalDriveStringsW")
procGetDriveType = common.Modkernel32.NewProc("GetDriveTypeW")
provGetVolumeInformation = common.Modkernel32.NewProc("GetVolumeInformationW")
)
var (
FileFileCompression = int64(16) // 0x00000010
FileReadOnlyVolume = int64(524288) // 0x00080000
)
type Win32_PerfFormattedData struct {
Name string
AvgDiskBytesPerRead uint64
AvgDiskBytesPerWrite uint64
AvgDiskReadQueueLength uint64
AvgDiskWriteQueueLength uint64
AvgDisksecPerRead uint64
AvgDisksecPerWrite uint64
}
const WaitMSec = 500
func Usage(path string) (*UsageStat, error) {
ret := &UsageStat{}
lpFreeBytesAvailable := int64(0)
lpTotalNumberOfBytes := int64(0)
lpTotalNumberOfFreeBytes := int64(0)
diskret, _, err := procGetDiskFreeSpaceExW.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
if diskret == 0 {
return nil, err
}
ret = &UsageStat{
Path: path,
Total: uint64(lpTotalNumberOfBytes),
Free: uint64(lpTotalNumberOfFreeBytes),
Used: uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
UsedPercent: (float64(lpTotalNumberOfBytes) - float64(lpTotalNumberOfFreeBytes)) / float64(lpTotalNumberOfBytes) * 100,
// InodesTotal: 0,
// InodesFree: 0,
// InodesUsed: 0,
// InodesUsedPercent: 0,
}
return ret, nil
}
func Partitions(all bool) ([]PartitionStat, error) {
var ret []PartitionStat
lpBuffer := make([]byte, 254)
diskret, _, err := procGetLogicalDriveStringsW.Call(
uintptr(len(lpBuffer)),
uintptr(unsafe.Pointer(&lpBuffer[0])))
if diskret == 0 {
return ret, err
}
for _, v := range lpBuffer {
if v >= 65 && v <= 90 {
path := string(v) + ":"
if path == "A:" || path == "B:" { // skip floppy drives
continue
}
typepath, _ := syscall.UTF16PtrFromString(path)
typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath)))
if typeret == 0 {
return ret, syscall.GetLastError()
}
// 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 5: DRIVE_CDROM
if typeret == 2 || typeret == 3 || typeret == 5 {
lpVolumeNameBuffer := make([]byte, 256)
lpVolumeSerialNumber := int64(0)
lpMaximumComponentLength := int64(0)
lpFileSystemFlags := int64(0)
lpFileSystemNameBuffer := make([]byte, 256)
volpath, _ := syscall.UTF16PtrFromString(string(v) + ":/")
driveret, _, err := provGetVolumeInformation.Call(
uintptr(unsafe.Pointer(volpath)),
uintptr(unsafe.Pointer(&lpVolumeNameBuffer[0])),
uintptr(len(lpVolumeNameBuffer)),
uintptr(unsafe.Pointer(&lpVolumeSerialNumber)),
uintptr(unsafe.Pointer(&lpMaximumComponentLength)),
uintptr(unsafe.Pointer(&lpFileSystemFlags)),
uintptr(unsafe.Pointer(&lpFileSystemNameBuffer[0])),
uintptr(len(lpFileSystemNameBuffer)))
if driveret == 0 {
if typeret == 5 {
continue //device is not ready will happen if there is no disk in the drive
}
return ret, err
}
opts := "rw"
if lpFileSystemFlags&FileReadOnlyVolume != 0 {
opts = "ro"
}
if lpFileSystemFlags&FileFileCompression != 0 {
opts += ".compress"
}
d := PartitionStat{
Mountpoint: path,
Device: path,
Fstype: string(bytes.Replace(lpFileSystemNameBuffer, []byte("\x00"), []byte(""), -1)),
Opts: opts,
}
ret = append(ret, d)
}
}
}
return ret, nil
}
func IOCounters() (map[string]IOCountersStat, error) {
ret := make(map[string]IOCountersStat, 0)
var dst []Win32_PerfFormattedData
err := wmi.Query("SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk ", &dst)
if err != nil {
return ret, err
}
for _, d := range dst {
if len(d.Name) > 3 { // not get _Total or Harddrive
continue
}
ret[d.Name] = IOCountersStat{
Name: d.Name,
ReadCount: uint64(d.AvgDiskReadQueueLength),
WriteCount: d.AvgDiskWriteQueueLength,
ReadBytes: uint64(d.AvgDiskBytesPerRead),
WriteBytes: uint64(d.AvgDiskBytesPerWrite),
ReadTime: d.AvgDisksecPerRead,
WriteTime: d.AvgDisksecPerWrite,
}
}
return ret, nil
}

View File

@@ -0,0 +1,88 @@
// +build ignore
// Hand writing: _Ctype_struct___0
/*
Input to cgo -godefs.
*/
package disk
/*
#include <sys/types.h>
#include <sys/mount.h>
#include <devstat.h>
enum {
sizeofPtr = sizeof(void*),
};
// because statinfo has long double snap_time, redefine with changing long long
struct statinfo2 {
long cp_time[CPUSTATES];
long tk_nin;
long tk_nout;
struct devinfo *dinfo;
long long snap_time;
};
*/
import "C"
// Machine characteristics; for internal use.
const (
sizeofPtr = C.sizeofPtr
sizeofShort = C.sizeof_short
sizeofInt = C.sizeof_int
sizeofLong = C.sizeof_long
sizeofLongLong = C.sizeof_longlong
sizeofLongDouble = C.sizeof_longlong
DEVSTAT_NO_DATA = 0x00
DEVSTAT_READ = 0x01
DEVSTAT_WRITE = 0x02
DEVSTAT_FREE = 0x03
// from sys/mount.h
MNT_RDONLY = 0x00000001 /* read only filesystem */
MNT_SYNCHRONOUS = 0x00000002 /* filesystem written synchronously */
MNT_NOEXEC = 0x00000004 /* can't exec from filesystem */
MNT_NOSUID = 0x00000008 /* don't honor setuid bits on fs */
MNT_UNION = 0x00000020 /* union with underlying filesystem */
MNT_ASYNC = 0x00000040 /* filesystem written asynchronously */
MNT_SUIDDIR = 0x00100000 /* special handling of SUID on dirs */
MNT_SOFTDEP = 0x00200000 /* soft updates being done */
MNT_NOSYMFOLLOW = 0x00400000 /* do not follow symlinks */
MNT_GJOURNAL = 0x02000000 /* GEOM journal support enabled */
MNT_MULTILABEL = 0x04000000 /* MAC support for individual objects */
MNT_ACLS = 0x08000000 /* ACL support enabled */
MNT_NOATIME = 0x10000000 /* disable update of file access time */
MNT_NOCLUSTERR = 0x40000000 /* disable cluster read */
MNT_NOCLUSTERW = 0x80000000 /* disable cluster write */
MNT_NFS4ACLS = 0x00000010
MNT_WAIT = 1 /* synchronously wait for I/O to complete */
MNT_NOWAIT = 2 /* start all I/O, but do not wait for it */
MNT_LAZY = 3 /* push data not written by filesystem syncer */
MNT_SUSPEND = 4 /* Suspend file system after sync */
)
const (
sizeOfDevstat = C.sizeof_struct_devstat
)
// Basic types
type (
_C_short C.short
_C_int C.int
_C_long C.long
_C_long_long C.longlong
_C_long_double C.longlong
)
type Statfs C.struct_statfs
type Fsid C.struct_fsid
type Devstat C.struct_devstat
type Bintime C.struct_bintime

1
vendor/github.com/shirou/gopsutil/doc.go generated vendored Normal file
View File

@@ -0,0 +1 @@
package gopsutil

59
vendor/github.com/shirou/gopsutil/docker/docker.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
package docker
import (
"errors"
"github.com/shirou/gopsutil/internal/common"
)
var ErrDockerNotAvailable = errors.New("docker not available")
var ErrCgroupNotAvailable = errors.New("cgroup not available")
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type CgroupMemStat struct {
ContainerID string `json:"containerID"`
Cache uint64 `json:"cache"`
RSS uint64 `json:"rss"`
RSSHuge uint64 `json:"rssHuge"`
MappedFile uint64 `json:"mappedFile"`
Pgpgin uint64 `json:"pgpgin"`
Pgpgout uint64 `json:"pgpgout"`
Pgfault uint64 `json:"pgfault"`
Pgmajfault uint64 `json:"pgmajfault"`
InactiveAnon uint64 `json:"inactiveAnon"`
ActiveAnon uint64 `json:"activeAnon"`
InactiveFile uint64 `json:"inactiveFile"`
ActiveFile uint64 `json:"activeFile"`
Unevictable uint64 `json:"unevictable"`
HierarchicalMemoryLimit uint64 `json:"hierarchicalMemoryLimit"`
TotalCache uint64 `json:"totalCache"`
TotalRSS uint64 `json:"totalRss"`
TotalRSSHuge uint64 `json:"totalRssHuge"`
TotalMappedFile uint64 `json:"totalMappedFile"`
TotalPgpgIn uint64 `json:"totalPgpgin"`
TotalPgpgOut uint64 `json:"totalPgpgout"`
TotalPgFault uint64 `json:"totalPgfault"`
TotalPgMajFault uint64 `json:"totalPgmajfault"`
TotalInactiveAnon uint64 `json:"totalInactiveAnon"`
TotalActiveAnon uint64 `json:"totalActiveAnon"`
TotalInactiveFile uint64 `json:"totalInactiveFile"`
TotalActiveFile uint64 `json:"totalActiveFile"`
TotalUnevictable uint64 `json:"totalUnevictable"`
MemUsageInBytes uint64 `json:"memUsageInBytes"`
MemMaxUsageInBytes uint64 `json:"memMaxUsageInBytes"`
MemLimitInBytes uint64 `json:"memoryLimitInBbytes"`
MemFailCnt uint64 `json:"memoryFailcnt"`
}
type CgroupDockerStat struct {
ContainerID string `json:"containerID"`
Name string `json:"name"`
Image string `json:"image"`
Status string `json:"status"`
Running bool `json:"running"`
}

View File

@@ -0,0 +1,254 @@
// +build linux
package docker
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path"
"strconv"
"strings"
cpu "github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/internal/common"
)
// GetDockerStat returns a list of Docker basic stats.
// This requires certain permission.
func GetDockerStat() ([]CgroupDockerStat, error) {
path, err := exec.LookPath("docker")
if err != nil {
return nil, ErrDockerNotAvailable
}
out, err := invoke.Command(path, "ps", "-a", "--no-trunc", "--format", "{{.ID}}|{{.Image}}|{{.Names}}|{{.Status}}")
if err != nil {
return []CgroupDockerStat{}, err
}
lines := strings.Split(string(out), "\n")
ret := make([]CgroupDockerStat, 0, len(lines))
for _, l := range lines {
if l == "" {
continue
}
cols := strings.Split(l, "|")
if len(cols) != 4 {
continue
}
names := strings.Split(cols[2], ",")
stat := CgroupDockerStat{
ContainerID: cols[0],
Name: names[0],
Image: cols[1],
Status: cols[3],
Running: strings.Contains(cols[3], "Up"),
}
ret = append(ret, stat)
}
return ret, nil
}
func (c CgroupDockerStat) String() string {
s, _ := json.Marshal(c)
return string(s)
}
// GetDockerIDList returnes a list of DockerID.
// This requires certain permission.
func GetDockerIDList() ([]string, error) {
path, err := exec.LookPath("docker")
if err != nil {
return nil, ErrDockerNotAvailable
}
out, err := invoke.Command(path, "ps", "-q", "--no-trunc")
if err != nil {
return []string{}, err
}
lines := strings.Split(string(out), "\n")
ret := make([]string, 0, len(lines))
for _, l := range lines {
if l == "" {
continue
}
ret = append(ret, l)
}
return ret, nil
}
// CgroupCPU returnes specified cgroup id CPU status.
// containerID is same as docker id if you use docker.
// If you use container via systemd.slice, you could use
// containerID = docker-<container id>.scope and base=/sys/fs/cgroup/cpuacct/system.slice/
func CgroupCPU(containerID string, base string) (*cpu.TimesStat, error) {
statfile := getCgroupFilePath(containerID, base, "cpuacct", "cpuacct.stat")
lines, err := common.ReadLines(statfile)
if err != nil {
return nil, err
}
// empty containerID means all cgroup
if len(containerID) == 0 {
containerID = "all"
}
ret := &cpu.TimesStat{CPU: containerID}
for _, line := range lines {
fields := strings.Split(line, " ")
if fields[0] == "user" {
user, err := strconv.ParseFloat(fields[1], 64)
if err == nil {
ret.User = float64(user)
}
}
if fields[0] == "system" {
system, err := strconv.ParseFloat(fields[1], 64)
if err == nil {
ret.System = float64(system)
}
}
}
return ret, nil
}
func CgroupCPUDocker(containerid string) (*cpu.TimesStat, error) {
return CgroupCPU(containerid, common.HostSys("fs/cgroup/cpuacct/docker"))
}
func CgroupMem(containerID string, base string) (*CgroupMemStat, error) {
statfile := getCgroupFilePath(containerID, base, "memory", "memory.stat")
// empty containerID means all cgroup
if len(containerID) == 0 {
containerID = "all"
}
lines, err := common.ReadLines(statfile)
if err != nil {
return nil, err
}
ret := &CgroupMemStat{ContainerID: containerID}
for _, line := range lines {
fields := strings.Split(line, " ")
v, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
continue
}
switch fields[0] {
case "cache":
ret.Cache = v
case "rss":
ret.RSS = v
case "rssHuge":
ret.RSSHuge = v
case "mappedFile":
ret.MappedFile = v
case "pgpgin":
ret.Pgpgin = v
case "pgpgout":
ret.Pgpgout = v
case "pgfault":
ret.Pgfault = v
case "pgmajfault":
ret.Pgmajfault = v
case "inactiveAnon":
ret.InactiveAnon = v
case "activeAnon":
ret.ActiveAnon = v
case "inactiveFile":
ret.InactiveFile = v
case "activeFile":
ret.ActiveFile = v
case "unevictable":
ret.Unevictable = v
case "hierarchicalMemoryLimit":
ret.HierarchicalMemoryLimit = v
case "totalCache":
ret.TotalCache = v
case "totalRss":
ret.TotalRSS = v
case "totalRssHuge":
ret.TotalRSSHuge = v
case "totalMappedFile":
ret.TotalMappedFile = v
case "totalPgpgin":
ret.TotalPgpgIn = v
case "totalPgpgout":
ret.TotalPgpgOut = v
case "totalPgfault":
ret.TotalPgFault = v
case "totalPgmajfault":
ret.TotalPgMajFault = v
case "totalInactiveAnon":
ret.TotalInactiveAnon = v
case "totalActiveAnon":
ret.TotalActiveAnon = v
case "totalInactiveFile":
ret.TotalInactiveFile = v
case "totalActiveFile":
ret.TotalActiveFile = v
case "totalUnevictable":
ret.TotalUnevictable = v
}
}
r, err := getCgroupMemFile(containerID, base, "memory.usage_in_bytes")
if err == nil {
ret.MemUsageInBytes = r
}
r, err = getCgroupMemFile(containerID, base, "memory.max_usage_in_bytes")
if err == nil {
ret.MemMaxUsageInBytes = r
}
r, err = getCgroupMemFile(containerID, base, "memoryLimitInBbytes")
if err == nil {
ret.MemLimitInBytes = r
}
r, err = getCgroupMemFile(containerID, base, "memoryFailcnt")
if err == nil {
ret.MemFailCnt = r
}
return ret, nil
}
func CgroupMemDocker(containerID string) (*CgroupMemStat, error) {
return CgroupMem(containerID, common.HostSys("fs/cgroup/memory/docker"))
}
func (m CgroupMemStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
// getCgroupFilePath constructs file path to get targetted stats file.
func getCgroupFilePath(containerID, base, target, file string) string {
if len(base) == 0 {
base = common.HostSys(fmt.Sprintf("fs/cgroup/%s/docker", target))
}
statfile := path.Join(base, containerID, file)
if _, err := os.Stat(statfile); os.IsNotExist(err) {
statfile = path.Join(
common.HostSys(fmt.Sprintf("fs/cgroup/%s/system.slice", target)), "docker-"+containerID+".scope", file)
}
return statfile
}
// getCgroupMemFile reads a cgroup file and return the contents as uint64.
func getCgroupMemFile(containerID, base, file string) (uint64, error) {
statfile := getCgroupFilePath(containerID, base, "memory", file)
lines, err := common.ReadLines(statfile)
if err != nil {
return 0, err
}
if len(lines) != 1 {
return 0, fmt.Errorf("wrong format file: %s", statfile)
}
return strconv.ParseUint(lines[0], 10, 64)
}

View File

@@ -0,0 +1,82 @@
// +build linux
package docker
import "testing"
func TestGetDockerIDList(t *testing.T) {
// If there is not docker environment, this test always fail.
// not tested here
/*
_, err := GetDockerIDList()
if err != nil {
t.Errorf("error %v", err)
}
*/
}
func TestGetDockerStat(t *testing.T) {
// If there is not docker environment, this test always fail.
// not tested here
/*
ret, err := GetDockerStat()
if err != nil {
t.Errorf("error %v", err)
}
if len(ret) == 0 {
t.Errorf("ret is empty")
}
empty := CgroupDockerStat{}
for _, v := range ret {
if empty == v {
t.Errorf("empty CgroupDockerStat")
}
if v.ContainerID == "" {
t.Errorf("Could not get container id")
}
}
*/
}
func TestCgroupCPU(t *testing.T) {
v, _ := GetDockerIDList()
for _, id := range v {
v, err := CgroupCPUDocker(id)
if err != nil {
t.Errorf("error %v", err)
}
if v.CPU == "" {
t.Errorf("could not get CgroupCPU %v", v)
}
}
}
func TestCgroupCPUInvalidId(t *testing.T) {
_, err := CgroupCPUDocker("bad id")
if err == nil {
t.Error("Expected path does not exist error")
}
}
func TestCgroupMem(t *testing.T) {
v, _ := GetDockerIDList()
for _, id := range v {
v, err := CgroupMemDocker(id)
if err != nil {
t.Errorf("error %v", err)
}
empty := &CgroupMemStat{}
if v == empty {
t.Errorf("Could not CgroupMemStat %v", v)
}
}
}
func TestCgroupMemInvalidId(t *testing.T) {
_, err := CgroupMemDocker("bad id")
if err == nil {
t.Error("Expected path does not exist error")
}
}

View File

@@ -0,0 +1,47 @@
// +build !linux
package docker
import (
"encoding/json"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/internal/common"
)
// GetDockerStat returns a list of Docker basic stats.
// This requires certain permission.
func GetDockerStat() ([]CgroupDockerStat, error) {
return nil, ErrDockerNotAvailable
}
// GetDockerIDList returnes a list of DockerID.
// This requires certain permission.
func GetDockerIDList() ([]string, error) {
return nil, ErrDockerNotAvailable
}
// CgroupCPU returnes specified cgroup id CPU status.
// containerid is same as docker id if you use docker.
// If you use container via systemd.slice, you could use
// containerid = docker-<container id>.scope and base=/sys/fs/cgroup/cpuacct/system.slice/
func CgroupCPU(containerid string, base string) (*cpu.TimesStat, error) {
return nil, ErrCgroupNotAvailable
}
func CgroupCPUDocker(containerid string) (*cpu.TimesStat, error) {
return CgroupCPU(containerid, common.HostSys("fs/cgroup/cpuacct/docker"))
}
func CgroupMem(containerid string, base string) (*CgroupMemStat, error) {
return nil, ErrCgroupNotAvailable
}
func CgroupMemDocker(containerid string) (*CgroupMemStat, error) {
return CgroupMem(containerid, common.HostSys("fs/cgroup/memory/docker"))
}
func (m CgroupMemStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}

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

@@ -0,0 +1,46 @@
package host
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
// A HostInfoStat describes the host status.
// This is not in the psutil but it useful.
type InfoStat struct {
Hostname string `json:"hostname"`
Uptime uint64 `json:"uptime"`
BootTime uint64 `json:"bootTime"`
Procs uint64 `json:"procs"` // number of processes
OS string `json:"os"` // ex: freebsd, linux
Platform string `json:"platform"` // ex: ubuntu, linuxmint
PlatformFamily string `json:"platformFamily"` // ex: debian, rhel
PlatformVersion string `json:"platformVersion"`
VirtualizationSystem string `json:"virtualizationSystem"`
VirtualizationRole string `json:"virtualizationRole"` // guest or host
HostID string `json:"hostid"` // ex: uuid
}
type UserStat struct {
User string `json:"user"`
Terminal string `json:"terminal"`
Host string `json:"host"`
Started int `json:"started"`
}
func (h InfoStat) String() string {
s, _ := json.Marshal(h)
return string(s)
}
func (u UserStat) String() string {
s, _ := json.Marshal(u)
return string(s)
}

164
vendor/github.com/shirou/gopsutil/host/host_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,164 @@
// +build darwin
package host
import (
"bytes"
"encoding/binary"
"io/ioutil"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"time"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/process"
)
// from utmpx.h
const USER_PROCESS = 7
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
PlatformFamily: "darwin",
}
hostname, err := os.Hostname()
if err == nil {
ret.Hostname = hostname
}
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
}
boot, err := BootTime()
if err == nil {
ret.BootTime = boot
ret.Uptime = uptime(boot)
}
procs, err := process.Pids()
if err == nil {
ret.Procs = uint64(len(procs))
}
values, err := common.DoSysctrl("kern.uuid")
if err == nil && len(values) == 1 && values[0] != "" {
ret.HostID = values[0]
}
return ret, nil
}
func BootTime() (uint64, error) {
values, err := common.DoSysctrl("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.ParseInt(v, 10, 64)
if err != nil {
return 0, err
}
return uint64(boottime), nil
}
func uptime(boot uint64) uint64 {
return uint64(time.Now().Unix()) - boot
}
func Uptime() (uint64, error) {
boot, err := BootTime()
if err != nil {
return 0, err
}
return uptime(boot), nil
}
func Users() ([]UserStat, error) {
utmpfile := "/var/run/utmpx"
var ret []UserStat
file, err := os.Open(utmpfile)
if err != nil {
return ret, err
}
buf, err := ioutil.ReadAll(file)
if err != nil {
return ret, err
}
u := Utmpx{}
entrySize := int(unsafe.Sizeof(u))
count := len(buf) / entrySize
for i := 0; i < count; i++ {
b := buf[i*entrySize : i*entrySize+entrySize]
var u Utmpx
br := bytes.NewReader(b)
err := binary.Read(br, binary.LittleEndian, &u)
if err != nil {
continue
}
if u.Type != USER_PROCESS {
continue
}
user := UserStat{
User: common.IntToString(u.User[:]),
Terminal: common.IntToString(u.Line[:]),
Host: common.IntToString(u.Host[:]),
Started: int(u.Tv.Sec),
}
ret = append(ret, user)
}
return ret, nil
}
func PlatformInformation() (string, string, string, error) {
platform := ""
family := ""
version := ""
uname, err := exec.LookPath("uname")
if err != nil {
return "", "", "", err
}
out, err := invoke.Command(uname, "-s")
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = invoke.Command(uname, "-r")
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}
return platform, family, version, nil
}
func Virtualization() (string, string, error) {
system := ""
role := ""
return system, role, nil
}

View File

@@ -0,0 +1,19 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_darwin.go
package host
type Utmpx struct {
User [256]int8
ID [4]int8
Line [32]int8
Pid int32
Type int16
Pad_cgo_0 [6]byte
Tv Timeval
Host [256]int8
Pad [16]uint32
}
type Timeval struct {
Sec int32
}

206
vendor/github.com/shirou/gopsutil/host/host_freebsd.go generated vendored Normal file
View File

@@ -0,0 +1,206 @@
// +build freebsd
package host
import (
"bytes"
"encoding/binary"
"io/ioutil"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"time"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/process"
)
const (
UTNameSize = 16 /* see MAXLOGNAME in <sys/param.h> */
UTLineSize = 8
UTHostSize = 16
)
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
PlatformFamily: "freebsd",
}
hostname, err := os.Hostname()
if err == nil {
ret.Hostname = hostname
}
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
}
boot, err := BootTime()
if err == nil {
ret.BootTime = boot
ret.Uptime = uptime(boot)
}
procs, err := process.Pids()
if err == nil {
ret.Procs = uint64(len(procs))
}
values, err := common.DoSysctrl("kern.hostuuid")
if err == nil && len(values) == 1 && values[0] != "" {
ret.HostID = values[0]
}
return ret, nil
}
func BootTime() (uint64, error) {
values, err := common.DoSysctrl("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
}
return boottime, nil
}
func uptime(boot uint64) uint64 {
return uint64(time.Now().Unix()) - boot
}
func Uptime() (uint64, error) {
boot, err := BootTime()
if err != nil {
return 0, err
}
return uptime(boot), nil
}
func Users() ([]UserStat, error) {
utmpfile := "/var/run/utx.active"
if !common.PathExists(utmpfile) {
utmpfile = "/var/run/utmp" // before 9.0
return getUsersFromUtmp(utmpfile)
}
var ret []UserStat
file, err := os.Open(utmpfile)
if err != nil {
return ret, err
}
buf, err := ioutil.ReadAll(file)
if err != nil {
return ret, err
}
entrySize := sizeOfUtmpx
count := len(buf) / entrySize
for i := 0; i < count; i++ {
b := buf[i*sizeOfUtmpx : (i+1)*sizeOfUtmpx]
var u Utmpx
br := bytes.NewReader(b)
err := binary.Read(br, binary.LittleEndian, &u)
if err != nil || u.Type != 4 {
continue
}
sec := (binary.LittleEndian.Uint32(u.Tv.Sec[:])) / 2 // TODO:
user := UserStat{
User: common.IntToString(u.User[:]),
Terminal: common.IntToString(u.Line[:]),
Host: common.IntToString(u.Host[:]),
Started: int(sec),
}
ret = append(ret, user)
}
return ret, nil
}
func PlatformInformation() (string, string, string, error) {
platform := ""
family := ""
version := ""
uname, err := exec.LookPath("uname")
if err != nil {
return "", "", "", err
}
out, err := invoke.Command(uname, "-s")
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = invoke.Command(uname, "-r")
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}
return platform, family, version, nil
}
func Virtualization() (string, string, error) {
system := ""
role := ""
return system, role, nil
}
// before 9.0
func getUsersFromUtmp(utmpfile string) ([]UserStat, error) {
var ret []UserStat
file, err := os.Open(utmpfile)
if err != nil {
return ret, err
}
buf, err := ioutil.ReadAll(file)
if err != nil {
return ret, err
}
u := Utmp{}
entrySize := int(unsafe.Sizeof(u))
count := len(buf) / entrySize
for i := 0; i < count; i++ {
b := buf[i*entrySize : i*entrySize+entrySize]
var u Utmp
br := bytes.NewReader(b)
err := binary.Read(br, binary.LittleEndian, &u)
if err != nil || u.Time == 0 {
continue
}
user := UserStat{
User: common.IntToString(u.Name[:]),
Terminal: common.IntToString(u.Line[:]),
Host: common.IntToString(u.Host[:]),
Started: int(u.Time),
}
ret = append(ret, user)
}
return ret, nil
}

View File

@@ -0,0 +1,43 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
package host
const (
sizeofPtr = 0x4
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x4
sizeofLongLong = 0x8
sizeOfUtmpx = 197 // TODO why should 197
)
type (
_C_short int16
_C_int int32
_C_long int32
_C_long_long int64
)
type Utmp struct {
Line [8]int8
Name [16]int8
Host [16]int8
Time int32
}
type Utmpx struct {
Type int16
Tv Timeval
Id [8]int8
Pid int32
User [32]int8
Line [16]int8
Host [125]int8
// X__ut_spare [64]int8
}
type Timeval struct {
Sec [4]byte
Usec [3]byte
}

View File

@@ -0,0 +1,44 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
package host
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmpx = 197 // TODO: why should 197, not 0x118
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type Utmp struct {
Line [8]int8
Name [16]int8
Host [16]int8
Time int32
}
type Utmpx struct {
Type int16
Tv Timeval
Id [8]int8
Pid int32
User [32]int8
Line [16]int8
Host [125]int8
// Host [128]int8
// X__ut_spare [64]int8
}
type Timeval struct {
Sec [4]byte
Usec [3]byte
}

498
vendor/github.com/shirou/gopsutil/host/host_linux.go generated vendored Normal file
View File

@@ -0,0 +1,498 @@
// +build linux
package host
import (
"bytes"
"encoding/binary"
"fmt"
"io/ioutil"
"os"
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
"time"
"github.com/shirou/gopsutil/internal/common"
)
type LSB struct {
ID string
Release string
Codename string
Description string
}
// from utmp.h
const USER_PROCESS = 7
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
}
hostname, err := os.Hostname()
if err == nil {
ret.Hostname = hostname
}
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
}
boot, err := BootTime()
if err == nil {
ret.BootTime = boot
ret.Uptime = uptime(boot)
}
if numProcs, err := common.NumProcs(); err == nil {
ret.Procs = numProcs
}
sysProductUUID := common.HostSys("class/dmi/id/product_uuid")
switch {
case common.PathExists(sysProductUUID):
lines, err := common.ReadLines(sysProductUUID)
if err == nil && len(lines) > 0 && lines[0] != "" {
ret.HostID = lines[0]
break
}
fallthrough
default:
values, err := common.DoSysctrl("kernel.random.boot_id")
if err == nil && len(values) == 1 && values[0] != "" {
ret.HostID = values[0]
}
}
return ret, nil
}
// BootTime returns the system boot time expressed in seconds since the epoch.
func BootTime() (uint64, error) {
filename := common.HostProc("stat")
lines, err := common.ReadLines(filename)
if err != nil {
return 0, err
}
for _, line := range lines {
if strings.HasPrefix(line, "btime") {
f := strings.Fields(line)
if len(f) != 2 {
return 0, fmt.Errorf("wrong btime format")
}
b, err := strconv.ParseInt(f[1], 10, 64)
if err != nil {
return 0, err
}
return uint64(b), nil
}
}
return 0, fmt.Errorf("could not find btime")
}
func uptime(boot uint64) uint64 {
return uint64(time.Now().Unix()) - boot
}
func Uptime() (uint64, error) {
boot, err := BootTime()
if err != nil {
return 0, err
}
return uptime(boot), nil
}
func Users() ([]UserStat, error) {
utmpfile := "/var/run/utmp"
file, err := os.Open(utmpfile)
if err != nil {
return nil, err
}
buf, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
count := len(buf) / sizeOfUtmp
ret := make([]UserStat, 0, count)
for i := 0; i < count; i++ {
b := buf[i*sizeOfUtmp : (i+1)*sizeOfUtmp]
var u utmp
br := bytes.NewReader(b)
err := binary.Read(br, binary.LittleEndian, &u)
if err != nil {
continue
}
if u.Type != USER_PROCESS {
continue
}
user := UserStat{
User: common.IntToString(u.User[:]),
Terminal: common.IntToString(u.Line[:]),
Host: common.IntToString(u.Host[:]),
Started: int(u.Tv.Sec),
}
ret = append(ret, user)
}
return ret, nil
}
func getOSRelease() (platform string, version string, err error) {
contents, err := common.ReadLines(common.HostEtc("os-release"))
if err != nil {
return "", "", nil // return empty
}
for _, line := range contents {
field := strings.Split(line, "=")
if len(field) < 2 {
continue
}
switch field[0] {
case "ID": // use ID for lowercase
platform = field[1]
case "VERSION":
version = field[1]
}
}
return platform, version, nil
}
func getLSB() (*LSB, error) {
ret := &LSB{}
if common.PathExists(common.HostEtc("lsb-release")) {
contents, err := common.ReadLines(common.HostEtc("lsb-release"))
if err != nil {
return ret, err // return empty
}
for _, line := range contents {
field := strings.Split(line, "=")
if len(field) < 2 {
continue
}
switch field[0] {
case "DISTRIB_ID":
ret.ID = field[1]
case "DISTRIB_RELEASE":
ret.Release = field[1]
case "DISTRIB_CODENAME":
ret.Codename = field[1]
case "DISTRIB_DESCRIPTION":
ret.Description = field[1]
}
}
} else if common.PathExists("/usr/bin/lsb_release") {
lsb_release, err := exec.LookPath("/usr/bin/lsb_release")
if err != nil {
return ret, err
}
out, err := invoke.Command(lsb_release)
if err != nil {
return ret, err
}
for _, line := range strings.Split(string(out), "\n") {
field := strings.Split(line, ":")
if len(field) < 2 {
continue
}
switch field[0] {
case "Distributor ID":
ret.ID = field[1]
case "Release":
ret.Release = field[1]
case "Codename":
ret.Codename = field[1]
case "Description":
ret.Description = field[1]
}
}
}
return ret, nil
}
func PlatformInformation() (platform string, family string, version string, err error) {
lsb, err := getLSB()
if err != nil {
lsb = &LSB{}
}
if common.PathExists(common.HostEtc("oracle-release")) {
platform = "oracle"
contents, err := common.ReadLines(common.HostEtc("oracle-release"))
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists(common.HostEtc("enterprise-release")) {
platform = "oracle"
contents, err := common.ReadLines(common.HostEtc("enterprise-release"))
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists(common.HostEtc("debian_version")) {
if lsb.ID == "Ubuntu" {
platform = "ubuntu"
version = lsb.Release
} else if lsb.ID == "LinuxMint" {
platform = "linuxmint"
version = lsb.Release
} else {
if common.PathExists("/usr/bin/raspi-config") {
platform = "raspbian"
} else {
platform = "debian"
}
contents, err := common.ReadLines(common.HostEtc("debian_version"))
if err == nil {
version = contents[0]
}
}
} else if common.PathExists(common.HostEtc("redhat-release")) {
contents, err := common.ReadLines(common.HostEtc("redhat-release"))
if err == nil {
version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents)
}
} else if common.PathExists(common.HostEtc("system-release")) {
contents, err := common.ReadLines(common.HostEtc("system-release"))
if err == nil {
version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents)
}
} else if common.PathExists(common.HostEtc("gentoo-release")) {
platform = "gentoo"
contents, err := common.ReadLines(common.HostEtc("gentoo-release"))
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists(common.HostEtc("SuSE-release")) {
contents, err := common.ReadLines(common.HostEtc("SuSE-release"))
if err == nil {
version = getSuseVersion(contents)
platform = getSusePlatform(contents)
}
// TODO: slackware detecion
} else if common.PathExists(common.HostEtc("arch-release")) {
platform = "arch"
version = lsb.Release
} else if common.PathExists(common.HostEtc("alpine-release")) {
platform = "alpine"
contents, err := common.ReadLines(common.HostEtc("alpine-release"))
if err == nil && len(contents) > 0 {
version = contents[0]
}
} else if common.PathExists(common.HostEtc("os-release")) {
p, v, err := getOSRelease()
if err == nil {
platform = p
version = v
}
} else if lsb.ID == "RedHat" {
platform = "redhat"
version = lsb.Release
} else if lsb.ID == "Amazon" {
platform = "amazon"
version = lsb.Release
} else if lsb.ID == "ScientificSL" {
platform = "scientific"
version = lsb.Release
} else if lsb.ID == "XenServer" {
platform = "xenserver"
version = lsb.Release
} else if lsb.ID != "" {
platform = strings.ToLower(lsb.ID)
version = lsb.Release
}
switch platform {
case "debian", "ubuntu", "linuxmint", "raspbian":
family = "debian"
case "fedora":
family = "fedora"
case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm":
family = "rhel"
case "suse", "opensuse":
family = "suse"
case "gentoo":
family = "gentoo"
case "slackware":
family = "slackware"
case "arch":
family = "arch"
case "exherbo":
family = "exherbo"
case "alpine":
family = "alpine"
case "coreos":
family = "coreos"
}
return platform, family, version, nil
}
func getRedhatishVersion(contents []string) string {
c := strings.ToLower(strings.Join(contents, ""))
if strings.Contains(c, "rawhide") {
return "rawhide"
}
if matches := regexp.MustCompile(`release (\d[\d.]*)`).FindStringSubmatch(c); matches != nil {
return matches[1]
}
return ""
}
func getRedhatishPlatform(contents []string) string {
c := strings.ToLower(strings.Join(contents, ""))
if strings.Contains(c, "red hat") {
return "redhat"
}
f := strings.Split(c, " ")
return f[0]
}
func getSuseVersion(contents []string) string {
version := ""
for _, line := range contents {
if matches := regexp.MustCompile(`VERSION = ([\d.]+)`).FindStringSubmatch(line); matches != nil {
version = matches[1]
} else if matches := regexp.MustCompile(`PATCHLEVEL = ([\d]+)`).FindStringSubmatch(line); matches != nil {
version = version + "." + matches[1]
}
}
return version
}
func getSusePlatform(contents []string) string {
c := strings.ToLower(strings.Join(contents, ""))
if strings.Contains(c, "opensuse") {
return "opensuse"
}
return "suse"
}
func Virtualization() (string, string, error) {
var system string
var role string
filename := common.HostProc("xen")
if common.PathExists(filename) {
system = "xen"
role = "guest" // assume guest
if common.PathExists(filename + "/capabilities") {
contents, err := common.ReadLines(filename + "/capabilities")
if err == nil {
if common.StringsContains(contents, "control_d") {
role = "host"
}
}
}
}
filename = common.HostProc("modules")
if common.PathExists(filename) {
contents, err := common.ReadLines(filename)
if err == nil {
if common.StringsContains(contents, "kvm") {
system = "kvm"
role = "host"
} else if common.StringsContains(contents, "vboxdrv") {
system = "vbox"
role = "host"
} else if common.StringsContains(contents, "vboxguest") {
system = "vbox"
role = "guest"
}
}
}
filename = common.HostProc("cpuinfo")
if common.PathExists(filename) {
contents, err := common.ReadLines(filename)
if err == nil {
if common.StringsContains(contents, "QEMU Virtual CPU") ||
common.StringsContains(contents, "Common KVM processor") ||
common.StringsContains(contents, "Common 32-bit KVM processor") {
system = "kvm"
role = "guest"
}
}
}
filename = common.HostProc()
if common.PathExists(filename + "/bc/0") {
system = "openvz"
role = "host"
} else if common.PathExists(filename + "/vz") {
system = "openvz"
role = "guest"
}
// not use dmidecode because it requires root
if common.PathExists(filename + "/self/status") {
contents, err := common.ReadLines(filename + "/self/status")
if err == nil {
if common.StringsContains(contents, "s_context:") ||
common.StringsContains(contents, "VxID:") {
system = "linux-vserver"
}
// TODO: guest or host
}
}
if common.PathExists(filename + "/self/cgroup") {
contents, err := common.ReadLines(filename + "/self/cgroup")
if err == nil {
if common.StringsContains(contents, "lxc") {
system = "lxc"
role = "guest"
} else if common.StringsContains(contents, "docker") {
system = "docker"
role = "guest"
} else if common.StringsContains(contents, "machine-rkt") {
system = "rkt"
role = "guest"
} else if common.PathExists("/usr/bin/lxc-version") {
system = "lxc"
role = "host"
}
}
}
if common.PathExists(common.HostEtc("os-release")) {
p, _, err := getOSRelease()
if err == nil && p == "coreos" {
system = "rkt" // Is it true?
role = "host"
}
}
return system, role, nil
}

View File

@@ -0,0 +1,45 @@
// ATTENTION - FILE MANUAL FIXED AFTER CGO.
// Fixed line: Tv _Ctype_struct_timeval -> Tv UtTv
// Created by cgo -godefs, MANUAL FIXED
// 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 UtTv
Addr_v6 [4]int32
X__unused [20]int8
}
type exit_status struct {
Termination int16
Exit int16
}
type UtTv struct {
Sec int32
Usec int32
}

View File

@@ -0,0 +1,48 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_linux.go
package host
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
_C_short int16
_C_int int32
_C_long int64
_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 _Ctype_struct___0
Addr_v6 [4]int32
X__glibc_reserved [20]int8
}
type exit_status struct {
Termination int16
Exit int16
}
type timeval struct {
Sec int64
Usec int64
}
type _Ctype_struct___0 struct {
Sec int32
Usec int32
}

View File

@@ -0,0 +1,43 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_linux.go | sed "s/uint8/int8/g"
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__glibc_reserved [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 = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
_C_short int16
_C_int int32
_C_long int64
_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__glibc_reserved [20]int8
}
type exit_status struct {
Termination int16
Exit int16
}
type timeval struct {
Sec int64
Usec int64
}

View File

@@ -0,0 +1,45 @@
// +build linux
// +build ppc64le
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_linux.go
package host
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
_C_short int16
_C_int int32
_C_long int64
_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__glibc_reserved [20]int8
}
type exit_status struct {
Termination int16
Exit int16
}
type timeval struct {
Sec int64
Usec int64
}

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

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

@@ -0,0 +1,88 @@
package host
import (
"fmt"
"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) {
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) {
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")
}
}
func TestUsers(t *testing.T) {
v, err := Users()
if err != nil {
t.Errorf("error %v", err)
}
empty := UserStat{}
if len(v) == 0 {
t.Errorf("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":"","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)
}
}

133
vendor/github.com/shirou/gopsutil/host/host_windows.go generated vendored Normal file
View File

@@ -0,0 +1,133 @@
// +build windows
package host
import (
"fmt"
"os"
"runtime"
"strings"
"time"
"github.com/StackExchange/wmi"
"github.com/shirou/gopsutil/internal/common"
process "github.com/shirou/gopsutil/process"
)
var (
procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime")
osInfo *Win32_OperatingSystem
)
type Win32_OperatingSystem struct {
Version string
Caption string
ProductType uint32
BuildNumber string
LastBootUpTime time.Time
}
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
}
hostname, err := os.Hostname()
if err == nil {
ret.Hostname = hostname
}
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
} else {
return ret, err
}
boot, err := BootTime()
if err == nil {
ret.BootTime = boot
ret.Uptime, _ = Uptime()
}
procs, err := process.Pids()
if err == nil {
ret.Procs = uint64(len(procs))
}
return ret, nil
}
func GetOSInfo() (Win32_OperatingSystem, error) {
var dst []Win32_OperatingSystem
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
if err != nil {
return Win32_OperatingSystem{}, err
}
osInfo = &dst[0]
return dst[0], nil
}
func Uptime() (uint64, error) {
if osInfo == nil {
_, err := GetOSInfo()
if err != nil {
return 0, err
}
}
now := time.Now()
t := osInfo.LastBootUpTime.Local()
return uint64(now.Sub(t).Seconds()), nil
}
func bootTime(up uint64) uint64 {
return uint64(time.Now().Unix()) - up
}
func BootTime() (uint64, error) {
up, err := Uptime()
if err != nil {
return 0, err
}
return bootTime(up), nil
}
func PlatformInformation() (platform string, family string, version string, err error) {
if osInfo == nil {
_, err = GetOSInfo()
if err != nil {
return
}
}
// Platform
platform = strings.Trim(osInfo.Caption, " ")
// PlatformFamily
switch osInfo.ProductType {
case 1:
family = "Standalone Workstation"
case 2:
family = "Server (Domain Controller)"
case 3:
family = "Server"
}
// Platform Version
version = fmt.Sprintf("%s Build %s", osInfo.Version, osInfo.BuildNumber)
return
}
func Users() ([]UserStat, error) {
var ret []UserStat
return ret, nil
}

17
vendor/github.com/shirou/gopsutil/host/types_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
// +build ignore
// plus hand editing about timeval
/*
Input to cgo -godefs.
*/
package host
/*
#include <sys/time.h>
#include <utmpx.h>
*/
import "C"
type Utmpx C.struct_utmpx
type Timeval C.struct_timeval

View File

@@ -0,0 +1,44 @@
// +build ignore
/*
Input to cgo -godefs.
*/
package host
/*
#define KERNEL
#include <sys/types.h>
#include <sys/time.h>
#include <utmpx.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
sizeOfUtmpx = C.sizeof_struct_utmpx
)
// Basic types
type (
_C_short C.short
_C_int C.int
_C_long C.long
_C_long_long C.longlong
)
type Utmp C.struct_utmp
type Utmpx C.struct_utmpx
type Timeval C.struct_timeval

42
vendor/github.com/shirou/gopsutil/host/types_linux.go generated vendored Normal file
View File

@@ -0,0 +1,42 @@
// +build ignore
/*
Input to cgo -godefs.
*/
package host
/*
#include <sys/types.h>
#include <utmp.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
sizeOfUtmp = C.sizeof_struct_utmp
)
// Basic types
type (
_C_short C.short
_C_int C.int
_C_long C.long
_C_long_long C.longlong
)
type utmp C.struct_utmp
type exit_status C.struct_exit_status
type timeval C.struct_timeval

View File

@@ -0,0 +1,634 @@
package common
// 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.
// Package binary implements simple translation between numbers and byte
// sequences and encoding and decoding of varints.
//
// Numbers are translated by reading and writing fixed-size values.
// A fixed-size value is either a fixed-size arithmetic
// type (int8, uint8, int16, float32, complex64, ...)
// or an array or struct containing only fixed-size values.
//
// The varint functions encode and decode single integer values using
// a variable-length encoding; smaller values require fewer bytes.
// For a specification, see
// http://code.google.com/apis/protocolbuffers/docs/encoding.html.
//
// This package favors simplicity over efficiency. Clients that require
// high-performance serialization, especially for large data structures,
// should look at more advanced solutions such as the encoding/gob
// package or protocol buffers.
import (
"errors"
"io"
"math"
"reflect"
)
// A ByteOrder specifies how to convert byte sequences into
// 16-, 32-, or 64-bit unsigned integers.
type ByteOrder interface {
Uint16([]byte) uint16
Uint32([]byte) uint32
Uint64([]byte) uint64
PutUint16([]byte, uint16)
PutUint32([]byte, uint32)
PutUint64([]byte, uint64)
String() string
}
// LittleEndian is the little-endian implementation of ByteOrder.
var LittleEndian littleEndian
// BigEndian is the big-endian implementation of ByteOrder.
var BigEndian bigEndian
type littleEndian struct{}
func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
func (littleEndian) PutUint16(b []byte, v uint16) {
b[0] = byte(v)
b[1] = byte(v >> 8)
}
func (littleEndian) Uint32(b []byte) uint32 {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
func (littleEndian) PutUint32(b []byte, v uint32) {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
}
func (littleEndian) Uint64(b []byte) uint64 {
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}
func (littleEndian) PutUint64(b []byte, v uint64) {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
b[4] = byte(v >> 32)
b[5] = byte(v >> 40)
b[6] = byte(v >> 48)
b[7] = byte(v >> 56)
}
func (littleEndian) String() string { return "LittleEndian" }
func (littleEndian) GoString() string { return "binary.LittleEndian" }
type bigEndian struct{}
func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
func (bigEndian) PutUint16(b []byte, v uint16) {
b[0] = byte(v >> 8)
b[1] = byte(v)
}
func (bigEndian) Uint32(b []byte) uint32 {
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
func (bigEndian) PutUint32(b []byte, v uint32) {
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}
func (bigEndian) Uint64(b []byte) uint64 {
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
func (bigEndian) PutUint64(b []byte, v uint64) {
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
b[2] = byte(v >> 40)
b[3] = byte(v >> 32)
b[4] = byte(v >> 24)
b[5] = byte(v >> 16)
b[6] = byte(v >> 8)
b[7] = byte(v)
}
func (bigEndian) String() string { return "BigEndian" }
func (bigEndian) GoString() string { return "binary.BigEndian" }
// Read reads structured binary data from r into data.
// Data must be a pointer to a fixed-size value or a slice
// of fixed-size values.
// Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data.
// When reading into structs, the field data for fields with
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
// When reading into a struct, all non-blank fields must be exported.
func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Fast path for basic types and slices.
if n := intDataSize(data); n != 0 {
var b [8]byte
var bs []byte
if n > len(b) {
bs = make([]byte, n)
} else {
bs = b[:n]
}
if _, err := io.ReadFull(r, bs); err != nil {
return err
}
switch data := data.(type) {
case *int8:
*data = int8(b[0])
case *uint8:
*data = b[0]
case *int16:
*data = int16(order.Uint16(bs))
case *uint16:
*data = order.Uint16(bs)
case *int32:
*data = int32(order.Uint32(bs))
case *uint32:
*data = order.Uint32(bs)
case *int64:
*data = int64(order.Uint64(bs))
case *uint64:
*data = order.Uint64(bs)
case []int8:
for i, x := range bs { // Easier to loop over the input for 8-bit values.
data[i] = int8(x)
}
case []uint8:
copy(data, bs)
case []int16:
for i := range data {
data[i] = int16(order.Uint16(bs[2*i:]))
}
case []uint16:
for i := range data {
data[i] = order.Uint16(bs[2*i:])
}
case []int32:
for i := range data {
data[i] = int32(order.Uint32(bs[4*i:]))
}
case []uint32:
for i := range data {
data[i] = order.Uint32(bs[4*i:])
}
case []int64:
for i := range data {
data[i] = int64(order.Uint64(bs[8*i:]))
}
case []uint64:
for i := range data {
data[i] = order.Uint64(bs[8*i:])
}
}
return nil
}
// Fallback to reflect-based decoding.
v := reflect.ValueOf(data)
size := -1
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
size = dataSize(v)
case reflect.Slice:
size = dataSize(v)
}
if size < 0 {
return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String())
}
d := &decoder{order: order, buf: make([]byte, size)}
if _, err := io.ReadFull(r, d.buf); err != nil {
return err
}
d.value(v)
return nil
}
// Write writes the binary representation of data into w.
// Data must be a fixed-size value or a slice of fixed-size
// values, or a pointer to such data.
// Bytes written to w are encoded using the specified byte order
// and read from successive fields of the data.
// When writing structs, zero values are written for fields
// with blank (_) field names.
func Write(w io.Writer, order ByteOrder, data interface{}) error {
// Fast path for basic types and slices.
if n := intDataSize(data); n != 0 {
var b [8]byte
var bs []byte
if n > len(b) {
bs = make([]byte, n)
} else {
bs = b[:n]
}
switch v := data.(type) {
case *int8:
bs = b[:1]
b[0] = byte(*v)
case int8:
bs = b[:1]
b[0] = byte(v)
case []int8:
for i, x := range v {
bs[i] = byte(x)
}
case *uint8:
bs = b[:1]
b[0] = *v
case uint8:
bs = b[:1]
b[0] = byte(v)
case []uint8:
bs = v
case *int16:
bs = b[:2]
order.PutUint16(bs, uint16(*v))
case int16:
bs = b[:2]
order.PutUint16(bs, uint16(v))
case []int16:
for i, x := range v {
order.PutUint16(bs[2*i:], uint16(x))
}
case *uint16:
bs = b[:2]
order.PutUint16(bs, *v)
case uint16:
bs = b[:2]
order.PutUint16(bs, v)
case []uint16:
for i, x := range v {
order.PutUint16(bs[2*i:], x)
}
case *int32:
bs = b[:4]
order.PutUint32(bs, uint32(*v))
case int32:
bs = b[:4]
order.PutUint32(bs, uint32(v))
case []int32:
for i, x := range v {
order.PutUint32(bs[4*i:], uint32(x))
}
case *uint32:
bs = b[:4]
order.PutUint32(bs, *v)
case uint32:
bs = b[:4]
order.PutUint32(bs, v)
case []uint32:
for i, x := range v {
order.PutUint32(bs[4*i:], x)
}
case *int64:
bs = b[:8]
order.PutUint64(bs, uint64(*v))
case int64:
bs = b[:8]
order.PutUint64(bs, uint64(v))
case []int64:
for i, x := range v {
order.PutUint64(bs[8*i:], uint64(x))
}
case *uint64:
bs = b[:8]
order.PutUint64(bs, *v)
case uint64:
bs = b[:8]
order.PutUint64(bs, v)
case []uint64:
for i, x := range v {
order.PutUint64(bs[8*i:], x)
}
}
_, err := w.Write(bs)
return err
}
// Fallback to reflect-based encoding.
v := reflect.Indirect(reflect.ValueOf(data))
size := dataSize(v)
if size < 0 {
return errors.New("binary.Write: invalid type " + reflect.TypeOf(data).String())
}
buf := make([]byte, size)
e := &encoder{order: order, buf: buf}
e.value(v)
_, err := w.Write(buf)
return err
}
// Size returns how many bytes Write would generate to encode the value v, which
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
// If v is neither of these, Size returns -1.
func Size(v interface{}) int {
return dataSize(reflect.Indirect(reflect.ValueOf(v)))
}
// dataSize returns the number of bytes the actual data represented by v occupies in memory.
// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
// it returns the length of the slice times the element size and does not count the memory
// occupied by the header. If the type of v is not acceptable, dataSize returns -1.
func dataSize(v reflect.Value) int {
if v.Kind() == reflect.Slice {
if s := sizeof(v.Type().Elem()); s >= 0 {
return s * v.Len()
}
return -1
}
return sizeof(v.Type())
}
// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable.
func sizeof(t reflect.Type) int {
switch t.Kind() {
case reflect.Array:
if s := sizeof(t.Elem()); s >= 0 {
return s * t.Len()
}
case reflect.Struct:
sum := 0
for i, n := 0, t.NumField(); i < n; i++ {
s := sizeof(t.Field(i).Type)
if s < 0 {
return -1
}
sum += s
}
return sum
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Ptr:
return int(t.Size())
}
return -1
}
type coder struct {
order ByteOrder
buf []byte
}
type decoder coder
type encoder coder
func (d *decoder) uint8() uint8 {
x := d.buf[0]
d.buf = d.buf[1:]
return x
}
func (e *encoder) uint8(x uint8) {
e.buf[0] = x
e.buf = e.buf[1:]
}
func (d *decoder) uint16() uint16 {
x := d.order.Uint16(d.buf[0:2])
d.buf = d.buf[2:]
return x
}
func (e *encoder) uint16(x uint16) {
e.order.PutUint16(e.buf[0:2], x)
e.buf = e.buf[2:]
}
func (d *decoder) uint32() uint32 {
x := d.order.Uint32(d.buf[0:4])
d.buf = d.buf[4:]
return x
}
func (e *encoder) uint32(x uint32) {
e.order.PutUint32(e.buf[0:4], x)
e.buf = e.buf[4:]
}
func (d *decoder) uint64() uint64 {
x := d.order.Uint64(d.buf[0:8])
d.buf = d.buf[8:]
return x
}
func (e *encoder) uint64(x uint64) {
e.order.PutUint64(e.buf[0:8], x)
e.buf = e.buf[8:]
}
func (d *decoder) int8() int8 { return int8(d.uint8()) }
func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
func (d *decoder) int16() int16 { return int16(d.uint16()) }
func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
func (d *decoder) int32() int32 { return int32(d.uint32()) }
func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
func (d *decoder) int64() int64 { return int64(d.uint64()) }
func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
func (d *decoder) value(v reflect.Value) {
switch v.Kind() {
case reflect.Array:
l := v.Len()
for i := 0; i < l; i++ {
d.value(v.Index(i))
}
case reflect.Struct:
t := v.Type()
l := v.NumField()
for i := 0; i < l; i++ {
// Note: Calling v.CanSet() below is an optimization.
// It would be sufficient to check the field name,
// but creating the StructField info for each field is
// costly (run "go test -bench=ReadStruct" and compare
// results when making changes to this code).
if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
d.value(v)
} else {
d.skip(v)
}
}
case reflect.Slice:
l := v.Len()
for i := 0; i < l; i++ {
d.value(v.Index(i))
}
case reflect.Int8:
v.SetInt(int64(d.int8()))
case reflect.Int16:
v.SetInt(int64(d.int16()))
case reflect.Int32:
v.SetInt(int64(d.int32()))
case reflect.Int64:
v.SetInt(d.int64())
case reflect.Uint8:
v.SetUint(uint64(d.uint8()))
case reflect.Uint16:
v.SetUint(uint64(d.uint16()))
case reflect.Uint32:
v.SetUint(uint64(d.uint32()))
case reflect.Uint64:
v.SetUint(d.uint64())
case reflect.Float32:
v.SetFloat(float64(math.Float32frombits(d.uint32())))
case reflect.Float64:
v.SetFloat(math.Float64frombits(d.uint64()))
case reflect.Complex64:
v.SetComplex(complex(
float64(math.Float32frombits(d.uint32())),
float64(math.Float32frombits(d.uint32())),
))
case reflect.Complex128:
v.SetComplex(complex(
math.Float64frombits(d.uint64()),
math.Float64frombits(d.uint64()),
))
}
}
func (e *encoder) value(v reflect.Value) {
switch v.Kind() {
case reflect.Array:
l := v.Len()
for i := 0; i < l; i++ {
e.value(v.Index(i))
}
case reflect.Struct:
t := v.Type()
l := v.NumField()
for i := 0; i < l; i++ {
// see comment for corresponding code in decoder.value()
if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
e.value(v)
} else {
e.skip(v)
}
}
case reflect.Slice:
l := v.Len()
for i := 0; i < l; i++ {
e.value(v.Index(i))
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch v.Type().Kind() {
case reflect.Int8:
e.int8(int8(v.Int()))
case reflect.Int16:
e.int16(int16(v.Int()))
case reflect.Int32:
e.int32(int32(v.Int()))
case reflect.Int64:
e.int64(v.Int())
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
switch v.Type().Kind() {
case reflect.Uint8:
e.uint8(uint8(v.Uint()))
case reflect.Uint16:
e.uint16(uint16(v.Uint()))
case reflect.Uint32:
e.uint32(uint32(v.Uint()))
case reflect.Uint64:
e.uint64(v.Uint())
}
case reflect.Float32, reflect.Float64:
switch v.Type().Kind() {
case reflect.Float32:
e.uint32(math.Float32bits(float32(v.Float())))
case reflect.Float64:
e.uint64(math.Float64bits(v.Float()))
}
case reflect.Complex64, reflect.Complex128:
switch v.Type().Kind() {
case reflect.Complex64:
x := v.Complex()
e.uint32(math.Float32bits(float32(real(x))))
e.uint32(math.Float32bits(float32(imag(x))))
case reflect.Complex128:
x := v.Complex()
e.uint64(math.Float64bits(real(x)))
e.uint64(math.Float64bits(imag(x)))
}
}
}
func (d *decoder) skip(v reflect.Value) {
d.buf = d.buf[dataSize(v):]
}
func (e *encoder) skip(v reflect.Value) {
n := dataSize(v)
for i := range e.buf[0:n] {
e.buf[i] = 0
}
e.buf = e.buf[n:]
}
// intDataSize returns the size of the data required to represent the data when encoded.
// It returns zero if the type cannot be implemented by the fast path in Read or Write.
func intDataSize(data interface{}) int {
switch data := data.(type) {
case int8, *int8, *uint8:
return 1
case []int8:
return len(data)
case []uint8:
return len(data)
case int16, *int16, *uint16:
return 2
case []int16:
return 2 * len(data)
case []uint16:
return 2 * len(data)
case int32, *int32, *uint32:
return 4
case []int32:
return 4 * len(data)
case []uint32:
return 4 * len(data)
case int64, *int64, *uint64:
return 8
case []int64:
return 8 * len(data)
case []uint64:
return 8 * len(data)
}
return 0
}

View File

@@ -0,0 +1,343 @@
package common
//
// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
// This covers these architectures.
// - linux (amd64, arm)
// - freebsd (amd64)
// - windows (amd64)
import (
"bufio"
"bytes"
"errors"
"io/ioutil"
"log"
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"reflect"
"runtime"
"strconv"
"strings"
"time"
)
var (
Timeout = 3 * time.Second
ErrTimeout = errors.New("Command timed out.")
)
type Invoker interface {
Command(string, ...string) ([]byte, error)
}
type Invoke struct{}
func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
cmd := exec.Command(name, arg...)
return CombinedOutputTimeout(cmd, Timeout)
}
type FakeInvoke struct {
CommandExpectedDir string // CommandExpectedDir specifies dir which includes expected outputs.
Suffix string // Suffix species expected file name suffix such as "fail"
Error error // If Error specfied, return the error.
}
// Command in FakeInvoke returns from expected file if exists.
func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
if i.Error != nil {
return []byte{}, i.Error
}
arch := runtime.GOOS
fname := strings.Join(append([]string{name}, arg...), "")
fname = url.QueryEscape(fname)
var dir string
if i.CommandExpectedDir == "" {
dir = "expected"
} else {
dir = i.CommandExpectedDir
}
fpath := path.Join(dir, arch, fname)
if i.Suffix != "" {
fpath += "_" + i.Suffix
}
if PathExists(fpath) {
return ioutil.ReadFile(fpath)
}
return exec.Command(name, arg...).Output()
}
var ErrNotImplementedError = errors.New("not implemented yet")
// ReadLines reads contents from a file and splits them by new lines.
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
func ReadLines(filename string) ([]string, error) {
return ReadLinesOffsetN(filename, 0, -1)
}
// ReadLines reads contents from file and splits them by new line.
// The offset tells at which line number to start.
// The count determines the number of lines to read (starting from offset):
// n >= 0: at most n lines
// n < 0: whole file
func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
f, err := os.Open(filename)
if err != nil {
return []string{""}, err
}
defer f.Close()
var ret []string
r := bufio.NewReader(f)
for i := 0; i < n+int(offset) || n < 0; i++ {
line, err := r.ReadString('\n')
if err != nil {
break
}
if i < int(offset) {
continue
}
ret = append(ret, strings.Trim(line, "\n"))
}
return ret, nil
}
func IntToString(orig []int8) string {
ret := make([]byte, len(orig))
size := -1
for i, o := range orig {
if o == 0 {
size = i
break
}
ret[i] = byte(o)
}
if size == -1 {
size = len(orig)
}
return string(ret[0:size])
}
func UintToString(orig []uint8) string {
ret := make([]byte, len(orig))
size := -1
for i, o := range orig {
if o == 0 {
size = i
break
}
ret[i] = byte(o)
}
if size == -1 {
size = len(orig)
}
return string(ret[0:size])
}
func ByteToString(orig []byte) string {
n := -1
l := -1
for i, b := range orig {
// skip left side null
if l == -1 && b == 0 {
continue
}
if l == -1 {
l = i
}
if b == 0 {
break
}
n = i + 1
}
if n == -1 {
return string(orig)
}
return string(orig[l:n])
}
// ReadInts reads contents from single line file and returns them as []int32.
func ReadInts(filename string) ([]int64, error) {
f, err := os.Open(filename)
if err != nil {
return []int64{}, err
}
defer f.Close()
var ret []int64
r := bufio.NewReader(f)
// The int files that this is concerned with should only be one liners.
line, err := r.ReadString('\n')
if err != nil {
return []int64{}, err
}
i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
if err != nil {
return []int64{}, err
}
ret = append(ret, i)
return ret, nil
}
// Parse to int32 without error
func mustParseInt32(val string) int32 {
vv, _ := strconv.ParseInt(val, 10, 32)
return int32(vv)
}
// Parse to uint64 without error
func mustParseUint64(val string) uint64 {
vv, _ := strconv.ParseInt(val, 10, 64)
return uint64(vv)
}
// Parse to Float64 without error
func mustParseFloat64(val string) float64 {
vv, _ := strconv.ParseFloat(val, 64)
return vv
}
// StringsHas checks the target string slice contains src or not
func StringsHas(target []string, src string) bool {
for _, t := range target {
if strings.TrimSpace(t) == src {
return true
}
}
return false
}
// StringsContains checks the src in any string of the target string slice
func StringsContains(target []string, src string) bool {
for _, t := range target {
if strings.Contains(t, src) {
return true
}
}
return false
}
// IntContains checks the src in any int of the target int slice.
func IntContains(target []int, src int) bool {
for _, t := range target {
if src == t {
return true
}
}
return false
}
// get struct attributes.
// This method is used only for debugging platform dependent code.
func attributes(m interface{}) map[string]reflect.Type {
typ := reflect.TypeOf(m)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
attrs := make(map[string]reflect.Type)
if typ.Kind() != reflect.Struct {
return nil
}
for i := 0; i < typ.NumField(); i++ {
p := typ.Field(i)
if !p.Anonymous {
attrs[p.Name] = p.Type
}
}
return attrs
}
func PathExists(filename string) bool {
if _, err := os.Stat(filename); err == nil {
return true
}
return false
}
//GetEnv retrieves the environment variable key. If it does not exist it returns the default.
func GetEnv(key string, dfault string, combineWith ...string) string {
value := os.Getenv(key)
if value == "" {
value = dfault
}
switch len(combineWith) {
case 0:
return value
case 1:
return filepath.Join(value, combineWith[0])
default:
all := make([]string, len(combineWith)+1)
all[0] = value
copy(all[1:], combineWith)
return filepath.Join(all...)
}
panic("invalid switch case")
}
func HostProc(combineWith ...string) string {
return GetEnv("HOST_PROC", "/proc", combineWith...)
}
func HostSys(combineWith ...string) string {
return GetEnv("HOST_SYS", "/sys", combineWith...)
}
func HostEtc(combineWith ...string) string {
return GetEnv("HOST_ETC", "/etc", combineWith...)
}
// CombinedOutputTimeout runs the given command with the given timeout and
// returns the combined output of stdout and stderr.
// If the command times out, it attempts to kill the process.
// copied from https://github.com/influxdata/telegraf
func CombinedOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) {
var b bytes.Buffer
c.Stdout = &b
c.Stderr = &b
if err := c.Start(); err != nil {
return nil, err
}
err := WaitTimeout(c, timeout)
return b.Bytes(), err
}
// WaitTimeout waits for the given command to finish with a timeout.
// It assumes the command has already been started.
// If the command times out, it attempts to kill the process.
// copied from https://github.com/influxdata/telegraf
func WaitTimeout(c *exec.Cmd, timeout time.Duration) error {
timer := time.NewTimer(timeout)
done := make(chan error)
go func() { done <- c.Wait() }()
select {
case err := <-done:
timer.Stop()
return err
case <-timer.C:
if err := c.Process.Kill(); err != nil {
log.Printf("FATAL error killing process: %s", err)
return err
}
// wait for the command to return after killing it
<-done
return ErrTimeout
}
}

View File

@@ -0,0 +1,70 @@
// +build darwin
package common
import (
"os"
"os/exec"
"strings"
"syscall"
"unsafe"
)
func DoSysctrl(mib string) ([]string, error) {
err := os.Setenv("LC_ALL", "C")
if err != nil {
return []string{}, err
}
sysctl, err := exec.LookPath("/usr/sbin/sysctl")
if err != nil {
return []string{}, err
}
out, err := exec.Command(sysctl, "-n", mib).Output()
if err != nil {
return []string{}, err
}
v := strings.Replace(string(out), "{ ", "", 1)
v = strings.Replace(string(v), " }", "", 1)
values := strings.Fields(string(v))
return values, nil
}
func CallSyscall(mib []int32) ([]byte, uint64, error) {
miblen := uint64(len(mib))
// get required buffer size
length := uint64(0)
_, _, err := syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(miblen),
0,
uintptr(unsafe.Pointer(&length)),
0,
0)
if err != 0 {
var b []byte
return b, length, err
}
if length == 0 {
var b []byte
return b, length, err
}
// get proc info itself
buf := make([]byte, length)
_, _, err = syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(miblen),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&length)),
0,
0)
if err != 0 {
return buf, length, err
}
return buf, length, nil
}

View File

@@ -0,0 +1,70 @@
// +build freebsd
package common
import (
"os"
"os/exec"
"strings"
"syscall"
"unsafe"
)
func DoSysctrl(mib string) ([]string, error) {
err := os.Setenv("LC_ALL", "C")
if err != nil {
return []string{}, err
}
sysctl, err := exec.LookPath("/sbin/sysctl")
if err != nil {
return []string{}, err
}
out, err := exec.Command(sysctl, "-n", mib).Output()
if err != nil {
return []string{}, err
}
v := strings.Replace(string(out), "{ ", "", 1)
v = strings.Replace(string(v), " }", "", 1)
values := strings.Fields(string(v))
return values, nil
}
func CallSyscall(mib []int32) ([]byte, uint64, error) {
mibptr := unsafe.Pointer(&mib[0])
miblen := uint64(len(mib))
// get required buffer size
length := uint64(0)
_, _, err := syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(mibptr),
uintptr(miblen),
0,
uintptr(unsafe.Pointer(&length)),
0,
0)
if err != 0 {
var b []byte
return b, length, err
}
if length == 0 {
var b []byte
return b, length, err
}
// get proc info itself
buf := make([]byte, length)
_, _, err = syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(mibptr),
uintptr(miblen),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&length)),
0,
0)
if err != 0 {
return buf, length, err
}
return buf, length, nil
}

View File

@@ -0,0 +1,43 @@
// +build linux
package common
import (
"os"
"os/exec"
"strings"
)
func DoSysctrl(mib string) ([]string, error) {
err := os.Setenv("LC_ALL", "C")
if err != nil {
return []string{}, err
}
sysctl, err := exec.LookPath("/sbin/sysctl")
if err != nil {
return []string{}, err
}
out, err := exec.Command(sysctl, "-n", mib).Output()
if err != nil {
return []string{}, err
}
v := strings.Replace(string(out), "{ ", "", 1)
v = strings.Replace(string(v), " }", "", 1)
values := strings.Fields(string(v))
return values, nil
}
func NumProcs() (uint64, error) {
f, err := os.Open(HostProc())
if err != nil {
return 0, err
}
list, err := f.Readdir(-1)
defer f.Close()
if err != nil {
return 0, err
}
return uint64(len(list)), err
}

View File

@@ -0,0 +1,97 @@
package common
import (
"fmt"
"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) {
p := HostEtc("mtab")
if p != "/etc/mtab" {
t.Errorf("invalid HostEtc, %s", p)
}
}

View File

@@ -0,0 +1,66 @@
// +build linux freebsd darwin
package common
import (
"os/exec"
"strconv"
"strings"
)
func CallLsof(invoke Invoker, pid int32, args ...string) ([]string, error) {
var cmd []string
if pid == 0 { // will get from all processes.
cmd = []string{"-a", "-n", "-P"}
} else {
cmd = []string{"-a", "-n", "-P", "-p", strconv.Itoa(int(pid))}
}
cmd = append(cmd, args...)
lsof, err := exec.LookPath("lsof")
if err != nil {
return []string{}, err
}
out, err := invoke.Command(lsof, cmd...)
if err != nil {
// if no pid found, lsof returnes code 1.
if err.Error() == "exit status 1" && len(out) == 0 {
return []string{}, nil
}
}
lines := strings.Split(string(out), "\n")
var ret []string
for _, l := range lines[1:] {
if len(l) == 0 {
continue
}
ret = append(ret, l)
}
return ret, nil
}
func CallPgrep(invoke Invoker, pid int32) ([]int32, error) {
var cmd []string
cmd = []string{"-P", strconv.Itoa(int(pid))}
pgrep, err := exec.LookPath("pgrep")
if err != nil {
return []int32{}, err
}
out, err := invoke.Command(pgrep, cmd...)
if err != nil {
return []int32{}, err
}
lines := strings.Split(string(out), "\n")
ret := make([]int32, 0, len(lines))
for _, l := range lines {
if len(l) == 0 {
continue
}
i, err := strconv.Atoi(l)
if err != nil {
continue
}
ret = append(ret, int32(i))
}
return ret, nil
}

View File

@@ -0,0 +1,110 @@
// +build windows
package common
import (
"syscall"
"unsafe"
)
// for double values
type PDH_FMT_COUNTERVALUE_DOUBLE struct {
CStatus uint32
DoubleValue float64
}
// for 64 bit integer values
type PDH_FMT_COUNTERVALUE_LARGE struct {
CStatus uint32
LargeValue int64
}
// for long values
type PDH_FMT_COUNTERVALUE_LONG struct {
CStatus uint32
LongValue int32
padding [4]byte
}
// windows system const
const (
ERROR_SUCCESS = 0
ERROR_FILE_NOT_FOUND = 2
DRIVE_REMOVABLE = 2
DRIVE_FIXED = 3
HKEY_LOCAL_MACHINE = 0x80000002
RRF_RT_REG_SZ = 0x00000002
RRF_RT_REG_DWORD = 0x00000010
PDH_FMT_LONG = 0x00000100
PDH_FMT_DOUBLE = 0x00000200
PDH_FMT_LARGE = 0x00000400
PDH_INVALID_DATA = 0xc0000bc6
PDH_INVALID_HANDLE = 0xC0000bbc
PDH_NO_DATA = 0x800007d5
)
var (
Modkernel32 = syscall.NewLazyDLL("kernel32.dll")
ModNt = syscall.NewLazyDLL("ntdll.dll")
ModPdh = syscall.NewLazyDLL("pdh.dll")
ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")
PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
PdhAddCounter = ModPdh.NewProc("PdhAddCounterW")
PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData")
PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery")
)
type FILETIME struct {
DwLowDateTime uint32
DwHighDateTime uint32
}
// borrowed from net/interface_windows.go
func BytePtrToString(p *uint8) string {
a := (*[10000]uint8)(unsafe.Pointer(p))
i := 0
for a[i] != 0 {
i++
}
return string(a[:i])
}
// CounterInfo
// copied from https://github.com/mackerelio/mackerel-agent/
type CounterInfo struct {
PostName string
CounterName string
Counter syscall.Handle
}
// CreateQuery XXX
// copied from https://github.com/mackerelio/mackerel-agent/
func CreateQuery() (syscall.Handle, error) {
var query syscall.Handle
r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))
if r != 0 {
return 0, err
}
return query, nil
}
// CreateCounter XXX
func CreateCounter(query syscall.Handle, pname, cname string) (*CounterInfo, error) {
var counter syscall.Handle
r, _, err := PdhAddCounter.Call(
uintptr(query),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(cname))),
0,
uintptr(unsafe.Pointer(&counter)))
if r != 0 {
return nil, err
}
return &CounterInfo{
PostName: pname,
CounterName: cname,
Counter: counter,
}, nil
}

35
vendor/github.com/shirou/gopsutil/load/load.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
package load
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type AvgStat struct {
Load1 float64 `json:"load1"`
Load5 float64 `json:"load5"`
Load15 float64 `json:"load15"`
}
func (l AvgStat) String() string {
s, _ := json.Marshal(l)
return string(s)
}
type MiscStat struct {
ProcsRunning int `json:"procsRunning"`
ProcsBlocked int `json:"procsBlocked"`
Ctxt int `json:"ctxt"`
}
func (m MiscStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}

67
vendor/github.com/shirou/gopsutil/load/load_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
// +build darwin
package load
import (
"os/exec"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
func Avg() (*AvgStat, error) {
values, err := common.DoSysctrl("vm.loadavg")
if err != nil {
return nil, err
}
load1, err := strconv.ParseFloat(values[0], 64)
if err != nil {
return nil, err
}
load5, err := strconv.ParseFloat(values[1], 64)
if err != nil {
return nil, err
}
load15, err := strconv.ParseFloat(values[2], 64)
if err != nil {
return nil, err
}
ret := &AvgStat{
Load1: float64(load1),
Load5: float64(load5),
Load15: float64(load15),
}
return ret, nil
}
// Misc returnes miscellaneous host-wide statistics.
// darwin use ps command to get process running/blocked count.
// Almost same as FreeBSD implementation, but state is different.
// U means 'Uninterruptible Sleep'.
func Misc() (*MiscStat, error) {
bin, err := exec.LookPath("ps")
if err != nil {
return nil, err
}
out, err := invoke.Command(bin, "axo", "state")
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
ret := MiscStat{}
for _, l := range lines {
if strings.Contains(l, "R") {
ret.ProcsRunning++
} else if strings.Contains(l, "U") {
// uninterruptible sleep == blocked
ret.ProcsBlocked++
}
}
return &ret, nil
}

65
vendor/github.com/shirou/gopsutil/load/load_freebsd.go generated vendored Normal file
View File

@@ -0,0 +1,65 @@
// +build freebsd
package load
import (
"os/exec"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
func Avg() (*AvgStat, error) {
values, err := common.DoSysctrl("vm.loadavg")
if err != nil {
return nil, err
}
load1, err := strconv.ParseFloat(values[0], 64)
if err != nil {
return nil, err
}
load5, err := strconv.ParseFloat(values[1], 64)
if err != nil {
return nil, err
}
load15, err := strconv.ParseFloat(values[2], 64)
if err != nil {
return nil, err
}
ret := &AvgStat{
Load1: float64(load1),
Load5: float64(load5),
Load15: float64(load15),
}
return ret, nil
}
// Misc returnes miscellaneous host-wide statistics.
// darwin use ps command to get process running/blocked count.
// Almost same as Darwin implementation, but state is different.
func Misc() (*MiscStat, error) {
bin, err := exec.LookPath("ps")
if err != nil {
return nil, err
}
out, err := invoke.Command(bin, "axo", "state")
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
ret := MiscStat{}
for _, l := range lines {
if strings.Contains(l, "R") {
ret.ProcsRunning++
} else if strings.Contains(l, "D") {
ret.ProcsBlocked++
}
}
return &ret, nil
}

78
vendor/github.com/shirou/gopsutil/load/load_linux.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
// +build linux
package load
import (
"io/ioutil"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
func Avg() (*AvgStat, error) {
filename := common.HostProc("loadavg")
line, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
values := strings.Fields(string(line))
load1, err := strconv.ParseFloat(values[0], 64)
if err != nil {
return nil, err
}
load5, err := strconv.ParseFloat(values[1], 64)
if err != nil {
return nil, err
}
load15, err := strconv.ParseFloat(values[2], 64)
if err != nil {
return nil, err
}
ret := &AvgStat{
Load1: load1,
Load5: load5,
Load15: load15,
}
return ret, nil
}
// Misc returnes miscellaneous host-wide statistics.
// Note: the name should be changed near future.
func Misc() (*MiscStat, error) {
filename := common.HostProc("stat")
out, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
ret := &MiscStat{}
lines := strings.Split(string(out), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) != 2 {
continue
}
v, err := strconv.ParseInt(fields[1], 10, 64)
if err != nil {
continue
}
switch fields[0] {
case "procs_running":
ret.ProcsRunning = int(v)
case "procs_blocked":
ret.ProcsBlocked = int(v)
case "ctxt":
ret.Ctxt = int(v)
default:
continue
}
}
return ret, nil
}

54
vendor/github.com/shirou/gopsutil/load/load_test.go generated vendored Normal file
View File

@@ -0,0 +1,54 @@
package load
import (
"fmt"
"testing"
)
func TestLoad(t *testing.T) {
v, err := Avg()
if err != nil {
t.Errorf("error %v", err)
}
empty := &AvgStat{}
if v == empty {
t.Errorf("error load: %v", v)
}
}
func TestLoadAvgStat_String(t *testing.T) {
v := AvgStat{
Load1: 10.1,
Load5: 20.1,
Load15: 30.1,
}
e := `{"load1":10.1,"load5":20.1,"load15":30.1}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("LoadAvgStat string is invalid: %v", v)
}
}
func TestMisc(t *testing.T) {
v, err := Misc()
if err != nil {
t.Errorf("error %v", err)
}
empty := &MiscStat{}
if v == empty {
t.Errorf("error load: %v", v)
}
}
func TestMiscStatString(t *testing.T) {
v := MiscStat{
ProcsRunning: 1,
ProcsBlocked: 2,
Ctxt: 3,
}
e := `{"procsRunning":1,"procsBlocked":2,"ctxt":3}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("TestMiscString string is invalid: %v", v)
}
}

19
vendor/github.com/shirou/gopsutil/load/load_windows.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
// +build windows
package load
import (
"github.com/shirou/gopsutil/internal/common"
)
func Avg() (*AvgStat, error) {
ret := AvgStat{}
return &ret, common.ErrNotImplementedError
}
func Misc() (*MiscStat, error) {
ret := MiscStat{}
return &ret, common.ErrNotImplementedError
}

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

@@ -0,0 +1,76 @@
package mem
import (
"encoding/json"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
// Memory usage statistics. Total, Available and Used contain numbers of bytes
// for human consumption.
//
// The other fields in this struct contain kernel specific values.
type VirtualMemoryStat struct {
// Total amount of RAM on this system
Total uint64 `json:"total"`
// RAM available for programs to allocate
//
// This value is computed from the kernel specific values.
Available uint64 `json:"available"`
// RAM used by programs
//
// This value is computed from the kernel specific values.
Used uint64 `json:"used"`
// Percentage of RAM used by programs
//
// This value is computed from the kernel specific values.
UsedPercent float64 `json:"usedPercent"`
// This is the kernel's notion of free memory; RAM chips whose bits nobody
// cares about the value of right now. For a human consumable number,
// Available is what you really want.
Free uint64 `json:"free"`
// OS X / BSD specific numbers:
// http://www.macyourself.com/2010/02/17/what-is-free-wired-active-and-inactive-system-memory-ram/
Active uint64 `json:"active"`
Inactive uint64 `json:"inactive"`
Wired uint64 `json:"wired"`
// Linux specific numbers
// https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html
// https://www.kernel.org/doc/Documentation/filesystems/proc.txt
Buffers uint64 `json:"buffers"`
Cached uint64 `json:"cached"`
Writeback uint64 `json:"writeback"`
Dirty uint64 `json:"dirty"`
WritebackTmp uint64 `json:"writebacktmp"`
}
type SwapMemoryStat struct {
Total uint64 `json:"total"`
Used uint64 `json:"used"`
Free uint64 `json:"free"`
UsedPercent float64 `json:"usedPercent"`
Sin uint64 `json:"sin"`
Sout uint64 `json:"sout"`
}
func (m VirtualMemoryStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
func (m SwapMemoryStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}

69
vendor/github.com/shirou/gopsutil/mem/mem_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,69 @@
// +build darwin
package mem
import (
"encoding/binary"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
func getHwMemsize() (uint64, error) {
totalString, err := syscall.Sysctl("hw.memsize")
if err != nil {
return 0, err
}
// syscall.sysctl() helpfully assumes the result is a null-terminated string and
// removes the last byte of the result if it's 0 :/
totalString += "\x00"
total := uint64(binary.LittleEndian.Uint64([]byte(totalString)))
return total, nil
}
// SwapMemory returns swapinfo.
func SwapMemory() (*SwapMemoryStat, error) {
var ret *SwapMemoryStat
swapUsage, err := common.DoSysctrl("vm.swapusage")
if err != nil {
return ret, err
}
total := strings.Replace(swapUsage[2], "M", "", 1)
used := strings.Replace(swapUsage[5], "M", "", 1)
free := strings.Replace(swapUsage[8], "M", "", 1)
total_v, err := strconv.ParseFloat(total, 64)
if err != nil {
return nil, err
}
used_v, err := strconv.ParseFloat(used, 64)
if err != nil {
return nil, err
}
free_v, err := strconv.ParseFloat(free, 64)
if err != nil {
return nil, err
}
u := float64(0)
if total_v != 0 {
u = ((total_v - free_v) / total_v) * 100.0
}
// vm.swapusage shows "M", multiply 1000
ret = &SwapMemoryStat{
Total: uint64(total_v * 1000),
Used: uint64(used_v * 1000),
Free: uint64(free_v * 1000),
UsedPercent: u,
}
return ret, nil
}

View File

@@ -0,0 +1,53 @@
// +build darwin
// +build cgo
package mem
/*
#include <mach/mach_host.h>
*/
import "C"
import (
"fmt"
"syscall"
"unsafe"
)
// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
count := C.mach_msg_type_number_t(C.HOST_VM_INFO_COUNT)
var vmstat C.vm_statistics_data_t
status := C.host_statistics(C.host_t(C.mach_host_self()),
C.HOST_VM_INFO,
C.host_info_t(unsafe.Pointer(&vmstat)),
&count)
if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_statistics error=%d", status)
}
pageSize := uint64(syscall.Getpagesize())
total, err := getHwMemsize()
if err != nil {
return nil, err
}
totalCount := C.natural_t(total / pageSize)
availableCount := vmstat.inactive_count + vmstat.free_count
usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)
usedCount := totalCount - availableCount
return &VirtualMemoryStat{
Total: total,
Available: pageSize * uint64(availableCount),
Used: pageSize * uint64(usedCount),
UsedPercent: usedPercent,
Free: pageSize * uint64(vmstat.free_count),
Active: pageSize * uint64(vmstat.active_count),
Inactive: pageSize * uint64(vmstat.inactive_count),
Wired: pageSize * uint64(vmstat.wire_count),
}, nil
}

View File

@@ -0,0 +1,88 @@
// +build darwin
// +build !cgo
package mem
import (
"os/exec"
"strconv"
"strings"
"syscall"
)
// Runs vm_stat and returns Free and inactive pages
func getVMStat(vms *VirtualMemoryStat) error {
vm_stat, err := exec.LookPath("vm_stat")
if err != nil {
return err
}
out, err := invoke.Command(vm_stat)
if err != nil {
return err
}
return parseVMStat(string(out), vms)
}
func parseVMStat(out string, vms *VirtualMemoryStat) error {
var err error
lines := strings.Split(out, "\n")
pagesize := uint64(syscall.Getpagesize())
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) < 2 {
continue
}
key := strings.TrimSpace(fields[0])
value := strings.Trim(fields[1], " .")
switch key {
case "Pages free":
free, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Free = free * pagesize
case "Pages inactive":
inactive, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Inactive = inactive * pagesize
case "Pages active":
active, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Active = active * pagesize
case "Pages wired down":
wired, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Wired = wired * pagesize
}
}
return err
}
// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
ret := &VirtualMemoryStat{}
total, err := getHwMemsize()
if err != nil {
return nil, err
}
err = getVMStat(ret)
if err != nil {
return nil, err
}
ret.Available = ret.Free + ret.Inactive
ret.Total = total
ret.Used = ret.Total - ret.Available
ret.UsedPercent = 100 * float64(ret.Used) / float64(ret.Total)
return ret, nil
}

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

134
vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go generated vendored Normal file
View File

@@ -0,0 +1,134 @@
// +build freebsd
package mem
import (
"errors"
"os/exec"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
func VirtualMemory() (*VirtualMemoryStat, error) {
pageSize, err := common.DoSysctrl("vm.stats.vm.v_page_size")
if err != nil {
return nil, err
}
p, err := strconv.ParseUint(pageSize[0], 10, 64)
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)
}
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,
}
ret.Available = ret.Inactive + ret.Cached + ret.Free
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
return ret, nil
}
// Return swapinfo
// FreeBSD can have multiple swap devices. but use only first device
func SwapMemory() (*SwapMemoryStat, error) {
swapinfo, err := exec.LookPath("swapinfo")
if err != nil {
return nil, err
}
out, err := invoke.Command(swapinfo)
if err != nil {
return nil, err
}
for _, line := range strings.Split(string(out), "\n") {
values := strings.Fields(line)
// skip title line
if len(values) == 0 || values[0] == "Device" {
continue
}
u := strings.Replace(values[4], "%", "", 1)
total_v, err := strconv.ParseUint(values[1], 10, 64)
if err != nil {
return nil, err
}
used_v, err := strconv.ParseUint(values[2], 10, 64)
if err != nil {
return nil, err
}
free_v, err := strconv.ParseUint(values[3], 10, 64)
if err != nil {
return nil, err
}
up_v, err := strconv.ParseFloat(u, 64)
if err != nil {
return nil, err
}
return &SwapMemoryStat{
Total: total_v,
Used: used_v,
Free: free_v,
UsedPercent: up_v,
}, nil
}
return nil, errors.New("no swap devices found")
}

106
vendor/github.com/shirou/gopsutil/mem/mem_linux.go generated vendored Normal file
View File

@@ -0,0 +1,106 @@
// +build linux
package mem
import (
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
func VirtualMemory() (*VirtualMemoryStat, error) {
filename := common.HostProc("meminfo")
lines, _ := common.ReadLines(filename)
// flag if MemAvailable is in /proc/meminfo (kernel 3.14+)
memavail := false
ret := &VirtualMemoryStat{}
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) != 2 {
continue
}
key := strings.TrimSpace(fields[0])
value := strings.TrimSpace(fields[1])
value = strings.Replace(value, " kB", "", -1)
t, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return ret, err
}
switch key {
case "MemTotal":
ret.Total = t * 1024
case "MemFree":
ret.Free = t * 1024
case "MemAvailable":
memavail = true
ret.Available = t * 1024
case "Buffers":
ret.Buffers = t * 1024
case "Cached":
ret.Cached = t * 1024
case "Active":
ret.Active = t * 1024
case "Inactive":
ret.Inactive = t * 1024
case "Writeback":
ret.Writeback = t * 1024
case "WritebackTmp":
ret.WritebackTmp = t * 1024
case "Dirty":
ret.Dirty = t * 1024
}
}
if !memavail {
ret.Available = ret.Free + ret.Buffers + ret.Cached
}
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0
return ret, nil
}
func SwapMemory() (*SwapMemoryStat, error) {
sysinfo := &syscall.Sysinfo_t{}
if err := syscall.Sysinfo(sysinfo); err != nil {
return nil, err
}
ret := &SwapMemoryStat{
Total: uint64(sysinfo.Totalswap),
Free: uint64(sysinfo.Freeswap),
}
ret.Used = ret.Total - ret.Free
//check Infinity
if ret.Total != 0 {
ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0
} else {
ret.UsedPercent = 0
}
filename := common.HostProc("vmstat")
lines, _ := common.ReadLines(filename)
for _, l := range lines {
fields := strings.Fields(l)
if len(fields) < 2 {
continue
}
switch fields[0] {
case "pswpin":
value, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
continue
}
ret.Sin = value * 4 * 1024
case "pswpout":
value, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
continue
}
ret.Sout = value * 4 * 1024
}
}
return ret, nil
}

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

@@ -0,0 +1,72 @@
package mem
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestVirtual_memory(t *testing.T) {
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}`
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)
}
}

50
vendor/github.com/shirou/gopsutil/mem/mem_windows.go generated vendored Normal file
View File

@@ -0,0 +1,50 @@
// +build windows
package mem
import (
"syscall"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
)
var (
procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
)
type memoryStatusEx struct {
cbSize uint32
dwMemoryLoad uint32
ullTotalPhys uint64 // in bytes
ullAvailPhys uint64
ullTotalPageFile uint64
ullAvailPageFile uint64
ullTotalVirtual uint64
ullAvailVirtual uint64
ullAvailExtendedVirtual uint64
}
func VirtualMemory() (*VirtualMemoryStat, error) {
var memInfo memoryStatusEx
memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
if mem == 0 {
return nil, syscall.GetLastError()
}
ret := &VirtualMemoryStat{
Total: memInfo.ullTotalPhys,
Available: memInfo.ullAvailPhys,
UsedPercent: float64(memInfo.dwMemoryLoad),
}
ret.Used = ret.Total - ret.Available
return ret, nil
}
func SwapMemory() (*SwapMemoryStat, error) {
ret := &SwapMemoryStat{}
return ret, nil
}

37
vendor/github.com/shirou/gopsutil/mktypes.sh generated vendored Normal file
View File

@@ -0,0 +1,37 @@
DIRS="cpu disk docker host load mem net process"
GOOS=`uname | tr '[:upper:]' '[:lower:]'`
ARCH=`uname -m`
case $ARCH in
amd64)
GOARCH="amd64"
;;
x86_64)
GOARCH="amd64"
;;
i386)
GOARCH="386"
;;
i686)
GOARCH="386"
;;
arm)
GOARCH="arm"
;;
*)
echo "unknown arch: $ARCH"
exit 1
esac
for DIR in $DIRS
do
if [ -e ${DIR}/types_${GOOS}.go ]; then
echo "// +build $GOOS" > ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
echo "// +build $GOARCH" >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
go tool cgo -godefs ${DIR}/types_${GOOS}.go >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
fi
done

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

@@ -0,0 +1,246 @@
package net
import (
"encoding/json"
"fmt"
"net"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type IOCountersStat struct {
Name string `json:"name"` // interface name
BytesSent uint64 `json:"bytesSent"` // number of bytes sent
BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
PacketsSent uint64 `json:"packetsSent"` // number of packets sent
PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
Errin uint64 `json:"errin"` // total number of errors while receiving
Errout uint64 `json:"errout"` // total number of errors while sending
Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
}
// Addr is implemented compatibility to psutil
type Addr struct {
IP string `json:"ip"`
Port uint32 `json:"port"`
}
type ConnectionStat struct {
Fd uint32 `json:"fd"`
Family uint32 `json:"family"`
Type uint32 `json:"type"`
Laddr Addr `json:"localaddr"`
Raddr Addr `json:"remoteaddr"`
Status string `json:"status"`
Pid int32 `json:"pid"`
}
// System wide stats about different network protocols
type ProtoCountersStat struct {
Protocol string `json:"protocol"`
Stats map[string]int64 `json:"stats"`
}
// NetInterfaceAddr is designed for represent interface addresses
type InterfaceAddr struct {
Addr string `json:"addr"`
}
type InterfaceStat struct {
MTU int `json:"mtu"` // maximum transmission unit
Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100"
HardwareAddr string `json:"hardwareaddr"` // IEEE MAC-48, EUI-48 and EUI-64 form
Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast
Addrs []InterfaceAddr `json:"addrs"`
}
type FilterStat struct {
ConnTrackCount int64 `json:"conntrackCount"`
ConnTrackMax int64 `json:"conntrackMax"`
}
var constMap = map[string]int{
"TCP": syscall.SOCK_STREAM,
"UDP": syscall.SOCK_DGRAM,
"IPv4": syscall.AF_INET,
"IPv6": syscall.AF_INET6,
}
func (n IOCountersStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func (n ConnectionStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func (n ProtoCountersStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func (a Addr) String() string {
s, _ := json.Marshal(a)
return string(s)
}
func (n InterfaceStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func (n InterfaceAddr) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func Interfaces() ([]InterfaceStat, error) {
is, err := net.Interfaces()
if err != nil {
return nil, err
}
ret := make([]InterfaceStat, 0, len(is))
for _, ifi := range is {
var flags []string
if ifi.Flags&net.FlagUp != 0 {
flags = append(flags, "up")
}
if ifi.Flags&net.FlagBroadcast != 0 {
flags = append(flags, "broadcast")
}
if ifi.Flags&net.FlagLoopback != 0 {
flags = append(flags, "loopback")
}
if ifi.Flags&net.FlagPointToPoint != 0 {
flags = append(flags, "pointtopoint")
}
if ifi.Flags&net.FlagMulticast != 0 {
flags = append(flags, "multicast")
}
r := InterfaceStat{
Name: ifi.Name,
MTU: ifi.MTU,
HardwareAddr: ifi.HardwareAddr.String(),
Flags: flags,
}
addrs, err := ifi.Addrs()
if err == nil {
r.Addrs = make([]InterfaceAddr, 0, len(addrs))
for _, addr := range addrs {
r.Addrs = append(r.Addrs, InterfaceAddr{
Addr: addr.String(),
})
}
}
ret = append(ret, r)
}
return ret, nil
}
func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) {
r := IOCountersStat{
Name: "all",
}
for _, nic := range n {
r.BytesRecv += nic.BytesRecv
r.PacketsRecv += nic.PacketsRecv
r.Errin += nic.Errin
r.Dropin += nic.Dropin
r.BytesSent += nic.BytesSent
r.PacketsSent += nic.PacketsSent
r.Errout += nic.Errout
r.Dropout += nic.Dropout
}
return []IOCountersStat{r}, nil
}
func parseNetLine(line string) (ConnectionStat, error) {
f := strings.Fields(line)
if len(f) < 9 {
return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
}
pid, err := strconv.Atoi(f[1])
if err != nil {
return ConnectionStat{}, err
}
fd, err := strconv.Atoi(strings.Trim(f[3], "u"))
if err != nil {
return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3])
}
netFamily, ok := constMap[f[4]]
if !ok {
return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4])
}
netType, ok := constMap[f[7]]
if !ok {
return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7])
}
laddr, raddr, err := parseNetAddr(f[8])
if err != nil {
return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8])
}
n := ConnectionStat{
Fd: uint32(fd),
Family: uint32(netFamily),
Type: uint32(netType),
Laddr: laddr,
Raddr: raddr,
Pid: int32(pid),
}
if len(f) == 10 {
n.Status = strings.Trim(f[9], "()")
}
return n, nil
}
func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) {
parse := func(l string) (Addr, error) {
host, port, err := net.SplitHostPort(l)
if err != nil {
return Addr{}, fmt.Errorf("wrong addr, %s", l)
}
lport, err := strconv.Atoi(port)
if err != nil {
return Addr{}, err
}
return Addr{IP: host, Port: uint32(lport)}, nil
}
addrs := strings.Split(line, "->")
if len(addrs) == 0 {
return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line)
}
laddr, err = parse(addrs[0])
if len(addrs) == 2 { // remote addr exists
raddr, err = parse(addrs[1])
if err != nil {
return laddr, raddr, err
}
}
return laddr, raddr, err
}

114
vendor/github.com/shirou/gopsutil/net/net_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,114 @@
// +build darwin
package net
import (
"errors"
"os/exec"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
// example of netstat -idbn output on yosemite
// Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop
// lo0 16384 <Link#1> 869107 0 169411755 869107 0 169411755 0 0
// 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) {
netstat, err := exec.LookPath("/usr/sbin/netstat")
if err != nil {
return nil, err
}
out, err := invoke.Command(netstat, "-ibdnW")
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
ret := make([]IOCountersStat, 0, len(lines)-1)
exists := make([]string, 0, len(ret))
for _, line := range lines {
values := strings.Fields(line)
if len(values) < 1 || values[0] == "Name" {
// skip first line
continue
}
if common.StringsHas(exists, values[0]) {
// skip if already get
continue
}
exists = append(exists, values[0])
base := 1
// sometimes Address is ommitted
if len(values) < 11 {
base = 0
}
parsed := make([]uint64, 0, 7)
vv := []string{
values[base+3], // Ipkts == PacketsRecv
values[base+4], // Ierrs == Errin
values[base+5], // Ibytes == BytesRecv
values[base+6], // Opkts == PacketsSent
values[base+7], // Oerrs == Errout
values[base+8], // Obytes == BytesSent
}
if len(values) == 12 {
vv = append(vv, values[base+10])
}
for _, target := range vv {
if target == "-" {
parsed = append(parsed, 0)
continue
}
t, err := strconv.ParseUint(target, 10, 64)
if err != nil {
return nil, err
}
parsed = append(parsed, t)
}
n := IOCountersStat{
Name: values[0],
PacketsRecv: parsed[0],
Errin: parsed[1],
BytesRecv: parsed[2],
PacketsSent: parsed[3],
Errout: parsed[4],
BytesSent: parsed[5],
}
if len(parsed) == 7 {
n.Dropout = parsed[6]
}
ret = append(ret, n)
}
if pernic == false {
return getIOCountersAll(ret)
}
return ret, nil
}
// NetIOCountersByFile is an method which is added just a compatibility for linux.
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic)
}
func FilterCounters() ([]FilterStat, error) {
return nil, errors.New("NetFilterCounters not implemented for darwin")
}
// NetProtoCounters returns network statistics for the entire system
// If protocols is empty then all protocols are returned, otherwise
// just the protocols in the list are returned.
// Not Implemented for Darwin
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
return nil, errors.New("NetProtoCounters not implemented for darwin")
}

108
vendor/github.com/shirou/gopsutil/net/net_freebsd.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
// +build freebsd
package net
import (
"errors"
"os/exec"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
func IOCounters(pernic bool) ([]IOCountersStat, error) {
netstat, err := exec.LookPath("/usr/bin/netstat")
if err != nil {
return nil, err
}
out, err := invoke.Command(netstat, "-ibdnW")
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
ret := make([]IOCountersStat, 0, len(lines)-1)
exists := make([]string, 0, len(ret))
for _, line := range lines {
values := strings.Fields(line)
if len(values) < 1 || values[0] == "Name" {
continue
}
if common.StringsHas(exists, values[0]) {
// skip if already get
continue
}
exists = append(exists, values[0])
if len(values) < 12 {
continue
}
base := 1
// sometimes Address is ommitted
if len(values) < 13 {
base = 0
}
parsed := make([]uint64, 0, 8)
vv := []string{
values[base+3], // PacketsRecv
values[base+4], // Errin
values[base+5], // Dropin
values[base+6], // BytesRecvn
values[base+7], // PacketSent
values[base+8], // Errout
values[base+9], // BytesSent
values[base+11], // Dropout
}
for _, target := range vv {
if target == "-" {
parsed = append(parsed, 0)
continue
}
t, err := strconv.ParseUint(target, 10, 64)
if err != nil {
return nil, err
}
parsed = append(parsed, t)
}
n := IOCountersStat{
Name: values[0],
PacketsRecv: parsed[0],
Errin: parsed[1],
Dropin: parsed[2],
BytesRecv: parsed[3],
PacketsSent: parsed[4],
Errout: parsed[5],
BytesSent: parsed[6],
Dropout: parsed[7],
}
ret = append(ret, n)
}
if pernic == false {
return getIOCountersAll(ret)
}
return ret, nil
}
// NetIOCountersByFile is an method which is added just a compatibility for linux.
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic)
}
func FilterCounters() ([]FilterStat, error) {
return nil, errors.New("NetFilterCounters not implemented for freebsd")
}
// NetProtoCounters returns network statistics for the entire system
// If protocols is empty then all protocols are returned, otherwise
// just the protocols in the list are returned.
// Not Implemented for FreeBSD
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
return nil, errors.New("NetProtoCounters not implemented for freebsd")
}

630
vendor/github.com/shirou/gopsutil/net/net_linux.go generated vendored Normal file
View File

@@ -0,0 +1,630 @@
// +build linux
package net
import (
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
// NetIOCounters returnes network I/O statistics for every network
// interface installed on the system. If pernic argument is false,
// return only sum of all information (which name is 'all'). If true,
// every network interface installed on the system is returned
// separately.
func IOCounters(pernic bool) ([]IOCountersStat, error) {
filename := common.HostProc("net/dev")
return IOCountersByFile(pernic, filename)
}
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
lines, err := common.ReadLines(filename)
if err != nil {
return nil, err
}
statlen := len(lines) - 1
ret := make([]IOCountersStat, 0, statlen)
for _, line := range lines[2:] {
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
interfaceName := strings.TrimSpace(parts[0])
if interfaceName == "" {
continue
}
fields := strings.Fields(strings.TrimSpace(parts[1]))
bytesRecv, err := strconv.ParseUint(fields[0], 10, 64)
if err != nil {
return ret, err
}
packetsRecv, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
return ret, err
}
errIn, err := strconv.ParseUint(fields[2], 10, 64)
if err != nil {
return ret, err
}
dropIn, err := strconv.ParseUint(fields[3], 10, 64)
if err != nil {
return ret, err
}
fifoIn, err := strconv.ParseUint(fields[4], 10, 64)
if err != nil {
return ret, err
}
bytesSent, err := strconv.ParseUint(fields[8], 10, 64)
if err != nil {
return ret, err
}
packetsSent, err := strconv.ParseUint(fields[9], 10, 64)
if err != nil {
return ret, err
}
errOut, err := strconv.ParseUint(fields[10], 10, 64)
if err != nil {
return ret, err
}
dropOut, err := strconv.ParseUint(fields[13], 10, 64)
if err != nil {
return ret, err
}
fifoOut, err := strconv.ParseUint(fields[14], 10, 64)
if err != nil {
return ret, err
}
nic := IOCountersStat{
Name: interfaceName,
BytesRecv: bytesRecv,
PacketsRecv: packetsRecv,
Errin: errIn,
Dropin: dropIn,
Fifoin: fifoIn,
BytesSent: bytesSent,
PacketsSent: packetsSent,
Errout: errOut,
Dropout: dropOut,
Fifoout: fifoOut,
}
ret = append(ret, nic)
}
if pernic == false {
return getIOCountersAll(ret)
}
return ret, nil
}
var netProtocols = []string{
"ip",
"icmp",
"icmpmsg",
"tcp",
"udp",
"udplite",
}
// NetProtoCounters returns network statistics for the entire system
// If protocols is empty then all protocols are returned, otherwise
// just the protocols in the list are returned.
// Available protocols:
// ip,icmp,icmpmsg,tcp,udp,udplite
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
if len(protocols) == 0 {
protocols = netProtocols
}
stats := make([]ProtoCountersStat, 0, len(protocols))
protos := make(map[string]bool, len(protocols))
for _, p := range protocols {
protos[p] = true
}
filename := common.HostProc("net/snmp")
lines, err := common.ReadLines(filename)
if err != nil {
return nil, err
}
linecount := len(lines)
for i := 0; i < linecount; i++ {
line := lines[i]
r := strings.IndexRune(line, ':')
if r == -1 {
return nil, errors.New(filename + " is not fomatted correctly, expected ':'.")
}
proto := strings.ToLower(line[:r])
if !protos[proto] {
// skip protocol and data line
i++
continue
}
// Read header line
statNames := strings.Split(line[r+2:], " ")
// Read data line
i++
statValues := strings.Split(lines[i][r+2:], " ")
if len(statNames) != len(statValues) {
return nil, errors.New(filename + " is not fomatted correctly, expected same number of columns.")
}
stat := ProtoCountersStat{
Protocol: proto,
Stats: make(map[string]int64, len(statNames)),
}
for j := range statNames {
value, err := strconv.ParseInt(statValues[j], 10, 64)
if err != nil {
return nil, err
}
stat.Stats[statNames[j]] = value
}
stats = append(stats, stat)
}
return stats, nil
}
// NetFilterCounters returns iptables conntrack statistics
// 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) {
countfile := common.HostProc("sys/net/netfilter/nf_conntrackCount")
maxfile := common.HostProc("sys/net/netfilter/nf_conntrackMax")
count, err := common.ReadInts(countfile)
if err != nil {
return nil, err
}
stats := make([]FilterStat, 0, 1)
max, err := common.ReadInts(maxfile)
if err != nil {
return nil, err
}
payload := FilterStat{
ConnTrackCount: count[0],
ConnTrackMax: max[0],
}
stats = append(stats, payload)
return stats, nil
}
// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
var TCPStatuses = map[string]string{
"01": "ESTABLISHED",
"02": "SYN_SENT",
"03": "SYN_RECV",
"04": "FIN_WAIT1",
"05": "FIN_WAIT2",
"06": "TIME_WAIT",
"07": "CLOSE",
"08": "CLOSE_WAIT",
"09": "LAST_ACK",
"0A": "LISTEN",
"0B": "CLOSING",
}
type netConnectionKindType struct {
family uint32
sockType uint32
filename string
}
var kindTCP4 = netConnectionKindType{
family: syscall.AF_INET,
sockType: syscall.SOCK_STREAM,
filename: "tcp",
}
var kindTCP6 = netConnectionKindType{
family: syscall.AF_INET6,
sockType: syscall.SOCK_STREAM,
filename: "tcp6",
}
var kindUDP4 = netConnectionKindType{
family: syscall.AF_INET,
sockType: syscall.SOCK_DGRAM,
filename: "udp",
}
var kindUDP6 = netConnectionKindType{
family: syscall.AF_INET6,
sockType: syscall.SOCK_DGRAM,
filename: "udp6",
}
var kindUNIX = netConnectionKindType{
family: syscall.AF_UNIX,
filename: "unix",
}
var netConnectionKindMap = map[string][]netConnectionKindType{
"all": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
"tcp": []netConnectionKindType{kindTCP4, kindTCP6},
"tcp4": []netConnectionKindType{kindTCP4},
"tcp6": []netConnectionKindType{kindTCP6},
"udp": []netConnectionKindType{kindUDP4, kindUDP6},
"udp4": []netConnectionKindType{kindUDP4},
"udp6": []netConnectionKindType{kindUDP6},
"unix": []netConnectionKindType{kindUNIX},
"inet": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6},
"inet4": []netConnectionKindType{kindTCP4, kindUDP4},
"inet6": []netConnectionKindType{kindTCP6, kindUDP6},
}
type inodeMap struct {
pid int32
fd uint32
}
type connTmp struct {
fd uint32
family uint32
sockType uint32
laddr Addr
raddr Addr
status string
pid int32
boundPid int32
path string
}
// Return a list of network connections opened.
func Connections(kind string) ([]ConnectionStat, error) {
return ConnectionsPid(kind, 0)
}
// Return a list of network connections opened by a process.
func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
tmap, ok := netConnectionKindMap[kind]
if !ok {
return nil, fmt.Errorf("invalid kind, %s", kind)
}
root := common.HostProc()
var err error
var inodes map[string][]inodeMap
if pid == 0 {
inodes, err = getProcInodesAll(root)
} else {
inodes, err = getProcInodes(root, pid)
if len(inodes) == 0 {
// no connection for the pid
return []ConnectionStat{}, nil
}
}
if err != nil {
return nil, fmt.Errorf("cound not get pid(s), %d", pid)
}
dupCheckMap := make(map[string]bool)
var ret []ConnectionStat
for _, t := range tmap {
var path string
var ls []connTmp
path = fmt.Sprintf("%s/net/%s", root, t.filename)
switch t.family {
case syscall.AF_INET:
fallthrough
case syscall.AF_INET6:
ls, err = processInet(path, t, inodes, pid)
case syscall.AF_UNIX:
ls, err = processUnix(path, t, inodes, pid)
}
if err != nil {
return nil, err
}
for _, c := range ls {
conn := ConnectionStat{
Fd: c.fd,
Family: c.family,
Type: c.sockType,
Laddr: c.laddr,
Raddr: c.raddr,
Status: c.status,
Pid: c.pid,
}
if c.pid == 0 {
conn.Pid = c.boundPid
} else {
conn.Pid = c.pid
}
// check duplicate using JSON format
json := conn.String()
_, exists := dupCheckMap[json]
if !exists {
ret = append(ret, conn)
dupCheckMap[json] = true
}
}
}
return ret, nil
}
// getProcInodes returnes fd of the pid.
func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) {
ret := make(map[string][]inodeMap)
dir := fmt.Sprintf("%s/%d/fd", root, pid)
files, err := ioutil.ReadDir(dir)
if err != nil {
return ret, nil
}
for _, fd := range files {
inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, fd.Name())
inode, err := os.Readlink(inodePath)
if err != nil {
continue
}
if !strings.HasPrefix(inode, "socket:[") {
continue
}
// the process is using a socket
l := len(inode)
inode = inode[8 : l-1]
_, ok := ret[inode]
if !ok {
ret[inode] = make([]inodeMap, 0)
}
fd, err := strconv.Atoi(fd.Name())
if err != nil {
continue
}
i := inodeMap{
pid: pid,
fd: uint32(fd),
}
ret[inode] = append(ret[inode], i)
}
return ret, nil
}
// Pids retunres all pids.
// Note: this is a copy of process_linux.Pids()
// FIXME: Import process occures import cycle.
// move to common made other platform breaking. Need consider.
func Pids() ([]int32, error) {
var ret []int32
d, err := os.Open(common.HostProc())
if err != nil {
return nil, err
}
defer d.Close()
fnames, err := d.Readdirnames(-1)
if err != nil {
return nil, err
}
for _, fname := range fnames {
pid, err := strconv.ParseInt(fname, 10, 32)
if err != nil {
// if not numeric name, just skip
continue
}
ret = append(ret, int32(pid))
}
return ret, nil
}
func getProcInodesAll(root string) (map[string][]inodeMap, error) {
pids, err := Pids()
if err != nil {
return nil, err
}
ret := make(map[string][]inodeMap)
for _, pid := range pids {
t, err := getProcInodes(root, pid)
if err != nil {
return ret, err
}
if len(t) == 0 {
continue
}
// TODO: update ret.
ret = updateMap(ret, t)
}
return ret, nil
}
// decodeAddress decode addresse represents addr in proc/net/*
// ex:
// "0500000A:0016" -> "10.0.0.5", 22
// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53
func decodeAddress(family uint32, src string) (Addr, error) {
t := strings.Split(src, ":")
if len(t) != 2 {
return Addr{}, fmt.Errorf("does not contain port, %s", src)
}
addr := t[0]
port, err := strconv.ParseInt("0x"+t[1], 0, 64)
if err != nil {
return Addr{}, fmt.Errorf("invalid port, %s", src)
}
decoded, err := hex.DecodeString(addr)
if err != nil {
return Addr{}, fmt.Errorf("decode error, %s", err)
}
var ip net.IP
// Assumes this is little_endian
if family == syscall.AF_INET {
ip = net.IP(Reverse(decoded))
} else { // IPv6
ip, err = parseIPv6HexString(decoded)
if err != nil {
return Addr{}, err
}
}
return Addr{
IP: ip.String(),
Port: uint32(port),
}, nil
}
// Reverse reverses array of bytes.
func Reverse(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]
}
return s
}
// parseIPv6HexString parse array of bytes to IPv6 string
func parseIPv6HexString(src []byte) (net.IP, error) {
if len(src) != 16 {
return nil, fmt.Errorf("invalid IPv6 string")
}
buf := make([]byte, 0, 16)
for i := 0; i < len(src); i += 4 {
r := Reverse(src[i : i+4])
buf = append(buf, r...)
}
return net.IP(buf), nil
}
func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
if strings.HasSuffix(file, "6") && !common.PathExists(file) {
// IPv6 not supported, return empty.
return []connTmp{}, nil
}
lines, err := common.ReadLines(file)
if err != nil {
return nil, err
}
var ret []connTmp
// skip first line
for _, line := range lines[1:] {
l := strings.Fields(line)
if len(l) < 10 {
continue
}
laddr := l[1]
raddr := l[2]
status := l[3]
inode := l[9]
pid := int32(0)
fd := uint32(0)
i, exists := inodes[inode]
if exists {
pid = i[0].pid
fd = i[0].fd
}
if filterPid > 0 && filterPid != pid {
continue
}
if kind.sockType == syscall.SOCK_STREAM {
status = TCPStatuses[status]
} else {
status = "NONE"
}
la, err := decodeAddress(kind.family, laddr)
if err != nil {
continue
}
ra, err := decodeAddress(kind.family, raddr)
if err != nil {
continue
}
ret = append(ret, connTmp{
fd: fd,
family: kind.family,
sockType: kind.sockType,
laddr: la,
raddr: ra,
status: status,
pid: pid,
})
}
return ret, nil
}
func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
lines, err := common.ReadLines(file)
if err != nil {
return nil, err
}
var ret []connTmp
// skip first line
for _, line := range lines[1:] {
tokens := strings.Fields(line)
if len(tokens) < 6 {
continue
}
st, err := strconv.Atoi(tokens[4])
if err != nil {
return nil, err
}
inode := tokens[6]
var pairs []inodeMap
pairs, exists := inodes[inode]
if !exists {
pairs = []inodeMap{
inodeMap{},
}
}
for _, pair := range pairs {
if filterPid > 0 && filterPid != pair.pid {
continue
}
var path string
if len(tokens) == 8 {
path = tokens[len(tokens)-1]
}
ret = append(ret, connTmp{
fd: pair.fd,
family: kind.family,
sockType: uint32(st),
laddr: Addr{
IP: path,
},
pid: pair.pid,
status: "NONE",
path: path,
})
}
}
return ret, nil
}
func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap {
for key, value := range add {
a, exists := src[key]
if !exists {
src[key] = value
continue
}
src[key] = append(a, value...)
}
return src
}

View File

@@ -0,0 +1,75 @@
package net
import (
"os"
"syscall"
"testing"
"github.com/shirou/gopsutil/internal/common"
"github.com/stretchr/testify/assert"
)
func TestGetProcInodesAll(t *testing.T) {
if os.Getenv("CIRCLECI") == "true" {
t.Skip("Skip CI")
}
root := common.HostProc("")
v, err := getProcInodesAll(root)
assert.Nil(t, err)
assert.NotEmpty(t, v)
}
type AddrTest struct {
IP string
Port int
Error bool
}
func TestDecodeAddress(t *testing.T) {
assert := assert.New(t)
addr := map[string]AddrTest{
"0500000A:0016": AddrTest{
IP: "10.0.0.5",
Port: 22,
},
"0100007F:D1C2": AddrTest{
IP: "127.0.0.1",
Port: 53698,
},
"11111:0035": AddrTest{
Error: true,
},
"0100007F:BLAH": AddrTest{
Error: true,
},
"0085002452100113070057A13F025401:0035": AddrTest{
IP: "2400:8500:1301:1052:a157:7:154:23f",
Port: 53,
},
"00855210011307F025401:0035": AddrTest{
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))
}

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

@@ -0,0 +1,228 @@
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,
}
e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","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{
IOCountersStat{
Name: "a",
BytesRecv: 10,
PacketsRecv: 10,
},
IOCountersStat{
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)
}
}
}

68
vendor/github.com/shirou/gopsutil/net/net_unix.go generated vendored Normal file
View File

@@ -0,0 +1,68 @@
// +build freebsd darwin
package net
import (
"strings"
"github.com/shirou/gopsutil/internal/common"
)
// Return a list of network connections opened.
func Connections(kind string) ([]ConnectionStat, error) {
return ConnectionsPid(kind, 0)
}
// Return a list of network connections opened by a process.
func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
var ret []ConnectionStat
args := []string{"-i"}
switch strings.ToLower(kind) {
default:
fallthrough
case "":
fallthrough
case "all":
fallthrough
case "inet":
args = append(args, "tcp", "-i", "udp")
case "inet4":
args = append(args, "4")
case "inet6":
args = append(args, "6")
case "tcp":
args = append(args, "tcp")
case "tcp4":
args = append(args, "4tcp")
case "tcp6":
args = append(args, "6tcp")
case "udp":
args = append(args, "udp")
case "udp4":
args = append(args, "6udp")
case "udp6":
args = append(args, "6udp")
case "unix":
return ret, common.ErrNotImplementedError
}
r, err := common.CallLsof(invoke, pid, args...)
if err != nil {
return nil, err
}
for _, rr := range r {
if strings.HasPrefix(rr, "COMMAND") {
continue
}
n, err := parseNetLine(rr)
if err != nil {
continue
}
ret = append(ret, n)
}
return ret, nil
}

116
vendor/github.com/shirou/gopsutil/net/net_windows.go generated vendored Normal file
View File

@@ -0,0 +1,116 @@
// +build windows
package net
import (
"errors"
"net"
"os"
"syscall"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
)
var (
modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable")
procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable")
)
const (
TCPTableBasicListener = iota
TCPTableBasicConnections
TCPTableBasicAll
TCPTableOwnerPIDListener
TCPTableOwnerPIDConnections
TCPTableOwnerPIDAll
TCPTableOwnerModuleListener
TCPTableOwnerModuleConnections
TCPTableOwnerModuleAll
)
func IOCounters(pernic bool) ([]IOCountersStat, error) {
ifs, err := net.Interfaces()
if err != nil {
return nil, err
}
ai, err := getAdapterList()
if err != nil {
return nil, err
}
var ret []IOCountersStat
for _, ifi := range ifs {
name := ifi.Name
for ; ai != nil; ai = ai.Next {
name = common.BytePtrToString(&ai.Description[0])
c := IOCountersStat{
Name: name,
}
row := syscall.MibIfRow{Index: ai.Index}
e := syscall.GetIfEntry(&row)
if e != nil {
return nil, os.NewSyscallError("GetIfEntry", e)
}
c.BytesSent = uint64(row.OutOctets)
c.BytesRecv = uint64(row.InOctets)
c.PacketsSent = uint64(row.OutUcastPkts)
c.PacketsRecv = uint64(row.InUcastPkts)
c.Errin = uint64(row.InErrors)
c.Errout = uint64(row.OutErrors)
c.Dropin = uint64(row.InDiscards)
c.Dropout = uint64(row.OutDiscards)
ret = append(ret, c)
}
}
if pernic == false {
return getIOCountersAll(ret)
}
return ret, nil
}
// NetIOCountersByFile is an method which is added just a compatibility for linux.
func IOCountersByFile(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) {
var ret []ConnectionStat
return ret, common.ErrNotImplementedError
}
// borrowed from src/pkg/net/interface_windows.go
func getAdapterList() (*syscall.IpAdapterInfo, error) {
b := make([]byte, 1000)
l := uint32(len(b))
a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
err := syscall.GetAdaptersInfo(a, &l)
if err == syscall.ERROR_BUFFER_OVERFLOW {
b = make([]byte, l)
a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
err = syscall.GetAdaptersInfo(a, &l)
}
if err != nil {
return nil, os.NewSyscallError("GetAdaptersInfo", err)
}
return a, nil
}
func FilterCounters() ([]FilterStat, error) {
return nil, errors.New("NetFilterCounters not implemented for windows")
}
// NetProtoCounters returns network statistics for the entire system
// If protocols is empty then all protocols are returned, otherwise
// just the protocols in the list are returned.
// Not Implemented for Windows
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
return nil, errors.New("NetProtoCounters not implemented for windows")
}

View File

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

167
vendor/github.com/shirou/gopsutil/process/process.go generated vendored Normal file
View File

@@ -0,0 +1,167 @@
package process
import (
"encoding/json"
"runtime"
"time"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/mem"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type Process struct {
Pid int32 `json:"pid"`
name string
status string
parent int32
numCtxSwitches *NumCtxSwitchesStat
uids []int32
gids []int32
numThreads int32
memInfo *MemoryInfoStat
lastCPUTimes *cpu.TimesStat
lastCPUTime time.Time
}
type OpenFilesStat struct {
Path string `json:"path"`
Fd uint64 `json:"fd"`
}
type MemoryInfoStat struct {
RSS uint64 `json:"rss"` // bytes
VMS uint64 `json:"vms"` // bytes
Swap uint64 `json:"swap"` // bytes
}
type RlimitStat struct {
Resource int32 `json:"resource"`
Soft int32 `json:"soft"`
Hard int32 `json:"hard"`
}
type IOCountersStat struct {
ReadCount uint64 `json:"readCount"`
WriteCount uint64 `json:"writeCount"`
ReadBytes uint64 `json:"readBytes"`
WriteBytes uint64 `json:"writeBytes"`
}
type NumCtxSwitchesStat struct {
Voluntary int64 `json:"voluntary"`
Involuntary int64 `json:"involuntary"`
}
func (p Process) String() string {
s, _ := json.Marshal(p)
return string(s)
}
func (o OpenFilesStat) String() string {
s, _ := json.Marshal(o)
return string(s)
}
func (m MemoryInfoStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
func (r RlimitStat) String() string {
s, _ := json.Marshal(r)
return string(s)
}
func (i IOCountersStat) String() string {
s, _ := json.Marshal(i)
return string(s)
}
func (p NumCtxSwitchesStat) String() string {
s, _ := json.Marshal(p)
return string(s)
}
func PidExists(pid int32) (bool, error) {
pids, err := Pids()
if err != nil {
return false, err
}
for _, i := range pids {
if i == pid {
return true, err
}
}
return false, err
}
// If interval is 0, return difference from last call(non-blocking).
// If interval > 0, wait interval sec and return diffrence between start and end.
func (p *Process) Percent(interval time.Duration) (float64, error) {
cpuTimes, err := p.Times()
if err != nil {
return 0, err
}
now := time.Now()
if interval > 0 {
p.lastCPUTimes = cpuTimes
p.lastCPUTime = now
time.Sleep(interval)
cpuTimes, err = p.Times()
now = time.Now()
if err != nil {
return 0, err
}
} else {
if p.lastCPUTimes == nil {
// invoked first time
p.lastCPUTimes = cpuTimes
p.lastCPUTime = now
return 0, nil
}
}
numcpu := runtime.NumCPU()
delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
p.lastCPUTimes = cpuTimes
p.lastCPUTime = now
return ret, nil
}
func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
if delta == 0 {
return 0
}
delta_proc := t2.Total() - t1.Total()
overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
return overall_percent
}
// MemoryPercent returns how many percent of the total RAM this process uses
func (p *Process) MemoryPercent() (float32, error) {
machineMemory, err := mem.VirtualMemory()
if err != nil {
return 0, err
}
total := machineMemory.Total
processMemory, err := p.MemoryInfo()
if err != nil {
return 0, err
}
used := processMemory.RSS
return (100 * float32(used) / float32(total)), nil
}

View File

@@ -0,0 +1,451 @@
// +build darwin
package process
import (
"bytes"
"encoding/binary"
"fmt"
"os/exec"
"strconv"
"strings"
"syscall"
"unsafe"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/net"
)
// copied from sys/sysctl.h
const (
CTLKern = 1 // "high kernel": proc, limits
KernProc = 14 // struct: process entries
KernProcPID = 1 // by process id
KernProcProc = 8 // only return procs
KernProcAll = 0 // everything
KernProcPathname = 12 // path to executable
)
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
)
type _Ctype_struct___0 struct {
Pad uint64
}
// MemoryInfoExStat is different between OSes
type MemoryInfoExStat struct {
}
type MemoryMapsStat struct {
}
func Pids() ([]int32, error) {
var ret []int32
pids, err := callPs("pid", 0, false)
if err != nil {
return ret, err
}
for _, pid := range pids {
v, err := strconv.Atoi(pid[0])
if err != nil {
return ret, err
}
ret = append(ret, int32(v))
}
return ret, nil
}
func (p *Process) Ppid() (int32, error) {
r, err := callPs("ppid", p.Pid, false)
v, err := strconv.Atoi(r[0][0])
if err != nil {
return 0, err
}
return int32(v), err
}
func (p *Process) Name() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
return common.IntToString(k.Proc.P_comm[:]), nil
}
func (p *Process) Exe() (string, error) {
return "", common.ErrNotImplementedError
}
// Cmdline returns the command line arguments of the process as a string with
// each argument separated by 0x20 ascii character.
func (p *Process) Cmdline() (string, error) {
r, err := callPs("command", p.Pid, false)
if err != nil {
return "", err
}
return strings.Join(r[0], " "), err
}
// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument. Because of current deficiencies in the way that the command
// line arguments are found, single arguments that have spaces in the will actually be
// reported as two separate items. In order to do something better CGO would be needed
// to use the native darwin functions.
func (p *Process) CmdlineSlice() ([]string, error) {
r, err := callPs("command", p.Pid, false)
if err != nil {
return nil, err
}
return r[0], err
}
func (p *Process) CreateTime() (int64, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Cwd() (string, error) {
return "", common.ErrNotImplementedError
}
func (p *Process) Parent() (*Process, error) {
rr, err := common.CallLsof(invoke, p.Pid, "-FR")
if err != nil {
return nil, err
}
for _, r := range rr {
if strings.HasPrefix(r, "p") { // skip if process
continue
}
l := string(r)
v, err := strconv.Atoi(strings.Replace(l, "R", "", 1))
if err != nil {
return nil, err
}
return NewProcess(int32(v))
}
return nil, fmt.Errorf("could not find parent line")
}
func (p *Process) Status() (string, error) {
r, err := callPs("state", p.Pid, false)
if err != nil {
return "", err
}
return r[0][0], err
}
func (p *Process) Uids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
// See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html
userEffectiveUID := int32(k.Eproc.Ucred.UID)
return []int32{userEffectiveUID}, nil
}
func (p *Process) Gids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
gids := make([]int32, 0, 3)
gids = append(gids, int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Ucred.Ngroups), int32(k.Eproc.Pcred.P_svgid))
return gids, nil
}
func (p *Process) Terminal() (string, error) {
return "", common.ErrNotImplementedError
/*
k, err := p.getKProc()
if err != nil {
return "", err
}
ttyNr := uint64(k.Eproc.Tdev)
termmap, err := getTerminalMap()
if err != nil {
return "", err
}
return termmap[ttyNr], nil
*/
}
func (p *Process) Nice() (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return int32(k.Proc.P_nice), nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.ErrNotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
r, err := callPs("utime,stime", p.Pid, true)
if err != nil {
return 0, err
}
return int32(len(r)), nil
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.ErrNotImplementedError
}
func convertCPUTimes(s string) (ret float64, err error) {
var t int
var _tmp string
if strings.Contains(s, ":") {
_t := strings.Split(s, ":")
hour, err := strconv.Atoi(_t[0])
if err != nil {
return ret, err
}
t += hour * 60 * 100
_tmp = _t[1]
} else {
_tmp = s
}
_t := strings.Split(_tmp, ".")
if err != nil {
return ret, err
}
h, err := strconv.Atoi(_t[0])
t += h * 100
h, err = strconv.Atoi(_t[1])
t += h
return float64(t) / ClockTicks, nil
}
func (p *Process) Times() (*cpu.TimesStat, error) {
r, err := callPs("utime,stime", p.Pid, false)
if err != nil {
return nil, err
}
utime, err := convertCPUTimes(r[0][0])
if err != nil {
return nil, err
}
stime, err := convertCPUTimes(r[0][1])
if err != nil {
return nil, err
}
ret := &cpu.TimesStat{
CPU: "cpu",
User: utime,
System: stime,
}
return ret, nil
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
r, err := callPs("rss,vsize,pagein", p.Pid, false)
if err != nil {
return nil, err
}
rss, err := strconv.Atoi(r[0][0])
if err != nil {
return nil, err
}
vms, err := strconv.Atoi(r[0][1])
if err != nil {
return nil, err
}
pagein, err := strconv.Atoi(r[0][2])
if err != nil {
return nil, err
}
ret := &MemoryInfoStat{
RSS: uint64(rss) * 1024,
VMS: uint64(vms) * 1024,
Swap: uint64(pagein),
}
return ret, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
pids, err := common.CallPgrep(invoke, p.Pid)
if err != nil {
return nil, err
}
ret := make([]*Process, 0, len(pids))
for _, pid := range pids {
np, err := NewProcess(pid)
if err != nil {
return nil, err
}
ret = append(ret, np)
}
return ret, nil
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) Connections() ([]net.ConnectionStat, error) {
return net.ConnectionsPid("all", p.Pid)
}
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
var ret []MemoryMapsStat
return &ret, common.ErrNotImplementedError
}
func processes() ([]Process, error) {
results := make([]Process, 0, 50)
mib := []int32{CTLKern, KernProc, KernProcAll, 0}
buf, length, err := common.CallSyscall(mib)
if err != nil {
return results, err
}
// get kinfo_proc size
k := KinfoProc{}
procinfoLen := int(unsafe.Sizeof(k))
count := int(length / uint64(procinfoLen))
/*
fmt.Println(length, procinfoLen, count)
b := buf[0*procinfoLen : 0*procinfoLen+procinfoLen]
fmt.Println(b)
kk, err := parseKinfoProc(b)
fmt.Printf("%#v", kk)
*/
// parse buf to procs
for i := 0; i < count; i++ {
b := buf[i*procinfoLen : i*procinfoLen+procinfoLen]
k, err := parseKinfoProc(b)
if err != nil {
continue
}
p, err := NewProcess(int32(k.Proc.P_pid))
if err != nil {
continue
}
results = append(results, *p)
}
return results, nil
}
func parseKinfoProc(buf []byte) (KinfoProc, error) {
var k KinfoProc
br := bytes.NewReader(buf)
err := common.Read(br, binary.LittleEndian, &k)
if err != nil {
return k, err
}
return k, nil
}
// Returns a proc as defined here:
// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html
func (p *Process) getKProc() (*KinfoProc, error) {
mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
procK := KinfoProc{}
length := uint64(unsafe.Sizeof(procK))
buf := make([]byte, length)
_, _, syserr := syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(len(mib)),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&length)),
0,
0)
if syserr != 0 {
return nil, syserr
}
k, err := parseKinfoProc(buf)
if err != nil {
return nil, err
}
return &k, nil
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}
// call ps command.
// Return value deletes Header line(you must not input wrong arg).
// And splited by Space. Caller have responsibility to manage.
// If passed arg pid is 0, get information from all process.
func callPs(arg string, pid int32, threadOption bool) ([][]string, error) {
bin, err := exec.LookPath("ps")
if err != nil {
return [][]string{}, err
}
var cmd []string
if pid == 0 { // will get from all processes.
cmd = []string{"-ax", "-o", arg}
} else if threadOption {
cmd = []string{"-x", "-o", arg, "-M", "-p", strconv.Itoa(int(pid))}
} else {
cmd = []string{"-x", "-o", arg, "-p", strconv.Itoa(int(pid))}
}
out, err := invoke.Command(bin, cmd...)
if err != nil {
return [][]string{}, err
}
lines := strings.Split(string(out), "\n")
var ret [][]string
for _, l := range lines[1:] {
var lr []string
for _, r := range strings.Split(l, " ") {
if r == "" {
continue
}
lr = append(lr, strings.TrimSpace(r))
}
if len(lr) != 0 {
ret = append(ret, lr)
}
}
return ret, nil
}

View File

@@ -0,0 +1,234 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_darwin.go
package process
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type Timespec struct {
Sec int64
Nsec int64
}
type Timeval struct {
Sec int64
Usec int32
Pad_cgo_0 [4]byte
}
type Rusage struct {
Utime Timeval
Stime Timeval
Maxrss int64
Ixrss int64
Idrss int64
Isrss int64
Minflt int64
Majflt int64
Nswap int64
Inblock int64
Oublock int64
Msgsnd int64
Msgrcv int64
Nsignals int64
Nvcsw int64
Nivcsw int64
}
type Rlimit struct {
Cur uint64
Max uint64
}
type UGid_t uint32
type KinfoProc struct {
Proc ExternProc
Eproc Eproc
}
type Eproc struct {
Paddr *uint64
Sess *Session
Pcred Upcred
Ucred Uucred
Pad_cgo_0 [4]byte
Vm Vmspace
Ppid int32
Pgid int32
Jobc int16
Pad_cgo_1 [2]byte
Tdev int32
Tpgid int32
Pad_cgo_2 [4]byte
Tsess *Session
Wmesg [8]int8
Xsize int32
Xrssize int16
Xccount int16
Xswrss int16
Pad_cgo_3 [2]byte
Flag int32
Login [12]int8
Spare [4]int32
Pad_cgo_4 [4]byte
}
type Proc struct{}
type Session struct{}
type ucred struct {
Link _Ctype_struct___0
Ref uint64
Posix Posix_cred
Label *Label
Audit Au_session
}
type Uucred struct {
Ref int32
UID uint32
Ngroups int16
Pad_cgo_0 [2]byte
Groups [16]uint32
}
type Upcred struct {
Pc_lock [72]int8
Pc_ucred *ucred
P_ruid uint32
P_svuid uint32
P_rgid uint32
P_svgid uint32
P_refcnt int32
Pad_cgo_0 [4]byte
}
type Vmspace struct {
Dummy int32
Pad_cgo_0 [4]byte
Dummy2 *int8
Dummy3 [5]int32
Pad_cgo_1 [4]byte
Dummy4 [3]*int8
}
type Sigacts struct{}
type ExternProc struct {
P_un [16]byte
P_vmspace uint64
P_sigacts uint64
Pad_cgo_0 [3]byte
P_flag int32
P_stat int8
P_pid int32
P_oppid int32
P_dupfd int32
Pad_cgo_1 [4]byte
User_stack uint64
Exit_thread uint64
P_debugger int32
Sigwait int32
P_estcpu uint32
P_cpticks int32
P_pctcpu uint32
Pad_cgo_2 [4]byte
P_wchan uint64
P_wmesg uint64
P_swtime uint32
P_slptime uint32
P_realtimer Itimerval
P_rtime Timeval
P_uticks uint64
P_sticks uint64
P_iticks uint64
P_traceflag int32
Pad_cgo_3 [4]byte
P_tracep uint64
P_siglist int32
Pad_cgo_4 [4]byte
P_textvp uint64
P_holdcnt int32
P_sigmask uint32
P_sigignore uint32
P_sigcatch uint32
P_priority uint8
P_usrpri uint8
P_nice int8
P_comm [17]int8
Pad_cgo_5 [4]byte
P_pgrp uint64
P_addr uint64
P_xstat uint16
P_acflag uint16
Pad_cgo_6 [4]byte
P_ru uint64
}
type Itimerval struct {
Interval Timeval
Value Timeval
}
type Vnode struct{}
type Pgrp struct{}
type UserStruct struct{}
type Au_session struct {
Aia_p *AuditinfoAddr
Mask AuMask
}
type Posix_cred struct {
UID uint32
Ruid uint32
Svuid uint32
Ngroups int16
Pad_cgo_0 [2]byte
Groups [16]uint32
Rgid uint32
Svgid uint32
Gmuid uint32
Flags int32
}
type Label struct{}
type AuditinfoAddr struct {
Auid uint32
Mask AuMask
Termid AuTidAddr
Asid int32
Flags uint64
}
type AuMask struct {
Success uint32
Failure uint32
}
type AuTidAddr struct {
Port int32
Type uint32
Addr [4]uint32
}
type UcredQueue struct {
Next *ucred
Prev **ucred
}

View File

@@ -0,0 +1,336 @@
// +build freebsd
package process
import (
"bytes"
"encoding/binary"
"strings"
"syscall"
cpu "github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/internal/common"
net "github.com/shirou/gopsutil/net"
)
// MemoryInfoExStat is different between OSes
type MemoryInfoExStat struct {
}
type MemoryMapsStat struct {
}
func Pids() ([]int32, error) {
var ret []int32
procs, err := processes()
if err != nil {
return ret, nil
}
for _, p := range procs {
ret = append(ret, p.Pid)
}
return ret, nil
}
func (p *Process) Ppid() (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return k.Ppid, nil
}
func (p *Process) Name() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
return common.IntToString(k.Comm[:]), nil
}
func (p *Process) Exe() (string, error) {
return "", common.ErrNotImplementedError
}
func (p *Process) Cmdline() (string, error) {
mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return "", err
}
ret := strings.FieldsFunc(string(buf), func(r rune) bool {
if r == '\u0000' {
return true
}
return false
})
return strings.Join(ret, " "), nil
}
func (p *Process) CmdlineSlice() ([]string, error) {
mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return nil, err
}
if len(buf) == 0 {
return nil, nil
}
if buf[len(buf)-1] == 0 {
buf = buf[:len(buf)-1]
}
parts := bytes.Split(buf, []byte{0})
var strParts []string
for _, p := range parts {
strParts = append(strParts, string(p))
}
return strParts, nil
}
func (p *Process) CreateTime() (int64, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Cwd() (string, error) {
return "", common.ErrNotImplementedError
}
func (p *Process) Parent() (*Process, error) {
return p, common.ErrNotImplementedError
}
func (p *Process) Status() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
var s string
switch k.Stat {
case SIDL:
s = "I"
case SRUN:
s = "R"
case SSLEEP:
s = "S"
case SSTOP:
s = "T"
case SZOMB:
s = "Z"
case SWAIT:
s = "W"
case SLOCK:
s = "L"
}
return s, nil
}
func (p *Process) Uids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
uids := make([]int32, 0, 3)
uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
return uids, nil
}
func (p *Process) Gids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
gids := make([]int32, 0, 3)
gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
return gids, nil
}
func (p *Process) Terminal() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
ttyNr := uint64(k.Tdev)
termmap, err := getTerminalMap()
if err != nil {
return "", err
}
return termmap[ttyNr], nil
}
func (p *Process) Nice() (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return int32(k.Nice), nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.ErrNotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
return &IOCountersStat{
ReadCount: uint64(k.Rusage.Inblock),
WriteCount: uint64(k.Rusage.Oublock),
}, nil
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return k.Numthreads, nil
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.ErrNotImplementedError
}
func (p *Process) Times() (*cpu.TimesStat, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
return &cpu.TimesStat{
CPU: "cpu",
User: float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,
System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,
}, nil
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
v, err := syscall.Sysctl("vm.stats.vm.v_page_size")
if err != nil {
return nil, err
}
pageSize := common.LittleEndian.Uint16([]byte(v))
return &MemoryInfoStat{
RSS: uint64(k.Rssize) * uint64(pageSize),
VMS: uint64(k.Size),
}, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
pids, err := common.CallPgrep(invoke, p.Pid)
if err != nil {
return nil, err
}
ret := make([]*Process, 0, len(pids))
for _, pid := range pids {
np, err := NewProcess(pid)
if err != nil {
return nil, err
}
ret = append(ret, np)
}
return ret, nil
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) Connections() ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
var ret []MemoryMapsStat
return &ret, common.ErrNotImplementedError
}
func processes() ([]Process, error) {
results := make([]Process, 0, 50)
mib := []int32{CTLKern, KernProc, KernProcProc, 0}
buf, length, err := common.CallSyscall(mib)
if err != nil {
return results, err
}
// get kinfo_proc size
count := int(length / uint64(sizeOfKinfoProc))
// parse buf to procs
for i := 0; i < count; i++ {
b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
k, err := parseKinfoProc(b)
if err != nil {
continue
}
p, err := NewProcess(int32(k.Pid))
if err != nil {
continue
}
results = append(results, *p)
}
return results, nil
}
func parseKinfoProc(buf []byte) (KinfoProc, error) {
var k KinfoProc
br := bytes.NewReader(buf)
err := common.Read(br, binary.LittleEndian, &k)
return k, err
}
func (p *Process) getKProc() (*KinfoProc, error) {
mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
buf, length, err := common.CallSyscall(mib)
if err != nil {
return nil, err
}
if length != sizeOfKinfoProc {
return nil, err
}
k, err := parseKinfoProc(buf)
if err != nil {
return nil, err
}
return &k, nil
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}

View File

@@ -0,0 +1,192 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
package process
const (
CTLKern = 1
KernProc = 14
KernProcPID = 1
KernProcProc = 8
KernProcPathname = 12
KernProcArgs = 7
)
const (
sizeofPtr = 0x4
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x4
sizeofLongLong = 0x8
)
const (
sizeOfKinfoVmentry = 0x488
sizeOfKinfoProc = 0x300
)
const (
SIDL = 1
SRUN = 2
SSLEEP = 3
SSTOP = 4
SZOMB = 5
SWAIT = 6
SLOCK = 7
)
type (
_C_short int16
_C_int int32
_C_long int32
_C_long_long int64
)
type Timespec struct {
Sec int32
Nsec int32
}
type Timeval struct {
Sec int32
Usec int32
}
type Rusage struct {
Utime Timeval
Stime Timeval
Maxrss int32
Ixrss int32
Idrss int32
Isrss int32
Minflt int32
Majflt int32
Nswap int32
Inblock int32
Oublock int32
Msgsnd int32
Msgrcv int32
Nsignals int32
Nvcsw int32
Nivcsw int32
}
type Rlimit struct {
Cur int64
Max int64
}
type KinfoProc struct {
Structsize int32
Layout int32
Args int32 /* pargs */
Paddr int32 /* proc */
Addr int32 /* user */
Tracep int32 /* vnode */
Textvp int32 /* vnode */
Fd int32 /* filedesc */
Vmspace int32 /* vmspace */
Wchan int32
Pid int32
Ppid int32
Pgid int32
Tpgid int32
Sid int32
Tsid int32
Jobc int16
Spare_short1 int16
Tdev uint32
Siglist [16]byte /* sigset */
Sigmask [16]byte /* sigset */
Sigignore [16]byte /* sigset */
Sigcatch [16]byte /* sigset */
Uid uint32
Ruid uint32
Svuid uint32
Rgid uint32
Svgid uint32
Ngroups int16
Spare_short2 int16
Groups [16]uint32
Size uint32
Rssize int32
Swrss int32
Tsize int32
Dsize int32
Ssize int32
Xstat uint16
Acflag uint16
Pctcpu uint32
Estcpu uint32
Slptime uint32
Swtime uint32
Cow uint32
Runtime uint64
Start Timeval
Childtime Timeval
Flag int32
Kiflag int32
Traceflag int32
Stat int8
Nice int8
Lock int8
Rqindex int8
Oncpu uint8
Lastcpu uint8
Tdname [17]int8
Wmesg [9]int8
Login [18]int8
Lockname [9]int8
Comm [20]int8
Emul [17]int8
Loginclass [18]int8
Sparestrings [50]int8
Spareints [7]int32
Flag2 int32
Fibnum int32
Cr_flags uint32
Jid int32
Numthreads int32
Tid int32
Pri Priority
Rusage Rusage
Rusage_ch Rusage
Pcb int32 /* pcb */
Kstack int32
Udata int32
Tdaddr int32 /* thread */
Spareptrs [6]int32
Sparelongs [12]int32
Sflag int32
Tdflags int32
}
type Priority struct {
Class uint8
Level uint8
Native uint8
User uint8
}
type KinfoVmentry struct {
Structsize int32
Type int32
Start uint64
End uint64
Offset uint64
Vn_fileid uint64
Vn_fsid uint32
Flags int32
Resident int32
Private_resident int32
Protection int32
Ref_count int32
Shadow_count int32
Vn_type int32
Vn_size uint64
Vn_rdev uint32
Vn_mode uint16
Status uint16
X_kve_ispare [12]int32
Path [1024]int8
}

View File

@@ -0,0 +1,192 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
package process
const (
CTLKern = 1
KernProc = 14
KernProcPID = 1
KernProcProc = 8
KernProcPathname = 12
KernProcArgs = 7
)
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
)
const (
sizeOfKinfoVmentry = 0x488
sizeOfKinfoProc = 0x440
)
const (
SIDL = 1
SRUN = 2
SSLEEP = 3
SSTOP = 4
SZOMB = 5
SWAIT = 6
SLOCK = 7
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type Timespec struct {
Sec int64
Nsec int64
}
type Timeval struct {
Sec int64
Usec int64
}
type Rusage struct {
Utime Timeval
Stime Timeval
Maxrss int64
Ixrss int64
Idrss int64
Isrss int64
Minflt int64
Majflt int64
Nswap int64
Inblock int64
Oublock int64
Msgsnd int64
Msgrcv int64
Nsignals int64
Nvcsw int64
Nivcsw int64
}
type Rlimit struct {
Cur int64
Max int64
}
type KinfoProc struct {
Structsize int32
Layout int32
Args int64 /* pargs */
Paddr int64 /* proc */
Addr int64 /* user */
Tracep int64 /* vnode */
Textvp int64 /* vnode */
Fd int64 /* filedesc */
Vmspace int64 /* vmspace */
Wchan int64
Pid int32
Ppid int32
Pgid int32
Tpgid int32
Sid int32
Tsid int32
Jobc int16
Spare_short1 int16
Tdev uint32
Siglist [16]byte /* sigset */
Sigmask [16]byte /* sigset */
Sigignore [16]byte /* sigset */
Sigcatch [16]byte /* sigset */
Uid uint32
Ruid uint32
Svuid uint32
Rgid uint32
Svgid uint32
Ngroups int16
Spare_short2 int16
Groups [16]uint32
Size uint64
Rssize int64
Swrss int64
Tsize int64
Dsize int64
Ssize int64
Xstat uint16
Acflag uint16
Pctcpu uint32
Estcpu uint32
Slptime uint32
Swtime uint32
Cow uint32
Runtime uint64
Start Timeval
Childtime Timeval
Flag int64
Kiflag int64
Traceflag int32
Stat int8
Nice int8
Lock int8
Rqindex int8
Oncpu uint8
Lastcpu uint8
Tdname [17]int8
Wmesg [9]int8
Login [18]int8
Lockname [9]int8
Comm [20]int8
Emul [17]int8
Loginclass [18]int8
Sparestrings [50]int8
Spareints [7]int32
Flag2 int32
Fibnum int32
Cr_flags uint32
Jid int32
Numthreads int32
Tid int32
Pri Priority
Rusage Rusage
Rusage_ch Rusage
Pcb int64 /* pcb */
Kstack int64
Udata int64
Tdaddr int64 /* thread */
Spareptrs [6]int64
Sparelongs [12]int64
Sflag int64
Tdflags int64
}
type Priority struct {
Class uint8
Level uint8
Native uint8
User uint8
}
type KinfoVmentry struct {
Structsize int32
Type int32
Start uint64
End uint64
Offset uint64
Vn_fileid uint64
Vn_fsid uint32
Flags int32
Resident int32
Private_resident int32
Protection int32
Ref_count int32
Shadow_count int32
Vn_type int32
Vn_size uint64
Vn_rdev uint32
Vn_mode uint16
Status uint16
X_kve_ispare [12]int32
Path [1024]int8
}

View File

@@ -0,0 +1,767 @@
// +build linux
package process
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/net"
)
var ErrorNoChildren = errors.New("process does not have children")
const (
PrioProcess = 0 // linux/resource.h
)
// MemoryInfoExStat is different between OSes
type MemoryInfoExStat struct {
RSS uint64 `json:"rss"` // bytes
VMS uint64 `json:"vms"` // bytes
Shared uint64 `json:"shared"` // bytes
Text uint64 `json:"text"` // bytes
Lib uint64 `json:"lib"` // bytes
Data uint64 `json:"data"` // bytes
Dirty uint64 `json:"dirty"` // bytes
}
func (m MemoryInfoExStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
type MemoryMapsStat struct {
Path string `json:"path"`
Rss uint64 `json:"rss"`
Size uint64 `json:"size"`
Pss uint64 `json:"pss"`
SharedClean uint64 `json:"sharedClean"`
SharedDirty uint64 `json:"sharedDirty"`
PrivateClean uint64 `json:"privateClean"`
PrivateDirty uint64 `json:"privateDirty"`
Referenced uint64 `json:"referenced"`
Anonymous uint64 `json:"anonymous"`
Swap uint64 `json:"swap"`
}
// String returns JSON value of the process.
func (m MemoryMapsStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
// NewProcess creates a new Process instance, it only stores the pid and
// checks that the process exists. Other method on Process can be used
// to get more information about the process. An error will be returned
// if the process does not exist.
func NewProcess(pid int32) (*Process, error) {
p := &Process{
Pid: int32(pid),
}
file, err := os.Open(common.HostProc(strconv.Itoa(int(p.Pid))))
defer file.Close()
return p, err
}
// Ppid returns Parent Process ID of the process.
func (p *Process) Ppid() (int32, error) {
_, ppid, _, _, _, err := p.fillFromStat()
if err != nil {
return -1, err
}
return ppid, nil
}
// Name returns name of the process.
func (p *Process) Name() (string, error) {
if p.name == "" {
if err := p.fillFromStatus(); err != nil {
return "", err
}
}
return p.name, nil
}
// Exe returns executable path of the process.
func (p *Process) Exe() (string, error) {
return p.fillFromExe()
}
// Cmdline returns the command line arguments of the process as a string with
// each argument separated by 0x20 ascii character.
func (p *Process) Cmdline() (string, error) {
return p.fillFromCmdline()
}
// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument.
func (p *Process) CmdlineSlice() ([]string, error) {
return p.fillSliceFromCmdline()
}
// CreateTime returns created time of the process in seconds since the epoch, in UTC.
func (p *Process) CreateTime() (int64, error) {
_, _, _, createTime, _, err := p.fillFromStat()
if err != nil {
return 0, err
}
return createTime, nil
}
// Cwd returns current working directory of the process.
func (p *Process) Cwd() (string, error) {
return p.fillFromCwd()
}
// Parent returns parent Process of the process.
func (p *Process) Parent() (*Process, error) {
err := p.fillFromStatus()
if err != nil {
return nil, err
}
if p.parent == 0 {
return nil, fmt.Errorf("wrong number of parents")
}
return NewProcess(p.parent)
}
// Status returns the process status.
// Return value could be one of these.
// R: Running S: Sleep T: Stop I: Idle
// Z: Zombie W: Wait L: Lock
// The charactor is same within all supported platforms.
func (p *Process) Status() (string, error) {
err := p.fillFromStatus()
if err != nil {
return "", err
}
return p.status, nil
}
// Uids returns user ids of the process as a slice of the int
func (p *Process) Uids() ([]int32, error) {
err := p.fillFromStatus()
if err != nil {
return []int32{}, err
}
return p.uids, nil
}
// Gids returns group ids of the process as a slice of the int
func (p *Process) Gids() ([]int32, error) {
err := p.fillFromStatus()
if err != nil {
return []int32{}, err
}
return p.gids, nil
}
// Terminal returns a terminal which is associated with the process.
func (p *Process) Terminal() (string, error) {
terminal, _, _, _, _, err := p.fillFromStat()
if err != nil {
return "", err
}
return terminal, nil
}
// Nice returns a nice value (priority).
// Notice: gopsutil can not set nice value.
func (p *Process) Nice() (int32, error) {
_, _, _, _, nice, err := p.fillFromStat()
if err != nil {
return 0, err
}
return nice, nil
}
// IOnice returns process I/O nice value (priority).
func (p *Process) IOnice() (int32, error) {
return 0, common.ErrNotImplementedError
}
// Rlimit returns Resource Limits.
func (p *Process) Rlimit() ([]RlimitStat, error) {
return nil, common.ErrNotImplementedError
}
// IOCounters returns IO Counters.
func (p *Process) IOCounters() (*IOCountersStat, error) {
return p.fillFromIO()
}
// NumCtxSwitches returns the number of the context switches of the process.
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
err := p.fillFromStatus()
if err != nil {
return nil, err
}
return p.numCtxSwitches, nil
}
// NumFDs returns the number of File Descriptors used by the process.
func (p *Process) NumFDs() (int32, error) {
numFds, _, err := p.fillFromfd()
return numFds, err
}
// NumThreads returns the number of threads used by the process.
func (p *Process) NumThreads() (int32, error) {
err := p.fillFromStatus()
if err != nil {
return 0, err
}
return p.numThreads, nil
}
// Threads returns a map of threads
//
// Notice: Not implemented yet. always returns empty map.
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, nil
}
// Times returns CPU times of the process.
func (p *Process) Times() (*cpu.TimesStat, error) {
_, _, cpuTimes, _, _, err := p.fillFromStat()
if err != nil {
return nil, err
}
return cpuTimes, nil
}
// CPUAffinity returns CPU affinity of the process.
//
// Notice: Not implemented yet.
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.ErrNotImplementedError
}
// MemoryInfo returns platform in-dependend memory information, such as RSS, VMS and Swap
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
meminfo, _, err := p.fillFromStatm()
if err != nil {
return nil, err
}
return meminfo, nil
}
// MemoryInfoEx returns platform dependend memory information.
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
_, memInfoEx, err := p.fillFromStatm()
if err != nil {
return nil, err
}
return memInfoEx, nil
}
// Children returns a slice of Process of the process.
func (p *Process) Children() ([]*Process, error) {
pids, err := common.CallPgrep(invoke, p.Pid)
if err != nil {
if pids == nil || len(pids) == 0 {
return nil, ErrorNoChildren
}
return nil, err
}
ret := make([]*Process, 0, len(pids))
for _, pid := range pids {
np, err := NewProcess(pid)
if err != nil {
return nil, err
}
ret = append(ret, np)
}
return ret, nil
}
// OpenFiles returns a slice of OpenFilesStat opend by the process.
// OpenFilesStat includes a file path and file descriptor.
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
_, ofs, err := p.fillFromfd()
if err != nil {
return nil, err
}
ret := make([]OpenFilesStat, len(ofs))
for i, o := range ofs {
ret[i] = *o
}
return ret, nil
}
// Connections returns a slice of net.ConnectionStat used by the process.
// This returns all kind of the connection. This measn TCP, UDP or UNIX.
func (p *Process) Connections() ([]net.ConnectionStat, error) {
return net.ConnectionsPid("all", p.Pid)
}
// NetIOCounters returns NetIOCounters of the process.
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
filename := common.HostProc(strconv.Itoa(int(p.Pid)), "net/dev")
return net.IOCountersByFile(pernic, filename)
}
// IsRunning returns whether the process is running or not.
// Not implemented yet.
func (p *Process) IsRunning() (bool, error) {
return true, common.ErrNotImplementedError
}
// MemoryMaps get memory maps from /proc/(pid)/smaps
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
pid := p.Pid
var ret []MemoryMapsStat
smapsPath := common.HostProc(strconv.Itoa(int(pid)), "smaps")
contents, err := ioutil.ReadFile(smapsPath)
if err != nil {
return nil, err
}
lines := strings.Split(string(contents), "\n")
// function of parsing a block
getBlock := func(first_line []string, block []string) (MemoryMapsStat, error) {
m := MemoryMapsStat{}
m.Path = first_line[len(first_line)-1]
for _, line := range block {
if strings.Contains(line, "VmFlags") {
continue
}
field := strings.Split(line, ":")
if len(field) < 2 {
continue
}
v := strings.Trim(field[1], " kB") // remove last "kB"
t, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return m, err
}
switch field[0] {
case "Size":
m.Size = t
case "Rss":
m.Rss = t
case "Pss":
m.Pss = t
case "Shared_Clean":
m.SharedClean = t
case "Shared_Dirty":
m.SharedDirty = t
case "Private_Clean":
m.PrivateClean = t
case "Private_Dirty":
m.PrivateDirty = t
case "Referenced":
m.Referenced = t
case "Anonymous":
m.Anonymous = t
case "Swap":
m.Swap = t
}
}
return m, nil
}
blocks := make([]string, 16)
for _, line := range lines {
field := strings.Split(line, " ")
if strings.HasSuffix(field[0], ":") == false {
// new block section
if len(blocks) > 0 {
g, err := getBlock(field, blocks)
if err != nil {
return &ret, err
}
ret = append(ret, g)
}
// starts new block
blocks = make([]string, 16)
} else {
blocks = append(blocks, line)
}
}
return &ret, nil
}
/**
** Internal functions
**/
// Get num_fds from /proc/(pid)/fd
func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) {
pid := p.Pid
statPath := common.HostProc(strconv.Itoa(int(pid)), "fd")
d, err := os.Open(statPath)
if err != nil {
return 0, nil, err
}
defer d.Close()
fnames, err := d.Readdirnames(-1)
numFDs := int32(len(fnames))
var openfiles []*OpenFilesStat
for _, fd := range fnames {
fpath := filepath.Join(statPath, fd)
filepath, err := os.Readlink(fpath)
if err != nil {
continue
}
t, err := strconv.ParseUint(fd, 10, 64)
if err != nil {
return numFDs, openfiles, err
}
o := &OpenFilesStat{
Path: filepath,
Fd: t,
}
openfiles = append(openfiles, o)
}
return numFDs, openfiles, nil
}
// Get cwd from /proc/(pid)/cwd
func (p *Process) fillFromCwd() (string, error) {
pid := p.Pid
cwdPath := common.HostProc(strconv.Itoa(int(pid)), "cwd")
cwd, err := os.Readlink(cwdPath)
if err != nil {
return "", err
}
return string(cwd), nil
}
// Get exe from /proc/(pid)/exe
func (p *Process) fillFromExe() (string, error) {
pid := p.Pid
exePath := common.HostProc(strconv.Itoa(int(pid)), "exe")
exe, err := os.Readlink(exePath)
if err != nil {
return "", err
}
return string(exe), nil
}
// Get cmdline from /proc/(pid)/cmdline
func (p *Process) fillFromCmdline() (string, error) {
pid := p.Pid
cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath)
if err != nil {
return "", err
}
ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
if r == '\u0000' {
return true
}
return false
})
return strings.Join(ret, " "), nil
}
func (p *Process) fillSliceFromCmdline() ([]string, error) {
pid := p.Pid
cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath)
if err != nil {
return nil, err
}
if len(cmdline) == 0 {
return nil, nil
}
if cmdline[len(cmdline)-1] == 0 {
cmdline = cmdline[:len(cmdline)-1]
}
parts := bytes.Split(cmdline, []byte{0})
var strParts []string
for _, p := range parts {
strParts = append(strParts, string(p))
}
return strParts, nil
}
// Get IO status from /proc/(pid)/io
func (p *Process) fillFromIO() (*IOCountersStat, error) {
pid := p.Pid
ioPath := common.HostProc(strconv.Itoa(int(pid)), "io")
ioline, err := ioutil.ReadFile(ioPath)
if err != nil {
return nil, err
}
lines := strings.Split(string(ioline), "\n")
ret := &IOCountersStat{}
for _, line := range lines {
field := strings.Fields(line)
if len(field) < 2 {
continue
}
t, err := strconv.ParseUint(field[1], 10, 64)
if err != nil {
return nil, err
}
param := field[0]
if strings.HasSuffix(param, ":") {
param = param[:len(param)-1]
}
switch param {
case "syscr":
ret.ReadCount = t
case "syscw":
ret.WriteCount = t
case "read_bytes":
ret.ReadBytes = t
case "write_bytes":
ret.WriteBytes = t
}
}
return ret, nil
}
// Get memory info from /proc/(pid)/statm
func (p *Process) fillFromStatm() (*MemoryInfoStat, *MemoryInfoExStat, error) {
pid := p.Pid
memPath := common.HostProc(strconv.Itoa(int(pid)), "statm")
contents, err := ioutil.ReadFile(memPath)
if err != nil {
return nil, nil, err
}
fields := strings.Split(string(contents), " ")
vms, err := strconv.ParseUint(fields[0], 10, 64)
if err != nil {
return nil, nil, err
}
rss, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
return nil, nil, err
}
memInfo := &MemoryInfoStat{
RSS: rss * PageSize,
VMS: vms * PageSize,
}
shared, err := strconv.ParseUint(fields[2], 10, 64)
if err != nil {
return nil, nil, err
}
text, err := strconv.ParseUint(fields[3], 10, 64)
if err != nil {
return nil, nil, err
}
lib, err := strconv.ParseUint(fields[4], 10, 64)
if err != nil {
return nil, nil, err
}
dirty, err := strconv.ParseUint(fields[5], 10, 64)
if err != nil {
return nil, nil, err
}
memInfoEx := &MemoryInfoExStat{
RSS: rss * PageSize,
VMS: vms * PageSize,
Shared: shared * PageSize,
Text: text * PageSize,
Lib: lib * PageSize,
Dirty: dirty * PageSize,
}
return memInfo, memInfoEx, nil
}
// Get various status from /proc/(pid)/status
func (p *Process) fillFromStatus() error {
pid := p.Pid
statPath := common.HostProc(strconv.Itoa(int(pid)), "status")
contents, err := ioutil.ReadFile(statPath)
if err != nil {
return err
}
lines := strings.Split(string(contents), "\n")
p.numCtxSwitches = &NumCtxSwitchesStat{}
p.memInfo = &MemoryInfoStat{}
for _, line := range lines {
tabParts := strings.SplitN(line, "\t", 2)
if len(tabParts) < 2 {
continue
}
value := tabParts[1]
switch strings.TrimRight(tabParts[0], ":") {
case "Name":
p.name = strings.Trim(value, " \t")
case "State":
p.status = value[0:1]
case "PPid", "Ppid":
pval, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
}
p.parent = int32(pval)
case "Uid":
p.uids = make([]int32, 0, 4)
for _, i := range strings.Split(value, "\t") {
v, err := strconv.ParseInt(i, 10, 32)
if err != nil {
return err
}
p.uids = append(p.uids, int32(v))
}
case "Gid":
p.gids = make([]int32, 0, 4)
for _, i := range strings.Split(value, "\t") {
v, err := strconv.ParseInt(i, 10, 32)
if err != nil {
return err
}
p.gids = append(p.gids, int32(v))
}
case "Threads":
v, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
}
p.numThreads = int32(v)
case "voluntary_ctxt_switches":
v, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
p.numCtxSwitches.Voluntary = v
case "nonvoluntary_ctxt_switches":
v, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
p.numCtxSwitches.Involuntary = v
case "VmRSS":
value := strings.Trim(value, " kB") // remove last "kB"
v, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
p.memInfo.RSS = v * 1024
case "VmSize":
value := strings.Trim(value, " kB") // remove last "kB"
v, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
p.memInfo.VMS = v * 1024
case "VmSwap":
value := strings.Trim(value, " kB") // remove last "kB"
v, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
p.memInfo.Swap = v * 1024
}
}
return nil
}
func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, int32, error) {
pid := p.Pid
statPath := common.HostProc(strconv.Itoa(int(pid)), "stat")
contents, err := ioutil.ReadFile(statPath)
if err != nil {
return "", 0, nil, 0, 0, err
}
fields := strings.Fields(string(contents))
i := 1
for !strings.HasSuffix(fields[i], ")") {
i++
}
termmap, err := getTerminalMap()
terminal := ""
if err == nil {
t, err := strconv.ParseUint(fields[i+5], 10, 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
terminal = termmap[t]
}
ppid, err := strconv.ParseInt(fields[i+2], 10, 32)
if err != nil {
return "", 0, nil, 0, 0, err
}
utime, err := strconv.ParseFloat(fields[i+12], 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
stime, err := strconv.ParseFloat(fields[i+13], 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
cpuTimes := &cpu.TimesStat{
CPU: "cpu",
User: float64(utime / ClockTicks),
System: float64(stime / ClockTicks),
}
bootTime, _ := host.BootTime()
t, err := strconv.ParseUint(fields[i+20], 10, 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
ctime := (t / uint64(ClockTicks)) + uint64(bootTime)
createTime := int64(ctime * 1000)
// p.Nice = mustParseInt32(fields[18])
// use syscall instead of parse Stat file
snice, _ := syscall.Getpriority(PrioProcess, int(pid))
nice := int32(snice) // FIXME: is this true?
return terminal, int32(ppid), cpuTimes, createTime, nice, nil
}
// Pids returns a slice of process ID list which are running now.
func Pids() ([]int32, error) {
var ret []int32
d, err := os.Open(common.HostProc())
if err != nil {
return nil, err
}
defer d.Close()
fnames, err := d.Readdirnames(-1)
if err != nil {
return nil, err
}
for _, fname := range fnames {
pid, err := strconv.ParseInt(fname, 10, 32)
if err != nil {
// if not numeric name, just skip
continue
}
ret = append(ret, int32(pid))
}
return ret, nil
}

View File

@@ -0,0 +1,9 @@
// +build linux
// +build 386
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@@ -0,0 +1,9 @@
// +build linux
// +build amd64
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@@ -0,0 +1,9 @@
// +build linux
// +build arm
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@@ -0,0 +1,9 @@
// +build linux
// +build arm64
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@@ -0,0 +1,122 @@
// +build linux freebsd darwin
package process
import (
"os"
"os/exec"
"os/user"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
// POSIX
func getTerminalMap() (map[uint64]string, error) {
ret := make(map[uint64]string)
var termfiles []string
d, err := os.Open("/dev")
if err != nil {
return nil, err
}
defer d.Close()
devnames, err := d.Readdirnames(-1)
for _, devname := range devnames {
if strings.HasPrefix(devname, "/dev/tty") {
termfiles = append(termfiles, "/dev/tty/"+devname)
}
}
ptsd, err := os.Open("/dev/pts")
if err != nil {
return nil, err
}
defer ptsd.Close()
ptsnames, err := ptsd.Readdirnames(-1)
for _, ptsname := range ptsnames {
termfiles = append(termfiles, "/dev/pts/"+ptsname)
}
for _, name := range termfiles {
stat := syscall.Stat_t{}
if err = syscall.Stat(name, &stat); err != nil {
return nil, err
}
rdev := uint64(stat.Rdev)
ret[rdev] = strings.Replace(name, "/dev", "", -1)
}
return ret, nil
}
// SendSignal sends a syscall.Signal to the process.
// Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported.
func (p *Process) SendSignal(sig syscall.Signal) error {
sigAsStr := "INT"
switch sig {
case syscall.SIGSTOP:
sigAsStr = "STOP"
case syscall.SIGCONT:
sigAsStr = "CONT"
case syscall.SIGTERM:
sigAsStr = "TERM"
case syscall.SIGKILL:
sigAsStr = "KILL"
}
kill, err := exec.LookPath("kill")
if err != nil {
return err
}
cmd := exec.Command(kill, "-s", sigAsStr, strconv.Itoa(int(p.Pid)))
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
return err
}
err = common.WaitTimeout(cmd, common.Timeout)
if err != nil {
return err
}
return nil
}
// Suspend sends SIGSTOP to the process.
func (p *Process) Suspend() error {
return p.SendSignal(syscall.SIGSTOP)
}
// Resume sends SIGCONT to the process.
func (p *Process) Resume() error {
return p.SendSignal(syscall.SIGCONT)
}
// Terminate sends SIGTERM to the process.
func (p *Process) Terminate() error {
return p.SendSignal(syscall.SIGTERM)
}
// Kill sends SIGKILL to the process.
func (p *Process) Kill() error {
return p.SendSignal(syscall.SIGKILL)
}
// Username returns a username of the process.
func (p *Process) Username() (string, error) {
uids, err := p.Uids()
if err != nil {
return "", err
}
if len(uids) > 0 {
u, err := user.LookupId(strconv.Itoa(int(uids[0])))
if err != nil {
return "", err
}
return u.Username, nil
}
return "", nil
}

View File

@@ -0,0 +1,19 @@
// +build linux freebsd
package process
import (
"os"
"syscall"
"testing"
)
func Test_SendSignal(t *testing.T) {
checkPid := os.Getpid()
p, _ := NewProcess(int32(checkPid))
err := p.SendSignal(syscall.SIGCONT)
if err != nil {
t.Errorf("send signal %v", err)
}
}

Some files were not shown because too many files have changed in this diff Show More