mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 09:41:57 +00:00
Merge pull request #711 from weaveworks/576-host-metrics
Add host memory and CPU usage metrics
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/common/mtime"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -18,17 +19,16 @@ const (
|
||||
Load1 = "load1"
|
||||
Load5 = "load5"
|
||||
Load15 = "load15"
|
||||
CPUUsage = "cpu_usage_percent"
|
||||
MemUsage = "mem_usage_percent"
|
||||
)
|
||||
|
||||
// Exposed for testing.
|
||||
const (
|
||||
ProcUptime = "/proc/uptime"
|
||||
ProcLoad = "/proc/loadavg"
|
||||
)
|
||||
|
||||
// Exposed for testing.
|
||||
var (
|
||||
Now = func() string { return time.Now().UTC().Format(time.RFC3339Nano) }
|
||||
ProcUptime = "/proc/uptime"
|
||||
ProcLoad = "/proc/loadavg"
|
||||
ProcStat = "/proc/stat"
|
||||
ProcMemInfo = "/proc/meminfo"
|
||||
)
|
||||
|
||||
// Reporter generates Reports containing the host topology.
|
||||
@@ -72,15 +72,22 @@ func (r *Reporter) Report() (report.Report, error) {
|
||||
return rep, err
|
||||
}
|
||||
|
||||
now := mtime.Now()
|
||||
metrics := GetLoad(now)
|
||||
cpuUsage, max := GetCPUUsagePercent()
|
||||
metrics[CPUUsage] = report.MakeMetric().Add(now, cpuUsage).WithMax(max)
|
||||
memUsage, max := GetMemoryUsagePercent()
|
||||
metrics[MemUsage] = report.MakeMetric().Add(now, memUsage).WithMax(max)
|
||||
|
||||
rep.Host.AddNode(report.MakeHostNodeID(r.hostID), report.MakeNodeWith(map[string]string{
|
||||
Timestamp: Now(),
|
||||
Timestamp: mtime.Now().UTC().Format(time.RFC3339Nano),
|
||||
HostName: r.hostName,
|
||||
OS: runtime.GOOS,
|
||||
KernelVersion: kernel,
|
||||
Uptime: uptime.String(),
|
||||
}).WithSets(report.Sets{
|
||||
LocalNetworks: report.MakeStringSet(localCIDRs...),
|
||||
}).WithMetrics(GetLoad()))
|
||||
}).WithMetrics(metrics))
|
||||
|
||||
return rep, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/common/mtime"
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
"github.com/weaveworks/scope/report"
|
||||
"github.com/weaveworks/scope/test"
|
||||
@@ -18,13 +19,14 @@ func TestReporter(t *testing.T) {
|
||||
version = "version"
|
||||
network = "192.168.0.0/16"
|
||||
hostID = "hostid"
|
||||
now = "now"
|
||||
hostname = "hostname"
|
||||
timestamp = time.Now()
|
||||
load = report.Metrics{
|
||||
host.Load1: report.MakeMetric().Add(timestamp, 1.0),
|
||||
host.Load5: report.MakeMetric().Add(timestamp, 5.0),
|
||||
host.Load15: report.MakeMetric().Add(timestamp, 15.0),
|
||||
host.Load1: report.MakeMetric().Add(timestamp, 1.0),
|
||||
host.Load5: report.MakeMetric().Add(timestamp, 5.0),
|
||||
host.Load15: report.MakeMetric().Add(timestamp, 15.0),
|
||||
host.CPUUsage: report.MakeMetric().Add(timestamp, 30.0).WithMax(100.0),
|
||||
host.MemUsage: report.MakeMetric().Add(timestamp, 60.0).WithMax(100.0),
|
||||
}
|
||||
uptime = "278h55m43s"
|
||||
kernel = "release version"
|
||||
@@ -32,26 +34,32 @@ func TestReporter(t *testing.T) {
|
||||
localNets = report.Networks([]*net.IPNet{ipnet})
|
||||
)
|
||||
|
||||
mtime.NowForce(timestamp)
|
||||
defer mtime.NowReset()
|
||||
|
||||
var (
|
||||
oldGetKernelVersion = host.GetKernelVersion
|
||||
oldGetLoad = host.GetLoad
|
||||
oldGetUptime = host.GetUptime
|
||||
oldNow = host.Now
|
||||
oldGetKernelVersion = host.GetKernelVersion
|
||||
oldGetLoad = host.GetLoad
|
||||
oldGetUptime = host.GetUptime
|
||||
oldGetCPUUsagePercent = host.GetCPUUsagePercent
|
||||
oldGetMemoryUsagePercent = host.GetMemoryUsagePercent
|
||||
)
|
||||
defer func() {
|
||||
host.GetKernelVersion = oldGetKernelVersion
|
||||
host.GetLoad = oldGetLoad
|
||||
host.GetUptime = oldGetUptime
|
||||
host.Now = oldNow
|
||||
host.GetCPUUsagePercent = oldGetCPUUsagePercent
|
||||
host.GetMemoryUsagePercent = oldGetMemoryUsagePercent
|
||||
}()
|
||||
host.GetKernelVersion = func() (string, error) { return release + " " + version, nil }
|
||||
host.GetLoad = func() report.Metrics { return load }
|
||||
host.GetLoad = func(time.Time) report.Metrics { return load }
|
||||
host.GetUptime = func() (time.Duration, error) { return time.ParseDuration(uptime) }
|
||||
host.Now = func() string { return now }
|
||||
host.GetCPUUsagePercent = func() (float64, float64) { return 30.0, 100.0 }
|
||||
host.GetMemoryUsagePercent = func() (float64, float64) { return 60.0, 100.0 }
|
||||
|
||||
want := report.MakeReport()
|
||||
want.Host.AddNode(report.MakeHostNodeID(hostID), report.MakeNodeWith(map[string]string{
|
||||
host.Timestamp: now,
|
||||
host.Timestamp: timestamp.UTC().Format(time.RFC3339Nano),
|
||||
host.HostName: hostname,
|
||||
host.OS: runtime.GOOS,
|
||||
host.Uptime: uptime,
|
||||
|
||||
@@ -30,12 +30,11 @@ var GetKernelVersion = func() (string, error) {
|
||||
}
|
||||
|
||||
// GetLoad returns the current load averages as metrics.
|
||||
var GetLoad = func() report.Metrics {
|
||||
var GetLoad = func(now time.Time) report.Metrics {
|
||||
out, err := exec.Command("w").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
now := time.Now()
|
||||
matches := loadRe.FindAllStringSubmatch(string(out), -1)
|
||||
if matches == nil || len(matches) < 1 || len(matches[0]) < 4 {
|
||||
return nil
|
||||
@@ -84,3 +83,13 @@ var GetUptime = func() (time.Duration, error) {
|
||||
}
|
||||
return (time.Duration(d) * 24 * time.Hour) + (time.Duration(h) * time.Hour) + (time.Duration(m) * time.Minute), nil
|
||||
}
|
||||
|
||||
// GetCPUUsagePercent returns the percent cpu usage and max (ie #cpus * 100)
|
||||
var GetCPUUsagePercent = func() (float64, float64) {
|
||||
return 0.0, 0.0
|
||||
}
|
||||
|
||||
// GetMemoryUsagePercent returns the percent memory usage and max (ie 100)
|
||||
var GetMemoryUsagePercent = func() (float64, float64) {
|
||||
return 0.0, 0.0
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
linuxproc "github.com/c9s/goprocinfo/linux"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -24,12 +26,11 @@ var GetKernelVersion = func() (string, error) {
|
||||
}
|
||||
|
||||
// GetLoad returns the current load averages as metrics.
|
||||
var GetLoad = func() report.Metrics {
|
||||
var GetLoad = func(now time.Time) report.Metrics {
|
||||
buf, err := ioutil.ReadFile("/proc/loadavg")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
now := time.Now()
|
||||
toks := strings.Fields(string(buf))
|
||||
if len(toks) < 3 {
|
||||
return nil
|
||||
@@ -72,3 +73,42 @@ var GetUptime = func() (time.Duration, error) {
|
||||
|
||||
return time.Duration(uptime) * time.Second, nil
|
||||
}
|
||||
|
||||
var previousStat = linuxproc.CPUStat{}
|
||||
|
||||
// GetCPUUsagePercent returns the percent cpu usage and max (ie #cpus * 100)
|
||||
var GetCPUUsagePercent = func() (float64, float64) {
|
||||
stat, err := linuxproc.ReadStat(ProcStat)
|
||||
if err != nil {
|
||||
return 0.0, 0.0
|
||||
}
|
||||
|
||||
// From http://stackoverflow.com/questions/23367857/accurate-calculation-of-cpu-usage-given-in-percentage-in-linux
|
||||
var (
|
||||
currentStat = stat.CPUStatAll
|
||||
prevIdle = previousStat.Idle + previousStat.IOWait
|
||||
idle = currentStat.Idle + currentStat.IOWait
|
||||
prevNonIdle = (previousStat.User + previousStat.Nice + previousStat.System +
|
||||
previousStat.IRQ + previousStat.SoftIRQ + previousStat.Steal)
|
||||
nonIdle = (currentStat.User + currentStat.Nice + currentStat.System +
|
||||
currentStat.IRQ + currentStat.SoftIRQ + currentStat.Steal)
|
||||
prevTotal = prevIdle + prevNonIdle
|
||||
total = idle + nonIdle
|
||||
// differentiate: actual value minus the previous one
|
||||
totald = total - prevTotal
|
||||
idled = idle - prevIdle
|
||||
)
|
||||
previousStat = currentStat
|
||||
return float64(totald-idled) * 100. / float64(totald), float64(len(stat.CPUStats)) * 100.
|
||||
}
|
||||
|
||||
// GetMemoryUsagePercent returns the percent memory usage and max (ie 100)
|
||||
var GetMemoryUsagePercent = func() (float64, float64) {
|
||||
meminfo, err := linuxproc.ReadMemInfo(ProcMemInfo)
|
||||
if err != nil {
|
||||
return 0.0, 0.0
|
||||
}
|
||||
|
||||
used := meminfo.MemTotal - meminfo.MemFree - meminfo.Buffers - meminfo.Cached
|
||||
return float64(used) * 100. / float64(meminfo.MemTotal), 100.
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package host_test
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/probe/host"
|
||||
)
|
||||
@@ -19,7 +20,7 @@ func TestGetKernelVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetLoad(t *testing.T) {
|
||||
have := host.GetLoad()
|
||||
have := host.GetLoad(time.Now())
|
||||
if len(have) != 3 {
|
||||
t.Fatalf("Expected 3 metrics, but got: %v", have)
|
||||
}
|
||||
|
||||
@@ -346,7 +346,9 @@ func processOriginTable(nmd report.Node, addHostTag bool, addContainerTag bool)
|
||||
}, len(rows) > 0 || commFound || pidFound
|
||||
}
|
||||
|
||||
func sparklineRow(human string, metric report.Metric, format func(report.Metric) (report.Metric, string)) Row {
|
||||
type formatter func(report.Metric) (report.Metric, string)
|
||||
|
||||
func sparklineRow(human string, metric report.Metric, format formatter) Row {
|
||||
if format == nil {
|
||||
format = formatDefault
|
||||
}
|
||||
@@ -520,6 +522,17 @@ func hostOriginTable(nmd report.Node) (Table, bool) {
|
||||
rows = append(rows, sparklineRow(tuple.human, val, nil))
|
||||
}
|
||||
}
|
||||
for _, tuple := range []struct {
|
||||
key, human string
|
||||
fmt formatter
|
||||
}{
|
||||
{host.CPUUsage, "CPU Usage", formatPercent},
|
||||
{host.MemUsage, "Memory Usage", formatPercent},
|
||||
} {
|
||||
if val, ok := nmd.Metrics[tuple.key]; ok {
|
||||
rows = append(rows, sparklineRow(tuple.human, val, tuple.fmt))
|
||||
}
|
||||
}
|
||||
for _, tuple := range []struct{ key, human string }{
|
||||
{host.OS, "Operating system"},
|
||||
{host.KernelVersion, "Kernel version"},
|
||||
|
||||
@@ -70,6 +70,17 @@ func (m Metric) WithFirst(t time.Time) Metric {
|
||||
}
|
||||
}
|
||||
|
||||
// WithMax returns a fresh copy of m, with Max set to max
|
||||
func (m Metric) WithMax(max float64) Metric {
|
||||
return Metric{
|
||||
Samples: m.Samples,
|
||||
Max: max,
|
||||
Min: m.Min,
|
||||
First: m.First,
|
||||
Last: m.Last,
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the number of samples in the metric.
|
||||
func (m Metric) Len() int {
|
||||
if m.Samples == nil {
|
||||
|
||||
127
vendor/github.com/c9s/goprocinfo/linux/cpuinfo.go
generated
vendored
Normal file
127
vendor/github.com/c9s/goprocinfo/linux/cpuinfo.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CPUInfo struct {
|
||||
Processors []Processor `json:"processors"`
|
||||
}
|
||||
|
||||
func (self *CPUInfo) NumCPU() int {
|
||||
return len(self.Processors)
|
||||
}
|
||||
|
||||
func (self *CPUInfo) NumCore() int {
|
||||
core := make(map[string]bool)
|
||||
|
||||
for _, p := range self.Processors {
|
||||
pid := p.PhysicalId
|
||||
cid := p.CoreId
|
||||
|
||||
if pid == -1 {
|
||||
return self.NumCPU()
|
||||
} else {
|
||||
// to avoid fmt import
|
||||
key := strconv.FormatInt(int64(pid), 10) + ":" + strconv.FormatInt(int64(cid), 10)
|
||||
core[key] = true
|
||||
}
|
||||
}
|
||||
|
||||
return len(core)
|
||||
}
|
||||
|
||||
func (self *CPUInfo) NumPhysicalCPU() int {
|
||||
pcpu := make(map[string]bool)
|
||||
|
||||
for _, p := range self.Processors {
|
||||
pid := p.PhysicalId
|
||||
|
||||
if pid == -1 {
|
||||
return self.NumCPU()
|
||||
} else {
|
||||
// to avoid fmt import
|
||||
key := strconv.FormatInt(int64(pid), 10)
|
||||
pcpu[key] = true
|
||||
}
|
||||
}
|
||||
|
||||
return len(pcpu)
|
||||
}
|
||||
|
||||
type Processor struct {
|
||||
Id int64 `json:"id"`
|
||||
VendorId string `json:"vendor_id"`
|
||||
Model int64 `json:"model"`
|
||||
ModelName string `json:"model_name"`
|
||||
Flags []string `json:"flags"`
|
||||
Cores int64 `json:"cores"`
|
||||
MHz float64 `json:"mhz"`
|
||||
PhysicalId int64 `json:"physical_id"`
|
||||
CoreId int64 `json:"core_id"`
|
||||
}
|
||||
|
||||
var cpuinfoRegExp = regexp.MustCompile("([^:]*?)\\s*:\\s*(.*)$")
|
||||
|
||||
func ReadCPUInfo(path string) (*CPUInfo, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
content := string(b)
|
||||
lines := strings.Split(content, "\n")
|
||||
|
||||
var cpuinfo = CPUInfo{}
|
||||
var processor = &Processor{CoreId: -1, PhysicalId: -1}
|
||||
|
||||
for i, line := range lines {
|
||||
var key string
|
||||
var value string
|
||||
|
||||
if len(line) == 0 && i != len(lines)-1 {
|
||||
// end of processor
|
||||
cpuinfo.Processors = append(cpuinfo.Processors, *processor)
|
||||
processor = &Processor{}
|
||||
continue
|
||||
} else if i == len(lines)-1 {
|
||||
continue
|
||||
}
|
||||
|
||||
submatches := cpuinfoRegExp.FindStringSubmatch(line)
|
||||
key = submatches[1]
|
||||
value = submatches[2]
|
||||
|
||||
switch key {
|
||||
case "processor":
|
||||
processor.Id, _ = strconv.ParseInt(value, 10, 32)
|
||||
case "vendor_id":
|
||||
processor.VendorId = value
|
||||
case "model":
|
||||
processor.Model, _ = strconv.ParseInt(value, 10, 32)
|
||||
case "model name":
|
||||
processor.ModelName = value
|
||||
case "flags":
|
||||
processor.Flags = strings.Fields(value)
|
||||
case "cpu cores":
|
||||
processor.Cores, _ = strconv.ParseInt(value, 10, 32)
|
||||
case "cpu MHz":
|
||||
processor.MHz, _ = strconv.ParseFloat(value, 64)
|
||||
case "physical id":
|
||||
processor.PhysicalId, _ = strconv.ParseInt(value, 10, 32)
|
||||
case "core id":
|
||||
processor.CoreId, _ = strconv.ParseInt(value, 10, 32)
|
||||
}
|
||||
/*
|
||||
processor : 0
|
||||
vendor_id : GenuineIntel
|
||||
cpu family : 6
|
||||
model : 26
|
||||
model name : Intel(R) Xeon(R) CPU L5520 @ 2.27GHz
|
||||
*/
|
||||
}
|
||||
return &cpuinfo, nil
|
||||
}
|
||||
62
vendor/github.com/c9s/goprocinfo/linux/cpuinfo_test.go
generated
vendored
Normal file
62
vendor/github.com/c9s/goprocinfo/linux/cpuinfo_test.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCPUInfo(t *testing.T) {
|
||||
|
||||
cpuinfo, err := ReadCPUInfo("proc/cpuinfo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%+v", cpuinfo)
|
||||
|
||||
if len(cpuinfo.Processors) != 8 {
|
||||
t.Fatal("wrong processor number : ", len(cpuinfo.Processors))
|
||||
}
|
||||
|
||||
if cpuinfo.NumCore() != 8 {
|
||||
t.Fatal("wrong core number", cpuinfo.NumCore())
|
||||
}
|
||||
|
||||
if cpuinfo.NumPhysicalCPU() != 2 {
|
||||
t.Fatal("wrong physical cpu number", cpuinfo.NumPhysicalCPU())
|
||||
}
|
||||
|
||||
cpuinfo, err = ReadCPUInfo("proc/cpuinfo_2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%+v", cpuinfo)
|
||||
|
||||
if len(cpuinfo.Processors) != 4 {
|
||||
t.Fatal("wrong processor number : ", len(cpuinfo.Processors))
|
||||
}
|
||||
|
||||
if cpuinfo.NumCore() != 4 {
|
||||
t.Fatal("wrong core number", cpuinfo.NumCore())
|
||||
}
|
||||
|
||||
// not sure at all here
|
||||
// does not match with https://github.com/randombit/cpuinfo/blob/master/x86/xeon_l5520
|
||||
if cpuinfo.NumPhysicalCPU() != 4 {
|
||||
t.Fatal("wrong physical cpu number", cpuinfo.NumPhysicalCPU())
|
||||
}
|
||||
|
||||
cpuinfo, err = ReadCPUInfo("proc/cpuinfo_3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%+v", cpuinfo)
|
||||
|
||||
if len(cpuinfo.Processors) != 4 {
|
||||
t.Fatal("wrong processor number : ", len(cpuinfo.Processors))
|
||||
}
|
||||
|
||||
if cpuinfo.NumCore() != 2 {
|
||||
t.Fatal("wrong core number", cpuinfo.NumCore())
|
||||
}
|
||||
|
||||
if cpuinfo.NumPhysicalCPU() != 1 {
|
||||
t.Fatal("wrong physical cpu number", cpuinfo.NumPhysicalCPU())
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/c9s/goprocinfo/linux/disk.go
generated
vendored
Normal file
26
vendor/github.com/c9s/goprocinfo/linux/disk.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type Disk struct {
|
||||
All uint64 `json:"all"`
|
||||
Used uint64 `json:"used"`
|
||||
Free uint64 `json:"free"`
|
||||
FreeInodes uint64 `json:"freeInodes"`
|
||||
}
|
||||
|
||||
func ReadDisk(path string) (*Disk, error) {
|
||||
fs := syscall.Statfs_t{}
|
||||
err := syscall.Statfs(path, &fs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
disk := Disk{}
|
||||
disk.All = fs.Blocks * uint64(fs.Bsize)
|
||||
disk.Free = fs.Bfree * uint64(fs.Bsize)
|
||||
disk.Used = disk.All - disk.Free
|
||||
disk.FreeInodes = fs.Ffree
|
||||
return &disk, nil
|
||||
}
|
||||
14
vendor/github.com/c9s/goprocinfo/linux/disk_test.go
generated
vendored
Normal file
14
vendor/github.com/c9s/goprocinfo/linux/disk_test.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDisk(t *testing.T) {
|
||||
disk, err := ReadDisk("/")
|
||||
t.Logf("%+v", disk)
|
||||
if err != nil {
|
||||
t.Fatal("disk read fail")
|
||||
}
|
||||
if disk.Free <= 0 {
|
||||
t.Log("no good")
|
||||
}
|
||||
}
|
||||
100
vendor/github.com/c9s/goprocinfo/linux/diskstat.go
generated
vendored
Normal file
100
vendor/github.com/c9s/goprocinfo/linux/diskstat.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DiskStat is disk statistics to help measure disk activity.
|
||||
//
|
||||
// Note:
|
||||
// * On a very busy or long-lived system values may wrap.
|
||||
// * No kernel locks are held while modifying these counters. This implies that
|
||||
// minor inaccuracies may occur.
|
||||
//
|
||||
// More more info see:
|
||||
// https://www.kernel.org/doc/Documentation/iostats.txt and
|
||||
// https://www.kernel.org/doc/Documentation/block/stat.txt
|
||||
type DiskStat struct {
|
||||
Major int `json:"major"` // major device number
|
||||
Minor int `json:"minor"` // minor device number
|
||||
Name string `json:"name"` // device name
|
||||
ReadIOs uint64 `json:"read_ios"` // number of read I/Os processed
|
||||
ReadMerges uint64 `json:"read_merges"` // number of read I/Os merged with in-queue I/O
|
||||
ReadSectors uint64 `json:"read_sectors"` // number of 512 byte sectors read
|
||||
ReadTicks uint64 `json:"read_ticks"` // total wait time for read requests in milliseconds
|
||||
WriteIOs uint64 `json:"write_ios"` // number of write I/Os processed
|
||||
WriteMerges uint64 `json:"write_merges"` // number of write I/Os merged with in-queue I/O
|
||||
WriteSectors uint64 `json:"write_sectors"` // number of 512 byte sectors written
|
||||
WriteTicks uint64 `json:"write_ticks"` // total wait time for write requests in milliseconds
|
||||
InFlight uint64 `json:"in_flight"` // number of I/Os currently in flight
|
||||
IOTicks uint64 `json:"io_ticks"` // total time this block device has been active in milliseconds
|
||||
TimeInQueue uint64 `json:"time_in_queue"` // total wait time for all requests in milliseconds
|
||||
}
|
||||
|
||||
// ReadDiskStats reads and parses the file.
|
||||
//
|
||||
// Note:
|
||||
// * Assumes a well formed file and will panic if it isn't.
|
||||
func ReadDiskStats(path string) ([]DiskStat, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
devices := strings.Split(string(data), "\n")
|
||||
results := make([]DiskStat, len(devices)-1)
|
||||
|
||||
for i := range results {
|
||||
fields := strings.Fields(devices[i])
|
||||
Major, _ := strconv.ParseInt(fields[0], 10, strconv.IntSize)
|
||||
results[i].Major = int(Major)
|
||||
Minor, _ := strconv.ParseInt(fields[1], 10, strconv.IntSize)
|
||||
results[i].Minor = int(Minor)
|
||||
results[i].Name = fields[2]
|
||||
results[i].ReadIOs, _ = strconv.ParseUint(fields[3], 10, 64)
|
||||
results[i].ReadMerges, _ = strconv.ParseUint(fields[4], 10, 64)
|
||||
results[i].ReadSectors, _ = strconv.ParseUint(fields[5], 10, 64)
|
||||
results[i].ReadTicks, _ = strconv.ParseUint(fields[6], 10, 64)
|
||||
results[i].WriteIOs, _ = strconv.ParseUint(fields[7], 10, 64)
|
||||
results[i].WriteMerges, _ = strconv.ParseUint(fields[8], 10, 64)
|
||||
results[i].WriteSectors, _ = strconv.ParseUint(fields[9], 10, 64)
|
||||
results[i].WriteTicks, _ = strconv.ParseUint(fields[10], 10, 64)
|
||||
results[i].InFlight, _ = strconv.ParseUint(fields[11], 10, 64)
|
||||
results[i].IOTicks, _ = strconv.ParseUint(fields[12], 10, 64)
|
||||
results[i].TimeInQueue, _ = strconv.ParseUint(fields[13], 10, 64)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// GetReadBytes returns the number of bytes read.
|
||||
func (ds *DiskStat) GetReadBytes() int64 {
|
||||
return int64(ds.ReadSectors) * 512
|
||||
}
|
||||
|
||||
// GetReadTicks returns the duration waited for read requests.
|
||||
func (ds *DiskStat) GetReadTicks() time.Duration {
|
||||
return time.Duration(ds.ReadTicks) * time.Millisecond
|
||||
}
|
||||
|
||||
// GetWriteBytes returns the number of bytes written.
|
||||
func (ds *DiskStat) GetWriteBytes() int64 {
|
||||
return int64(ds.WriteSectors) * 512
|
||||
}
|
||||
|
||||
// GetReadTicks returns the duration waited for write requests.
|
||||
func (ds *DiskStat) GetWriteTicks() time.Duration {
|
||||
return time.Duration(ds.WriteTicks) * time.Millisecond
|
||||
}
|
||||
|
||||
// GetIOTicks returns the duration the disk has been active.
|
||||
func (ds *DiskStat) GetIOTicks() time.Duration {
|
||||
return time.Duration(ds.IOTicks) * time.Millisecond
|
||||
}
|
||||
|
||||
// GetTimeInQueue returns the duration waited for all requests.
|
||||
func (ds *DiskStat) GetTimeInQueue() time.Duration {
|
||||
return time.Duration(ds.TimeInQueue) * time.Millisecond
|
||||
}
|
||||
56
vendor/github.com/c9s/goprocinfo/linux/diskstat_test.go
generated
vendored
Normal file
56
vendor/github.com/c9s/goprocinfo/linux/diskstat_test.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDiskStats(t *testing.T) {
|
||||
|
||||
var expected = []DiskStat{
|
||||
{8, 0, "sda", 408408680, 130632009, 4314826058, 420257268, 1096727, 1393188, 17797821, 100425864, 0, 28419096, 520607448},
|
||||
{8, 1, "sda1", 408408656, 130632009, 4314825866, 420257172, 833896, 1393188, 17797821, 97461104, 0, 27780028, 517642756},
|
||||
{8, 32, "sdc", 783343, 36781, 110773558, 4017272, 361505, 12583190, 103537696, 36551180, 1, 2894524, 40572548},
|
||||
{8, 33, "sdc1", 782412, 36169, 110761218, 4013708, 355897, 12581496, 103518680, 36525596, 1, 2871296, 40543408},
|
||||
{8, 34, "sdc2", 2, 0, 4, 516, 0, 0, 0, 0, 0, 516, 516},
|
||||
{8, 37, "sdc5", 683, 612, 10360, 2088, 683, 1694, 19016, 1368, 0, 2436, 3452},
|
||||
{8, 16, "sdb", 312308426, 182345841, 3959499204, 361778396, 1106171, 1389910, 17845949, 43843528, 0, 29961500, 405464444},
|
||||
{8, 17, "sdb1", 312308273, 182345841, 3959497980, 361778280, 843340, 1389910, 17845949, 41908056, 0, 29850872, 403529168},
|
||||
{8, 48, "sdd", 417146071, 77508205, 3959480897, 326427168, 1111215, 1414930, 18087405, 81691580, 0, 24858444, 407955392},
|
||||
{8, 49, "sdd1", 417145917, 77508205, 3959479665, 326427124, 848384, 1414930, 18087405, 78896812, 0, 24244124, 405160740},
|
||||
{8, 96, "sdg", 235527286, 259133373, 3959571171, 622690468, 1103264, 1412477, 18003005, 55607916, 0, 40736480, 678171012},
|
||||
{8, 97, "sdg1", 235527254, 259133373, 3959570915, 622690416, 840433, 1412477, 18003005, 53727712, 0, 40290036, 676291336},
|
||||
{8, 112, "sdh", 236183930, 258478518, 3959539350, 736661480, 1102696, 1417936, 18042109, 234611108, 3, 168077436, 1235195636},
|
||||
{8, 113, "sdh1", 236183899, 258478518, 3959539102, 736661420, 839866, 1417936, 18042109, 231864320, 2, 167583296, 1106678880},
|
||||
{8, 128, "sdi", 241879666, 252778748, 3959567060, 565428444, 1077187, 1403162, 17722541, 139558580, 0, 39615292, 704848044},
|
||||
{8, 129, "sdi1", 241879648, 252778748, 3959566916, 565428432, 814356, 1403162, 17722541, 136947936, 0, 39169104, 702237520},
|
||||
{8, 144, "sdj", 239842786, 254815073, 3959571267, 605240464, 1093790, 1412969, 17933493, 217510180, 0, 40249492, 822590992},
|
||||
{8, 145, "sdj1", 239842768, 254815073, 3959571123, 605240444, 830959, 1412969, 17933493, 214796948, 0, 39767160, 819880212},
|
||||
{8, 176, "sdl", 108207, 237256, 2854160, 13616744, 68344261, 905844149, 7819441640, 2108756004, 0, 54571620, 2128460032},
|
||||
{8, 177, "sdl1", 107707, 237243, 2850056, 13611560, 64425824, 421281850, 3912412464, 135188688, 0, 40488396, 154892008},
|
||||
{8, 64, "sde", 244185799, 250469327, 3959527864, 359434792, 1100737, 1407009, 17939589, 49226088, 0, 38876124, 408523288},
|
||||
{8, 65, "sde1", 244185781, 250469327, 3959527720, 359434700, 837906, 1407009, 17939589, 47151748, 0, 38603948, 406448252},
|
||||
{8, 80, "sdf", 240921831, 253733300, 3959498760, 353025952, 1128792, 1408474, 18175485, 53618980, 0, 38840468, 406489356},
|
||||
{8, 81, "sdf1", 240921678, 253733300, 3959497536, 353025840, 865961, 1408474, 18175485, 51534252, 0, 38585732, 404403848},
|
||||
{8, 160, "sdk", 236490604, 258168217, 3959527459, 1334815348, 1130766, 1411015, 18211397, 41485768, 0, 47199324, 1376168140},
|
||||
{8, 161, "sdk1", 236490587, 258168217, 3959527323, 1334815288, 867935, 1411015, 18211397, 39843692, 0, 46972288, 1374525752},
|
||||
{7, 0, "loop0", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{7, 1, "loop1", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{7, 2, "loop2", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{7, 3, "loop3", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{7, 4, "loop4", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{7, 5, "loop5", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{7, 6, "loop6", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{7, 7, "loop7", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{9, 2, "md2", 796135, 0, 31381793, 0, 1575830, 0, 72485781, 0, 0, 0, 0},
|
||||
{253, 0, "dm-0", 795799, 0, 31379112, 17971064, 1316610, 0, 72485909, 3892582864, 4, 144707052, 5470248},
|
||||
}
|
||||
|
||||
stats, err := ReadDiskStats("proc/diskstats")
|
||||
if err != nil {
|
||||
t.Fatal("disk stat read fail")
|
||||
}
|
||||
if !reflect.DeepEqual(stats, expected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
}
|
||||
67
vendor/github.com/c9s/goprocinfo/linux/loadavg.go
generated
vendored
Normal file
67
vendor/github.com/c9s/goprocinfo/linux/loadavg.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LoadAvg struct {
|
||||
Last1Min float64 `json:"last1min"`
|
||||
Last5Min float64 `json:"last5min"`
|
||||
Last15Min float64 `json:"last15min"`
|
||||
ProcessRunning uint64 `json:"process_running"`
|
||||
ProcessTotal uint64 `json:"process_total"`
|
||||
LastPID uint64 `json:"last_pid"`
|
||||
}
|
||||
|
||||
func ReadLoadAvg(path string) (*LoadAvg, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
content := strings.TrimSpace(string(b))
|
||||
fields := strings.Fields(content)
|
||||
|
||||
if len(fields) < 5 {
|
||||
return nil, errors.New("Cannot parse loadavg: " + content)
|
||||
}
|
||||
|
||||
process := strings.Split(fields[3], "/")
|
||||
|
||||
if len(process) != 2 {
|
||||
return nil, errors.New("Cannot parse loadavg: " + content)
|
||||
}
|
||||
|
||||
loadavg := LoadAvg{}
|
||||
|
||||
if loadavg.Last1Min, err = strconv.ParseFloat(fields[0], 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if loadavg.Last5Min, err = strconv.ParseFloat(fields[1], 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if loadavg.Last15Min, err = strconv.ParseFloat(fields[2], 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if loadavg.ProcessRunning, err = strconv.ParseUint(process[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if loadavg.ProcessTotal, err = strconv.ParseUint(process[1], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if loadavg.LastPID, err = strconv.ParseUint(fields[4], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &loadavg, nil
|
||||
}
|
||||
30
vendor/github.com/c9s/goprocinfo/linux/loadavg_test.go
generated
vendored
Normal file
30
vendor/github.com/c9s/goprocinfo/linux/loadavg_test.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadAvg(t *testing.T) {
|
||||
|
||||
loadavg, err := ReadLoadAvg("proc/loadavg")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("read loadavg fail", err)
|
||||
}
|
||||
|
||||
expected := &LoadAvg{
|
||||
Last1Min: 0.01,
|
||||
Last5Min: 0.02,
|
||||
Last15Min: 0.05,
|
||||
ProcessRunning: 1,
|
||||
ProcessTotal: 135,
|
||||
LastPID: 11975,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(loadavg, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", loadavg)
|
||||
}
|
||||
97
vendor/github.com/c9s/goprocinfo/linux/meminfo.go
generated
vendored
Normal file
97
vendor/github.com/c9s/goprocinfo/linux/meminfo.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MemInfo struct {
|
||||
MemTotal uint64 `json:"mem_total"`
|
||||
MemFree uint64 `json:"mem_free"`
|
||||
MemAvailable uint64 `json:"mem_available"`
|
||||
Buffers uint64 `json:"buffers"`
|
||||
Cached uint64 `json:"cached"`
|
||||
SwapCached uint64 `json:"swap_cached"`
|
||||
Active uint64 `json:"active"`
|
||||
Inactive uint64 `json:"inactive"`
|
||||
ActiveAnon uint64 `json:"active_anon" field:"Active(anon)"`
|
||||
InactiveAnon uint64 `json:"inactive_anon" field:"Inactive(anon)"`
|
||||
ActiveFile uint64 `json:"active_file" field:"Active(file)"`
|
||||
InactiveFile uint64 `json:"inactive_file" field:"Inactive(file)"`
|
||||
Unevictable uint64 `json:"unevictable"`
|
||||
Mlocked uint64 `json:"mlocked"`
|
||||
SwapTotal uint64 `json:"swap_total"`
|
||||
SwapFree uint64 `json:"swap_free"`
|
||||
Dirty uint64 `json:"dirty"`
|
||||
Writeback uint64 `json:"write_back"`
|
||||
AnonPages uint64 `json:"anon_pages"`
|
||||
Mapped uint64 `json:"mapped"`
|
||||
Shmem uint64 `json:"shmem"`
|
||||
Slab uint64 `json:"slab"`
|
||||
SReclaimable uint64 `json:"s_reclaimable"`
|
||||
SUnreclaim uint64 `json:"s_unclaim"`
|
||||
KernelStack uint64 `json:"kernel_stack"`
|
||||
PageTables uint64 `json:"page_tables"`
|
||||
NFS_Unstable uint64 `json:"nfs_unstable"`
|
||||
Bounce uint64 `json:"bounce"`
|
||||
WritebackTmp uint64 `json:"writeback_tmp"`
|
||||
CommitLimit uint64 `json:"commit_limit"`
|
||||
Committed_AS uint64 `json:"committed_as"`
|
||||
VmallocTotal uint64 `json:"vmalloc_total"`
|
||||
VmallocUsed uint64 `json:"vmalloc_used"`
|
||||
VmallocChunk uint64 `json:"vmalloc_chunk"`
|
||||
HardwareCorrupted uint64 `json:"hardware_corrupted"`
|
||||
AnonHugePages uint64 `json:"anon_huge_pages"`
|
||||
HugePages_Total uint64 `json:"huge_pages_total"`
|
||||
HugePages_Free uint64 `json:"huge_pages_free"`
|
||||
HugePages_Rsvd uint64 `json:"huge_pages_rsvd"`
|
||||
HugePages_Surp uint64 `json:"huge_pages_surp"`
|
||||
Hugepagesize uint64 `json:"hugepagesize"`
|
||||
DirectMap4k uint64 `json:"direct_map_4k"`
|
||||
DirectMap2M uint64 `json:"direct_map_2M"`
|
||||
DirectMap1G uint64 `json:"direct_map_1G"`
|
||||
}
|
||||
|
||||
func ReadMemInfo(path string) (*MemInfo, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(data), "\n")
|
||||
|
||||
// Maps a meminfo metric to its value (i.e. MemTotal --> 100000)
|
||||
statMap := make(map[string]uint64)
|
||||
|
||||
var info = MemInfo{}
|
||||
|
||||
for _, line := range lines {
|
||||
fields := strings.SplitN(line, ":", 2)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
valFields := strings.Fields(fields[1])
|
||||
val, _ := strconv.ParseUint(valFields[0], 10, 64)
|
||||
statMap[fields[0]] = val
|
||||
}
|
||||
|
||||
elem := reflect.ValueOf(&info).Elem()
|
||||
typeOfElem := elem.Type()
|
||||
|
||||
for i := 0; i < elem.NumField(); i++ {
|
||||
val, ok := statMap[typeOfElem.Field(i).Name]
|
||||
if ok {
|
||||
elem.Field(i).SetUint(val)
|
||||
continue
|
||||
}
|
||||
val, ok = statMap[typeOfElem.Field(i).Tag.Get("field")]
|
||||
if ok {
|
||||
elem.Field(i).SetUint(val)
|
||||
}
|
||||
}
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
61
vendor/github.com/c9s/goprocinfo/linux/meminfo_test.go
generated
vendored
Normal file
61
vendor/github.com/c9s/goprocinfo/linux/meminfo_test.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMemInfo(t *testing.T) {
|
||||
{
|
||||
var expected = MemInfo{1011048, 92096, 0, 44304, 681228, 4, 494100, 306804, 71424, 9576, 422676, 297228, 0, 0, 524284, 524280, 28, 0, 75444, 26384, 5624, 60884, 45068, 15816, 1112, 2936, 0, 0, 0, 1029808, 528152, 34359738367, 10504, 34359725792, 0, 0, 0, 0, 0, 0, 2048, 1056768, 0, 0}
|
||||
|
||||
read, err := ReadMemInfo("proc/meminfo_1")
|
||||
if err != nil {
|
||||
t.Fatal("meminfo read fail")
|
||||
}
|
||||
t.Logf("%+v", read)
|
||||
|
||||
if err := compareExpectedReadFieldsMemInfo(&expected, read); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*read, expected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
}
|
||||
{
|
||||
var expected = MemInfo{132003228, 126199196, 130327756, 819908, 2910788, 0, 3043760, 1027084, 340788, 1056, 2702972, 1026028, 0, 0, 3903484, 3903484, 8, 0, 342276, 72380, 1704, 899472, 737432, 162040, 7328, 7120, 0, 0, 0, 69905096, 1024672, 34359738367, 495100, 34290957508, 0, 172032, 0, 0, 0, 0, 2048, 143652, 14501888, 121634816}
|
||||
|
||||
read, err := ReadMemInfo("proc/meminfo_2")
|
||||
if err != nil {
|
||||
t.Fatal("meminfo read fail")
|
||||
}
|
||||
t.Logf("%+v", read)
|
||||
|
||||
if err := compareExpectedReadFieldsMemInfo(&expected, read); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*read, expected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This is a helper function which makes it easier to track down errors in expected versus read values.
|
||||
func compareExpectedReadFieldsMemInfo(expected *MemInfo, read *MemInfo) error {
|
||||
elemExpected := reflect.ValueOf(*expected)
|
||||
typeOfElemExpected := elemExpected.Type()
|
||||
elemRead := reflect.ValueOf(*read)
|
||||
|
||||
for i := 0; i < elemExpected.NumField(); i++ {
|
||||
fieldName := typeOfElemExpected.Field(i).Name
|
||||
|
||||
if elemExpected.Field(i).Uint() != elemRead.Field(i).Uint() {
|
||||
return fmt.Errorf("Read value not equal to expected value for field %s. Got %d and expected %d.", fieldName, elemRead.Field(i).Uint(), elemExpected.Field(i).Uint())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
49
vendor/github.com/c9s/goprocinfo/linux/mounts.go
generated
vendored
Normal file
49
vendor/github.com/c9s/goprocinfo/linux/mounts.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Mounts struct {
|
||||
Mounts []Mount `json:"mounts"`
|
||||
}
|
||||
|
||||
type Mount struct {
|
||||
Device string `json:"device"`
|
||||
MountPoint string `json:"mountpoint"`
|
||||
FSType string `json:"fstype"`
|
||||
Options string `json:"options"`
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultBufferSize = 1024
|
||||
)
|
||||
|
||||
func ReadMounts(path string) (*Mounts, error) {
|
||||
fin, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fin.Close()
|
||||
|
||||
var mounts = Mounts{}
|
||||
|
||||
scanner := bufio.NewScanner(fin)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
var mount = &Mount{
|
||||
fields[0],
|
||||
fields[1],
|
||||
fields[2],
|
||||
fields[3],
|
||||
}
|
||||
mounts.Mounts = append(mounts.Mounts, *mount)
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mounts, nil
|
||||
}
|
||||
19
vendor/github.com/c9s/goprocinfo/linux/mounts_test.go
generated
vendored
Normal file
19
vendor/github.com/c9s/goprocinfo/linux/mounts_test.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMounts(t *testing.T) {
|
||||
mounts, err := ReadMounts("proc/mounts")
|
||||
if err != nil {
|
||||
t.Fatal("mounts read fail")
|
||||
}
|
||||
t.Logf("%+v", mounts)
|
||||
if mounts.Mounts[0].Device != "rootfs" {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
if mounts.Mounts[1].FSType != "proc" {
|
||||
t.Fatal("unexpected value")
|
||||
}
|
||||
}
|
||||
173
vendor/github.com/c9s/goprocinfo/linux/net_ip.go
generated
vendored
Normal file
173
vendor/github.com/c9s/goprocinfo/linux/net_ip.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ipv4RegExp = regexp.MustCompile("^[0-9a-fA-F]{8}:[0-9a-fA-F]{4}$") // Regex for NetIPv4Decoder
|
||||
ipv6RegExp = regexp.MustCompile("^[0-9a-fA-F]{32}:[0-9a-fA-F]{4}$") // Regex for NetIPv6Decoder
|
||||
)
|
||||
|
||||
type NetIPDecoder func(string) (string, error) // Either NetIPv4Decoder or NetIPv6Decoder
|
||||
|
||||
type NetSocket struct {
|
||||
LocalAddress string `json:"local_address"`
|
||||
RemoteAddress string `json:"remote_address"`
|
||||
Status uint8 `json:"st"`
|
||||
TxQueue uint64 `json:"tx_queue"`
|
||||
RxQueue uint64 `json:"rx_queue"`
|
||||
Uid uint32 `json:"uid"`
|
||||
Inode uint64 `json:"inode"`
|
||||
SocketReferenceCount uint64 `json:"ref"`
|
||||
}
|
||||
|
||||
func parseNetSocket(f []string, ip NetIPDecoder) (*NetSocket, error) {
|
||||
|
||||
if len(f) < 11 {
|
||||
return nil, errors.New("Cannot parse net socket line: " + strings.Join(f, " "))
|
||||
}
|
||||
|
||||
if strings.Index(f[4], ":") == -1 {
|
||||
return nil, errors.New("Cannot parse tx/rx queues: " + f[4])
|
||||
}
|
||||
|
||||
q := strings.Split(f[4], ":")
|
||||
|
||||
socket := &NetSocket{}
|
||||
|
||||
var s uint64 // socket.Status
|
||||
var u uint64 // socket.Uid
|
||||
var err error // parse error
|
||||
|
||||
if socket.LocalAddress, err = ip(f[1]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if socket.RemoteAddress, err = ip(f[2]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s, err = strconv.ParseUint(f[3], 16, 8); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if socket.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if socket.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if u, err = strconv.ParseUint(f[7], 10, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if socket.Inode, err = strconv.ParseUint(f[9], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if socket.SocketReferenceCount, err = strconv.ParseUint(f[10], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
socket.Status = uint8(s)
|
||||
socket.Uid = uint32(u)
|
||||
|
||||
return socket, nil
|
||||
}
|
||||
|
||||
// Decode an IPv4 address with port from a given hex string
|
||||
// NOTE: This function match NetIPDecoder type
|
||||
func NetIPv4Decoder(s string) (string, error) {
|
||||
|
||||
if !ipv4RegExp.MatchString(s) {
|
||||
return "", errors.New("Cannot decode ipv4 address: " + s)
|
||||
}
|
||||
|
||||
i := strings.Split(s, ":")
|
||||
|
||||
b := make([]byte, 4)
|
||||
|
||||
for j := 0; j < 4; j++ {
|
||||
|
||||
x := j * 2
|
||||
y := x + 2
|
||||
z := 3 - j
|
||||
|
||||
// Extract 2 characters from hex string, 4 times.
|
||||
//
|
||||
// s: "0100007F" -> [
|
||||
// h: "01", h: "00", h: "00", h: "7F",
|
||||
// ]
|
||||
h := i[0][x:y]
|
||||
|
||||
// Reverse byte order
|
||||
n, _ := strconv.ParseUint(h, 16, 8)
|
||||
b[z] = byte(n)
|
||||
|
||||
}
|
||||
|
||||
h := net.IP(b).String()
|
||||
n, _ := strconv.ParseUint(i[1], 16, 64)
|
||||
p := strconv.FormatUint(n, 10)
|
||||
|
||||
// ipv4:port
|
||||
v := h + ":" + p
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Decode an IPv6 address with port from a given hex string
|
||||
// NOTE: This function match NetIPDecoder type
|
||||
func NetIPv6Decoder(s string) (string, error) {
|
||||
|
||||
if !ipv6RegExp.MatchString(s) {
|
||||
return "", errors.New("Cannot decode ipv6 address: " + s)
|
||||
}
|
||||
|
||||
i := strings.Split(s, ":")
|
||||
|
||||
b := make([]byte, 16)
|
||||
|
||||
for j := 0; j < 4; j++ {
|
||||
|
||||
x := j * 8
|
||||
y := x + 8
|
||||
|
||||
// Extract 8 characters from hex string, 4 times.
|
||||
//
|
||||
// s: "350E012A900F122E85EDEAADA64DAAD1" -> [
|
||||
// h: "350E012A", h: "900F122E",
|
||||
// h: "85EDEAAD", h: "A64DAAD1",
|
||||
// ]
|
||||
h := i[0][x:y]
|
||||
|
||||
for k := 0; k < 4; k++ {
|
||||
|
||||
// Reverse byte order
|
||||
// "350E012A" -> [ 0x2A, 0x01, 0x0E, 0x35 ]
|
||||
z := (j * 4) + k
|
||||
g := 8 - (k * 2)
|
||||
f := g - 2
|
||||
|
||||
n, _ := strconv.ParseUint(h[f:g], 16, 8)
|
||||
b[z] = byte(n)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
h := net.IP(b).String()
|
||||
n, _ := strconv.ParseUint(i[1], 16, 64)
|
||||
p := strconv.FormatUint(n, 10)
|
||||
|
||||
// ipv6:port
|
||||
v := h + ":" + p
|
||||
|
||||
return v, nil
|
||||
}
|
||||
65
vendor/github.com/c9s/goprocinfo/linux/net_ip_test.go
generated
vendored
Normal file
65
vendor/github.com/c9s/goprocinfo/linux/net_ip_test.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNetIPv4DecoderRemote(t *testing.T) {
|
||||
|
||||
ip, err := NetIPv4Decoder("00000000:0050")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net ipv4 decode fail", err)
|
||||
}
|
||||
|
||||
if ip != "0.0.0.0:80" {
|
||||
t.Error("unexpected value")
|
||||
}
|
||||
|
||||
t.Logf("%+v", ip)
|
||||
}
|
||||
|
||||
func TestNetIPv4DecoderLocal(t *testing.T) {
|
||||
|
||||
ip, err := NetIPv4Decoder("0100007F:1F90")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net ipv4 decode fail", err)
|
||||
}
|
||||
|
||||
if ip != "127.0.0.1:8080" {
|
||||
t.Error("unexpected value")
|
||||
}
|
||||
|
||||
t.Logf("%+v", ip)
|
||||
}
|
||||
|
||||
func TestNetIPv6DecoderRemote(t *testing.T) {
|
||||
|
||||
ip, err := NetIPv6Decoder("350E012A900F122E85EDEAADA64DAAD1:0016")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net ipv6 decode fail", err)
|
||||
}
|
||||
|
||||
if ip != "2a01:e35:2e12:f90:adea:ed85:d1aa:4da6:22" {
|
||||
t.Error("unexpected value")
|
||||
}
|
||||
|
||||
t.Logf("%+v", ip)
|
||||
}
|
||||
|
||||
func TestNetIPv6DecoderLocal(t *testing.T) {
|
||||
|
||||
ip, err := NetIPv6Decoder("00000000000000000000000001000000:2328")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net ipv6 decode fail", err)
|
||||
}
|
||||
|
||||
if ip != "::1:9000" {
|
||||
t.Error("unexpected value")
|
||||
}
|
||||
|
||||
t.Logf("%+v", ip)
|
||||
}
|
||||
82
vendor/github.com/c9s/goprocinfo/linux/net_tcp.go
generated
vendored
Normal file
82
vendor/github.com/c9s/goprocinfo/linux/net_tcp.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NetTCPSockets struct {
|
||||
Sockets []NetTCPSocket `json:"sockets"`
|
||||
}
|
||||
|
||||
type NetTCPSocket struct {
|
||||
NetSocket
|
||||
RetransmitTimeout uint64 `json:"retransmit_timeout"`
|
||||
PredictedTick uint64 `json:"predicted_tick"`
|
||||
AckQuick uint8 `json:"ack_quick"`
|
||||
AckPingpong bool `json:"ack_pingpong"`
|
||||
SendingCongestionWindow uint64 `json:"sending_congestion_window"`
|
||||
SlowStartSizeThreshold int64 `json:"slow_start_size_threshold"`
|
||||
}
|
||||
|
||||
func ReadNetTCPSockets(path string, ip NetIPDecoder) (*NetTCPSockets, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(b), "\n")
|
||||
|
||||
tcp := &NetTCPSockets{}
|
||||
|
||||
for i := 1; i < len(lines); i++ {
|
||||
|
||||
line := lines[i]
|
||||
|
||||
f := strings.Fields(line)
|
||||
|
||||
if len(f) < 17 {
|
||||
continue
|
||||
}
|
||||
|
||||
s, err := parseNetSocket(f, ip)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var n int64
|
||||
e := &NetTCPSocket{
|
||||
NetSocket: *s,
|
||||
}
|
||||
|
||||
if e.RetransmitTimeout, err = strconv.ParseUint(f[12], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if e.PredictedTick, err = strconv.ParseUint(f[13], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n, err = strconv.ParseInt(f[14], 10, 8); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.AckQuick = uint8(n >> 1)
|
||||
e.AckPingpong = ((n & 1) == 1)
|
||||
|
||||
if e.SendingCongestionWindow, err = strconv.ParseUint(f[15], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if e.SlowStartSizeThreshold, err = strconv.ParseInt(f[16], 10, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tcp.Sockets = append(tcp.Sockets, *e)
|
||||
}
|
||||
|
||||
return tcp, nil
|
||||
}
|
||||
88
vendor/github.com/c9s/goprocinfo/linux/net_tcp_test.go
generated
vendored
Normal file
88
vendor/github.com/c9s/goprocinfo/linux/net_tcp_test.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadNetTCP(t *testing.T) {
|
||||
|
||||
tcp, err := ReadNetTCPSockets("proc/net_tcp", NetIPv4Decoder)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net tcp read fail", err)
|
||||
}
|
||||
|
||||
expected := &NetTCPSockets{
|
||||
Sockets: []NetTCPSocket{
|
||||
NetTCPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "127.0.0.1:8080", RemoteAddress: "0.0.0.0:0", Status: 10,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 1000, Inode: 569261, SocketReferenceCount: 1,
|
||||
},
|
||||
RetransmitTimeout: 100, PredictedTick: 0, AckQuick: 0, AckPingpong: false,
|
||||
SendingCongestionWindow: 10, SlowStartSizeThreshold: -1,
|
||||
},
|
||||
NetTCPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "0.0.0.0:80", RemoteAddress: "0.0.0.0:0", Status: 10,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 4609, SocketReferenceCount: 1,
|
||||
},
|
||||
RetransmitTimeout: 100, PredictedTick: 0, AckQuick: 0, AckPingpong: false,
|
||||
SendingCongestionWindow: 10, SlowStartSizeThreshold: -1,
|
||||
},
|
||||
NetTCPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "0.0.0.0:22", RemoteAddress: "0.0.0.0:0", Status: 10,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 420553, SocketReferenceCount: 1,
|
||||
},
|
||||
RetransmitTimeout: 100, PredictedTick: 0, AckQuick: 0, AckPingpong: false,
|
||||
SendingCongestionWindow: 10, SlowStartSizeThreshold: -1,
|
||||
},
|
||||
NetTCPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "10.0.7.21:22", RemoteAddress: "10.0.251.11:53280", Status: 1,
|
||||
TxQueue: 96, RxQueue: 0, Uid: 0, Inode: 582338, SocketReferenceCount: 4,
|
||||
},
|
||||
RetransmitTimeout: 29, PredictedTick: 4, AckQuick: 13, AckPingpong: true,
|
||||
SendingCongestionWindow: 10, SlowStartSizeThreshold: -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tcp, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", tcp)
|
||||
|
||||
}
|
||||
|
||||
func TestReadNetTCP6(t *testing.T) {
|
||||
|
||||
tcp, err := ReadNetTCPSockets("proc/net_tcp6", NetIPv6Decoder)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net tcp read fail", err)
|
||||
}
|
||||
|
||||
expected := &NetTCPSockets{
|
||||
Sockets: []NetTCPSocket{
|
||||
NetTCPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: ":::22", RemoteAddress: ":::0", Status: 10,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 420555, SocketReferenceCount: 1,
|
||||
},
|
||||
RetransmitTimeout: 100, PredictedTick: 0, AckQuick: 0, AckPingpong: false,
|
||||
SendingCongestionWindow: 2, SlowStartSizeThreshold: -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tcp, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", tcp)
|
||||
|
||||
}
|
||||
59
vendor/github.com/c9s/goprocinfo/linux/net_udp.go
generated
vendored
Normal file
59
vendor/github.com/c9s/goprocinfo/linux/net_udp.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NetUDPSockets struct {
|
||||
Sockets []NetUDPSocket `json:"sockets"`
|
||||
}
|
||||
|
||||
type NetUDPSocket struct {
|
||||
NetSocket
|
||||
Drops uint64 `json:"drops"`
|
||||
}
|
||||
|
||||
func ReadNetUDPSockets(path string, ip NetIPDecoder) (*NetUDPSockets, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(b), "\n")
|
||||
|
||||
udp := &NetUDPSockets{}
|
||||
|
||||
for i := 1; i < len(lines); i++ {
|
||||
|
||||
line := lines[i]
|
||||
|
||||
f := strings.Fields(line)
|
||||
|
||||
if len(f) < 13 {
|
||||
continue
|
||||
}
|
||||
|
||||
s, err := parseNetSocket(f, ip)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e := &NetUDPSocket{
|
||||
NetSocket: *s,
|
||||
Drops: 0,
|
||||
}
|
||||
|
||||
if e.Drops, err = strconv.ParseUint(f[12], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
udp.Sockets = append(udp.Sockets, *e)
|
||||
}
|
||||
|
||||
return udp, nil
|
||||
}
|
||||
137
vendor/github.com/c9s/goprocinfo/linux/net_udp_test.go
generated
vendored
Normal file
137
vendor/github.com/c9s/goprocinfo/linux/net_udp_test.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadNetUDP(t *testing.T) {
|
||||
|
||||
udp, err := ReadNetUDPSockets("proc/net_udp", NetIPv4Decoder)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net udp read fail", err)
|
||||
}
|
||||
|
||||
expected := &NetUDPSockets{
|
||||
Sockets: []NetUDPSocket{
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "127.0.0.1:53", RemoteAddress: "0.0.0.0:0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 11833, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "0.0.0.0:68", RemoteAddress: "0.0.0.0:0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 12616, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "192.168.1.111:123", RemoteAddress: "0.0.0.0:0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 18789, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "127.0.0.1:123", RemoteAddress: "0.0.0.0:0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 18788, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "0.0.0.0:123", RemoteAddress: "0.0.0.0:0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 18781, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "0.0.0.0:5353", RemoteAddress: "0.0.0.0:0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 109, Inode: 9025, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 2237,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(udp, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", udp)
|
||||
}
|
||||
|
||||
func TestReadNetUDP6(t *testing.T) {
|
||||
|
||||
udp, err := ReadNetUDPSockets("proc/net_udp6", NetIPv6Decoder)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("net udp read fail", err)
|
||||
}
|
||||
|
||||
expected := &NetUDPSockets{
|
||||
Sockets: []NetUDPSocket{
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "::1:123", RemoteAddress: ":::0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 840244, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "fe80::221:6aff:fea0:dd5e:123", RemoteAddress: ":::0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 840243, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "fe80::226:b9ff:fe1f:155e:123", RemoteAddress: ":::0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 840242, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "2a01:e35:2e12:f90:226:b9ff:fe1f:155e:123", RemoteAddress: ":::0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 840241, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: "2a01:e35:2e12:f90:adea:ed85:d1aa:4da6:123", RemoteAddress: ":::0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 840240, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: ":::123", RemoteAddress: ":::0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 0, Inode: 840231, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 8946,
|
||||
},
|
||||
NetUDPSocket{
|
||||
NetSocket: NetSocket{
|
||||
LocalAddress: ":::5353", RemoteAddress: ":::0", Status: 7,
|
||||
TxQueue: 0, RxQueue: 0, Uid: 109, Inode: 8944, SocketReferenceCount: 2,
|
||||
},
|
||||
Drops: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(udp, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", udp)
|
||||
}
|
||||
174
vendor/github.com/c9s/goprocinfo/linux/netstat.go
generated
vendored
Normal file
174
vendor/github.com/c9s/goprocinfo/linux/netstat.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NetStat struct {
|
||||
// TcpExt
|
||||
SyncookiesSent uint64 `json:"syncookie_sent"`
|
||||
SyncookiesRecv uint64 `json:"syncookies_recv"`
|
||||
SyncookiesFailed uint64 `json:"syncookies_failed"`
|
||||
EmbryonicRsts uint64 `json:"embryonic_rsts"`
|
||||
PruneCalled uint64 `json:"prune_called"`
|
||||
RcvPruned uint64 `json:"rcv_pruned"`
|
||||
OfoPruned uint64 `json:"ofo_pruned"`
|
||||
OutOfWindowIcmps uint64 `json:"out_of_window_icmps"`
|
||||
LockDroppedIcmps uint64 `json:"lock_dropped_icmps"`
|
||||
ArpFilter uint64 `json:"arp_filter"`
|
||||
TW uint64 `json:"tw"`
|
||||
TWRecycled uint64 `json:"tw_recycled"`
|
||||
TWKilled uint64 `json:"tw_killed"`
|
||||
PAWSPassive uint64 `json:"paws_passive"`
|
||||
PAWSActive uint64 `json:"paws_active"`
|
||||
PAWSEstab uint64 `json:"paws_estab"`
|
||||
DelayedACKs uint64 `json:"delayed_acks"`
|
||||
DelayedACKLocked uint64 `json:"delayed_ack_locked"`
|
||||
DelayedACKLost uint64 `json:"delayed_ack_lost"`
|
||||
ListenOverflows uint64 `json:"listen_overflows"`
|
||||
ListenDrops uint64 `json:"listen_drops"`
|
||||
TCPPrequeued uint64 `json:"tcp_prequeued"`
|
||||
TCPDirectCopyFromBacklog uint64 `json:"tcp_direct_copy_from_backlog"`
|
||||
TCPDirectCopyFromPrequeue uint64 `json:"tcp_direct_copy_from_prequeue"`
|
||||
TCPPrequeueDropped uint64 `json:"tcp_prequeue_dropped"`
|
||||
TCPHPHits uint64 `json:"tcp_hp_hits"`
|
||||
TCPHPHitsToUser uint64 `json:"tcp_hp_hits_to_user"`
|
||||
TCPPureAcks uint64 `json:"tcp_pure_acks"`
|
||||
TCPHPAcks uint64 `json:"tcp_hp_acks"`
|
||||
TCPRenoRecovery uint64 `json:"tcp_reno_recovery"`
|
||||
TCPSackRecovery uint64 `json:"tcp_sack_recovery"`
|
||||
TCPSACKReneging uint64 `json:"tcp_sack_reneging"`
|
||||
TCPFACKReorder uint64 `json:"tcp_fack_reorder"`
|
||||
TCPSACKReorder uint64 `json:"tcp_sack_reorder"`
|
||||
TCPRenoReorder uint64 `json:"tcp_reno_reorder"`
|
||||
TCPTSReorder uint64 `json:"tcp_ts_reorder"`
|
||||
TCPFullUndo uint64 `json:"tcp_full_undo"`
|
||||
TCPPartialUndo uint64 `json:"tcp_partial_undo"`
|
||||
TCPDSACKUndo uint64 `json:"tcp_dsack_undo"`
|
||||
TCPLossUndo uint64 `json:"tcp_loss_undo"`
|
||||
TCPLoss uint64 `json:"tcp_loss"`
|
||||
TCPLostRetransmit uint64 `json:"tcp_lost_retransmit"`
|
||||
TCPRenoFailures uint64 `json:"tcp_reno_failures"`
|
||||
TCPSackFailures uint64 `json:"tcp_sack_failures"`
|
||||
TCPLossFailures uint64 `json:"tcp_loss_failures"`
|
||||
TCPFastRetrans uint64 `json:"tcp_fast_retrans"`
|
||||
TCPForwardRetrans uint64 `json:"tcp_forward_retrans"`
|
||||
TCPSlowStartRetrans uint64 `json:"tcp_slow_start_retrans"`
|
||||
TCPTimeouts uint64 `json:"tcp_timeouts"`
|
||||
TCPLossProbes uint64 `json:"tcp_loss_probes"`
|
||||
TCPLossProbeRecovery uint64 `json:"tcp_loss_probe_recovery"`
|
||||
TCPRenoRecoveryFail uint64 `json:"tcp_reno_recovery_fail"`
|
||||
TCPSackRecoveryFail uint64 `json:"tcp_sack_recovery_fail"`
|
||||
TCPSchedulerFailed uint64 `json:"tcp_scheduler_failed"`
|
||||
TCPRcvCollapsed uint64 `json:"tcp_rcv_collapsed"`
|
||||
TCPDSACKOldSent uint64 `json:"tcp_dsack_old_sent"`
|
||||
TCPDSACKOfoSent uint64 `json:"tcp_dsack_ofo_sent"`
|
||||
TCPDSACKRecv uint64 `json:"tcp_dsack_recv"`
|
||||
TCPDSACKOfoRecv uint64 `json:"tcp_dsack_ofo_recv"`
|
||||
TCPAbortOnSyn uint64 `json:"tcp_abort_on_syn"`
|
||||
TCPAbortOnData uint64 `json:"tcp_abort_on_data"`
|
||||
TCPAbortOnClose uint64 `json:"tcp_abort_on_close"`
|
||||
TCPAbortOnMemory uint64 `json:"tcp_abort_on_memory"`
|
||||
TCPAbortOnTimeout uint64 `json:"tcp_abort_on_timeout"`
|
||||
TCPAbortOnLinger uint64 `json:"tcp_abort_on_linger"`
|
||||
TCPAbortFailed uint64 `json:"tcp_abort_failed"`
|
||||
TCPMemoryPressures uint64 `json:"tcp_memory_pressures"`
|
||||
TCPSACKDiscard uint64 `json:"tcp_sack_discard"`
|
||||
TCPDSACKIgnoredOld uint64 `json:"tcp_dsack_ignored_old"`
|
||||
TCPDSACKIgnoredNoUndo uint64 `json:"tcp_dsack_ignored_no_undo"`
|
||||
TCPSpuriousRTOs uint64 `json:"tcp_spurious_rtos"`
|
||||
TCPMD5NotFound uint64 `json:"tcp_md5_not_found"`
|
||||
TCPMD5Unexpected uint64 `json:"tcp_md5_unexpected"`
|
||||
TCPSackShifted uint64 `json:"tcp_sack_shifted"`
|
||||
TCPSackMerged uint64 `json:"tcp_sack_merged"`
|
||||
TCPSackShiftFallback uint64 `json:"tcp_sack_shift_fallback"`
|
||||
TCPBacklogDrop uint64 `json:"tcp_backlog_drop"`
|
||||
TCPMinTTLDrop uint64 `json:"tcp_min_ttl_drop"`
|
||||
TCPDeferAcceptDrop uint64 `json:"tcp_defer_accept_drop"`
|
||||
IPReversePathFilter uint64 `json:"ip_reverse_path_filter"`
|
||||
TCPTimeWaitOverflow uint64 `json:"tcp_time_wait_overflow"`
|
||||
TCPReqQFullDoCookies uint64 `json:"tcp_req_q_full_do_cookies"`
|
||||
TCPReqQFullDrop uint64 `json:"tcp_req_q_full_drop"`
|
||||
TCPRetransFail uint64 `json:"tcp_retrans_fail"`
|
||||
TCPRcvCoalesce uint64 `json:"tcp_rcv_coalesce"`
|
||||
TCPOFOQueue uint64 `json:"tcp_ofo_drop"`
|
||||
TCPOFODrop uint64 `json:"tcp_ofo_drop"`
|
||||
TCPOFOMerge uint64 `json:"tcp_ofo_merge"`
|
||||
TCPChallengeACK uint64 `json:"tcp_challenge_ack"`
|
||||
TCPSYNChallenge uint64 `json:"tcp_syn_challenge"`
|
||||
TCPFastOpenActive uint64 `json:"tcp_fast_open_active"`
|
||||
TCPFastOpenActiveFail uint64 `json:"tcp_fast_open_active_fail"`
|
||||
TCPFastOpenPassive uint64 `json:"tcp_fast_open_passive"`
|
||||
TCPFastOpenPassiveFail uint64 `json:"tcp_fast_open_passive_fail"`
|
||||
TCPFastOpenListenOverflow uint64 `json:"tcp_fast_open_listen_overflow"`
|
||||
TCPFastOpenCookieReqd uint64 `json:"tcp_fast_open_cookie_reqd"`
|
||||
TCPSpuriousRtxHostQueues uint64 `json:"tcp_spurious_rtx_host_queues"`
|
||||
BusyPollRxPackets uint64 `json:"busy_poll_rx_packets"`
|
||||
TCPAutoCorking uint64 `json:"tcp_auto_corking"`
|
||||
TCPFromZeroWindowAdv uint64 `json:"tcp_from_zero_window_adv"`
|
||||
TCPToZeroWindowAdv uint64 `json:"tcp_to_zero_window_adv"`
|
||||
TCPWantZeroWindowAdv uint64 `json:"tcp_want_zero_window_adv"`
|
||||
TCPSynRetrans uint64 `json:"tcp_syn_retrans"`
|
||||
TCPOrigDataSent uint64 `json:"tcp_orig_data_sent"`
|
||||
// IpExt
|
||||
InNoRoutes uint64 `json:"in_no_routes"`
|
||||
InTruncatedPkts uint64 `json:"in_truncated_pkts"`
|
||||
InMcastPkts uint64 `json:"in_mcast_pkts"`
|
||||
OutMcastPkts uint64 `json:"out_mcast_pkts"`
|
||||
InBcastPkts uint64 `json:"in_bcast_pkts"`
|
||||
OutBcastPkts uint64 `json:"out_bcast_pkts"`
|
||||
InOctets uint64 `json:"in_octets"`
|
||||
OutOctets uint64 `json:"out_octets"`
|
||||
InMcastOctets uint64 `json:"in_mcast_octets"`
|
||||
OutMcastOctets uint64 `json:"out_mcast_octets"`
|
||||
InBcastOctets uint64 `json:"in_bcast_octets"`
|
||||
OutBcastOctets uint64 `json:"out_bcast_octets"`
|
||||
InCsumErrors uint64 `json:"in_csum_errors"`
|
||||
InNoECTPkts uint64 `json:"in_no_ect_pkts"`
|
||||
InECT1Pkts uint64 `json:"in_ect1_pkts"`
|
||||
InECT0Pkts uint64 `json:"in_ect0_pkts"`
|
||||
InCEPkts uint64 `json:"in_ce_pkts"`
|
||||
}
|
||||
|
||||
func ReadNetStat(path string) (*NetStat, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(data), "\n")
|
||||
|
||||
// Maps a netstat metric to its value (i.e. SyncookiesSent --> 0)
|
||||
statMap := make(map[string]string)
|
||||
|
||||
// patterns
|
||||
// TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed... <-- header
|
||||
// TcpExt: 0 0 1764... <-- values
|
||||
|
||||
for i := 1; i < len(lines); i = i + 2 {
|
||||
headers := strings.Fields(lines[i-1][strings.Index(lines[i-1], ":")+1:])
|
||||
values := strings.Fields(lines[i][strings.Index(lines[i], ":")+1:])
|
||||
|
||||
for j, header := range headers {
|
||||
statMap[header] = values[j]
|
||||
}
|
||||
}
|
||||
|
||||
var netstat NetStat = NetStat{}
|
||||
|
||||
elem := reflect.ValueOf(&netstat).Elem()
|
||||
typeOfElem := elem.Type()
|
||||
|
||||
for i := 0; i < elem.NumField(); i++ {
|
||||
if val, ok := statMap[typeOfElem.Field(i).Name]; ok {
|
||||
parsedVal, _ := strconv.ParseUint(val, 10, 64)
|
||||
elem.Field(i).SetUint(parsedVal)
|
||||
}
|
||||
}
|
||||
|
||||
return &netstat, nil
|
||||
}
|
||||
63
vendor/github.com/c9s/goprocinfo/linux/netstat_test.go
generated
vendored
Normal file
63
vendor/github.com/c9s/goprocinfo/linux/netstat_test.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
import "reflect"
|
||||
import "fmt"
|
||||
|
||||
func TestNetStat(t *testing.T) {
|
||||
{
|
||||
var expected = NetStat{0, 0, 1764, 180, 0, 0, 0, 0, 0, 0, 28321, 0, 0, 0, 0, 243, 25089, 53, 837, 0, 0, 95994, 623148353, 640988091, 0, 92391, 81263, 594305, 590571, 35, 6501, 81, 113, 213, 1, 223, 318, 1056, 287, 218, 6619, 435, 1, 975, 264, 17298, 871, 5836, 3843, 0, 0, 2, 520, 0, 0, 833, 0, 3235, 44, 0, 571, 163, 0, 138, 0, 0, 0, 19, 1312, 677, 129, 0, 0, 27986, 27713, 40522, 837, 0, 38648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2772402103, 5189844022, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
read, err := ReadNetStat("proc/net_netstat_1")
|
||||
if err != nil {
|
||||
t.Fatal("netstat read fail", err)
|
||||
}
|
||||
|
||||
t.Logf("%+v", expected)
|
||||
t.Logf("%+v", read)
|
||||
|
||||
if err := compareExpectedReadFieldsNetStat(&expected, read); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*read, expected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
}
|
||||
{
|
||||
expected := NetStat{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427717, 0, 0, 0, 0, 370, 3111446, 59, 1825, 0, 0, 170176, 0, 507248, 0, 47385919, 0, 7377770, 29264396, 0, 410, 0, 3, 1, 0, 0, 4, 0, 18, 579, 0, 2, 0, 50, 6, 949, 50, 332, 1005, 5893, 978, 0, 8, 0, 0, 1838, 8, 764, 0, 0, 157868, 3281, 0, 35, 0, 0, 0, 0, 28, 453, 46, 0, 0, 226, 316, 2725, 0, 0, 0, 0, 0, 0, 0, 0, 11292855, 88470, 0, 8, 261, 198, 0, 0, 0, 0, 0, 0, 0, 0, 842446, 118, 118, 11490, 859, 105365136, 0, 0, 0, 0, 249, 0, 205328912480, 353370957921, 0, 0, 92394, 0, 0, 157218430, 0, 0, 0}
|
||||
|
||||
read, err := ReadNetStat("proc/net_netstat_2")
|
||||
if err != nil {
|
||||
t.Fatal("netstat read fail", err)
|
||||
}
|
||||
|
||||
t.Logf("%+v", expected)
|
||||
t.Logf("%+v", read)
|
||||
|
||||
if err := compareExpectedReadFieldsNetStat(&expected, read); err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(*read, expected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a helper function which makes it easier to track down errors in expected versus read values.
|
||||
func compareExpectedReadFieldsNetStat(expected *NetStat, read *NetStat) error {
|
||||
elemExpected := reflect.ValueOf(*expected)
|
||||
typeOfElemExpected := elemExpected.Type()
|
||||
elemRead := reflect.ValueOf(*read)
|
||||
|
||||
for i := 0; i < elemExpected.NumField(); i++ {
|
||||
fieldName := typeOfElemExpected.Field(i).Name
|
||||
|
||||
if elemExpected.Field(i).Uint() != elemRead.Field(i).Uint() {
|
||||
return fmt.Errorf("Read value not equal to expected value for field %s. Got %d and expected %d.", fieldName, elemRead.Field(i).Uint(), elemExpected.Field(i).Uint())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
73
vendor/github.com/c9s/goprocinfo/linux/network_stat.go
generated
vendored
Normal file
73
vendor/github.com/c9s/goprocinfo/linux/network_stat.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NetworkStat struct {
|
||||
Iface string `json:"iface"`
|
||||
RxBytes uint64 `json:"rxbytes"`
|
||||
RxPackets uint64 `json:"rxpackets"`
|
||||
RxErrs uint64 `json:"rxerrs"`
|
||||
RxDrop uint64 `json:"rxdrop"`
|
||||
RxFifo uint64 `json:"rxfifo"`
|
||||
RxFrame uint64 `json:"rxframe"`
|
||||
RxCompressed uint64 `json:"rxcompressed"`
|
||||
RxMulticast uint64 `json:"rxmulticast"`
|
||||
TxBytes uint64 `json:"txbytes"`
|
||||
TxPackets uint64 `json:"txpackets"`
|
||||
TxErrs uint64 `json:"txerrs"`
|
||||
TxDrop uint64 `json:"txdrop"`
|
||||
TxFifo uint64 `json:"txfifo"`
|
||||
TxColls uint64 `json:"txcolls"`
|
||||
TxCarrier uint64 `json:"txcarrier"`
|
||||
TxCompressed uint64 `json:"txcompressed"`
|
||||
}
|
||||
|
||||
func ReadNetworkStat(path string) ([]NetworkStat, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(data), "\n")
|
||||
|
||||
// lines[2:] remove /proc/net/dev header
|
||||
results := make([]NetworkStat, len(lines[2:])-1)
|
||||
|
||||
for i, line := range lines[2:] {
|
||||
// patterns
|
||||
// <iface>: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
// or
|
||||
// <iface>:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 (without space after colon)
|
||||
colon := strings.Index(line, ":")
|
||||
|
||||
if colon > 0 {
|
||||
metrics := line[colon+1:]
|
||||
fields := strings.Fields(metrics)
|
||||
|
||||
results[i].Iface = strings.Replace(line[0:colon], " ", "", -1)
|
||||
results[i].RxBytes, _ = strconv.ParseUint(fields[0], 10, 64)
|
||||
results[i].RxPackets, _ = strconv.ParseUint(fields[1], 10, 64)
|
||||
results[i].RxErrs, _ = strconv.ParseUint(fields[2], 10, 64)
|
||||
results[i].RxDrop, _ = strconv.ParseUint(fields[3], 10, 64)
|
||||
results[i].RxFifo, _ = strconv.ParseUint(fields[4], 10, 64)
|
||||
results[i].RxFrame, _ = strconv.ParseUint(fields[5], 10, 64)
|
||||
results[i].RxCompressed, _ = strconv.ParseUint(fields[6], 10, 64)
|
||||
results[i].RxMulticast, _ = strconv.ParseUint(fields[7], 10, 64)
|
||||
results[i].TxBytes, _ = strconv.ParseUint(fields[8], 10, 64)
|
||||
results[i].TxPackets, _ = strconv.ParseUint(fields[9], 10, 64)
|
||||
results[i].TxErrs, _ = strconv.ParseUint(fields[10], 10, 64)
|
||||
results[i].TxDrop, _ = strconv.ParseUint(fields[11], 10, 64)
|
||||
results[i].TxFifo, _ = strconv.ParseUint(fields[12], 10, 64)
|
||||
results[i].TxColls, _ = strconv.ParseUint(fields[13], 10, 64)
|
||||
results[i].TxCarrier, _ = strconv.ParseUint(fields[14], 10, 64)
|
||||
results[i].TxCompressed, _ = strconv.ParseUint(fields[15], 10, 64)
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
41
vendor/github.com/c9s/goprocinfo/linux/network_stat_test.go
generated
vendored
Normal file
41
vendor/github.com/c9s/goprocinfo/linux/network_stat_test.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
import "reflect"
|
||||
|
||||
func TestNetworkStat(t *testing.T) {
|
||||
|
||||
var expected = []NetworkStat{
|
||||
{"eth0", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{"lo", 870813, 8693, 0, 0, 0, 0, 0, 0, 870813, 8693, 0, 0, 0, 0, 0, 0},
|
||||
{"virbr0", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{"wlan0", 1163823097, 838432, 0, 0, 0, 0, 0, 0, 73047180, 641124, 0, 0, 0, 0, 0, 0},
|
||||
}
|
||||
|
||||
networkStat, err := ReadNetworkStat("proc/net_dev")
|
||||
if err != nil {
|
||||
t.Fatal("network stat read fail", err)
|
||||
}
|
||||
|
||||
t.Logf("%+v", networkStat)
|
||||
|
||||
if !reflect.DeepEqual(networkStat, expected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
|
||||
var squeezeexpected = []NetworkStat{
|
||||
{"lo", 480134461, 2323077, 0, 0, 0, 0, 0, 0, 480134461, 2323077, 0, 0, 0, 0, 0, 0},
|
||||
{"eth0", 23443246382, 63554887, 0, 0, 0, 0, 0, 0, 10900929232, 27373481, 0, 0, 0, 0, 0, 0},
|
||||
}
|
||||
|
||||
networkStat, err = ReadNetworkStat("proc/net_dev_squeeze")
|
||||
if err != nil {
|
||||
t.Fatal("network stat read fail", err)
|
||||
}
|
||||
|
||||
t.Logf("%+v", networkStat)
|
||||
|
||||
if !reflect.DeepEqual(networkStat, squeezeexpected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
}
|
||||
62
vendor/github.com/c9s/goprocinfo/linux/process.go
generated
vendored
Normal file
62
vendor/github.com/c9s/goprocinfo/linux/process.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Process struct {
|
||||
Status ProcessStatus `json:"status"`
|
||||
Statm ProcessStatm `json:"statm"`
|
||||
Stat ProcessStat `json:"stat"`
|
||||
IO ProcessIO `json:"io"`
|
||||
Cmdline string `json:"cmdline"`
|
||||
}
|
||||
|
||||
func ReadProcess(pid uint64, path string) (*Process, error) {
|
||||
|
||||
var err error
|
||||
|
||||
p := filepath.Join(path, strconv.FormatUint(pid, 10))
|
||||
|
||||
if _, err = os.Stat(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
process := Process{}
|
||||
|
||||
var io *ProcessIO
|
||||
var stat *ProcessStat
|
||||
var statm *ProcessStatm
|
||||
var status *ProcessStatus
|
||||
var cmdline string
|
||||
|
||||
if io, err = ReadProcessIO(filepath.Join(p, "io")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stat, err = ReadProcessStat(filepath.Join(p, "stat")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if statm, err = ReadProcessStatm(filepath.Join(p, "statm")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if status, err = ReadProcessStatus(filepath.Join(p, "status")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cmdline, err = ReadProcessCmdline(filepath.Join(p, "cmdline")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
process.IO = *io
|
||||
process.Stat = *stat
|
||||
process.Statm = *statm
|
||||
process.Status = *status
|
||||
process.Cmdline = cmdline
|
||||
|
||||
return &process, nil
|
||||
}
|
||||
39
vendor/github.com/c9s/goprocinfo/linux/process_cmdline.go
generated
vendored
Normal file
39
vendor/github.com/c9s/goprocinfo/linux/process_cmdline.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ReadProcessCmdline(path string) (string, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
l := len(b) - 1 // Define limit before last byte ('\0')
|
||||
z := byte(0) // '\0' or null byte
|
||||
s := byte(0x20) // space byte
|
||||
c := 0 // cursor of useful bytes
|
||||
|
||||
for i := 0; i < l; i++ {
|
||||
|
||||
// Check if next byte is not a '\0' byte.
|
||||
if b[i+1] != z {
|
||||
|
||||
// Offset must match a '\0' byte.
|
||||
c = i + 2
|
||||
|
||||
// If current byte is '\0', replace it with a space byte.
|
||||
if b[i] == z {
|
||||
b[i] = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x := strings.TrimSpace(string(b[0:c]))
|
||||
|
||||
return x, nil
|
||||
}
|
||||
39
vendor/github.com/c9s/goprocinfo/linux/process_cmdline_test.go
generated
vendored
Normal file
39
vendor/github.com/c9s/goprocinfo/linux/process_cmdline_test.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadProcessCmdlineSimple(t *testing.T) {
|
||||
|
||||
cmdline, err := ReadProcessCmdline("proc/3323/cmdline")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process cmdline read fail", err)
|
||||
}
|
||||
|
||||
expected := "proftpd: (accepting connections)"
|
||||
|
||||
if cmdline != expected {
|
||||
t.Error("not equal to expected", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", cmdline)
|
||||
}
|
||||
|
||||
func TestReadProcessCmdlineComplex(t *testing.T) {
|
||||
|
||||
cmdline, err := ReadProcessCmdline("proc/5811/cmdline")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process cmdline read fail", err)
|
||||
}
|
||||
|
||||
expected := "/home/c9s/.config/sublime-text-2/Packages/User/GoSublime/linux-x64/bin/gosublime.margo_r14.12.06-1_go1.4.2.exe -oom 1000 -poll 30 -tag r14.12.06-1"
|
||||
|
||||
if cmdline != expected {
|
||||
t.Error("not equal to expected", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", cmdline)
|
||||
}
|
||||
71
vendor/github.com/c9s/goprocinfo/linux/process_io.go
generated
vendored
Normal file
71
vendor/github.com/c9s/goprocinfo/linux/process_io.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// I/O statistics for the process.
|
||||
type ProcessIO struct {
|
||||
RChar uint64 `json:"rchar" field:"rchar"` // chars read
|
||||
WChar uint64 `json:"wchar" field:"wchar"` // chars written
|
||||
Syscr uint64 `json:"syscr" field:"syscr"` // read syscalls
|
||||
Syscw uint64 `json:"syscw" field:"syscw"` // write syscalls
|
||||
ReadBytes uint64 `json:"read_bytes" field:"read_bytes"` // bytes read
|
||||
WriteBytes uint64 `json:"write_bytes" field:"write_bytes"` // bytes written
|
||||
CancelledWriteBytes uint64 `json:"cancelled_write_bytes" field:"cancelled_write_bytes"` // bytes truncated
|
||||
}
|
||||
|
||||
func ReadProcessIO(path string) (*ProcessIO, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Maps a io metric to its value (i.e. rchar --> 100000)
|
||||
m := map[string]uint64{}
|
||||
|
||||
io := ProcessIO{}
|
||||
|
||||
lines := strings.Split(string(b), "\n")
|
||||
|
||||
for _, line := range lines {
|
||||
|
||||
if strings.Index(line, ": ") == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
l := strings.Split(line, ": ")
|
||||
|
||||
k := l[0]
|
||||
v, err := strconv.ParseUint(l[1], 10, 64)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m[k] = v
|
||||
|
||||
}
|
||||
|
||||
e := reflect.ValueOf(&io).Elem()
|
||||
t := e.Type()
|
||||
|
||||
for i := 0; i < e.NumField(); i++ {
|
||||
|
||||
k := t.Field(i).Tag.Get("field")
|
||||
|
||||
v, ok := m[k]
|
||||
|
||||
if ok {
|
||||
e.Field(i).SetUint(v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &io, nil
|
||||
}
|
||||
31
vendor/github.com/c9s/goprocinfo/linux/process_io_test.go
generated
vendored
Normal file
31
vendor/github.com/c9s/goprocinfo/linux/process_io_test.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadProcessIO(t *testing.T) {
|
||||
|
||||
io, err := ReadProcessIO("proc/3323/io")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process io read fail", err)
|
||||
}
|
||||
|
||||
expected := &ProcessIO{
|
||||
RChar: 3865585,
|
||||
WChar: 183294,
|
||||
Syscr: 6697,
|
||||
Syscw: 997,
|
||||
ReadBytes: 90112,
|
||||
WriteBytes: 45056,
|
||||
CancelledWriteBytes: 0,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(io, expected) {
|
||||
t.Error("not equal to expected", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", io)
|
||||
}
|
||||
54
vendor/github.com/c9s/goprocinfo/linux/process_pid.go
generated
vendored
Normal file
54
vendor/github.com/c9s/goprocinfo/linux/process_pid.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ReadMaxPID(path string) (uint64, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
s := strings.TrimSpace(string(b))
|
||||
|
||||
i, err := strconv.ParseUint(s, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return i, nil
|
||||
|
||||
}
|
||||
|
||||
func ListPID(path string, max uint64) ([]uint64, error) {
|
||||
|
||||
l := make([]uint64, 0, 5)
|
||||
|
||||
for i := uint64(1); i <= max; i++ {
|
||||
|
||||
p := filepath.Join(path, strconv.FormatUint(i, 10))
|
||||
|
||||
s, err := os.Stat(p)
|
||||
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err != nil || !s.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
l = append(l, i)
|
||||
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
38
vendor/github.com/c9s/goprocinfo/linux/process_pid_test.go
generated
vendored
Normal file
38
vendor/github.com/c9s/goprocinfo/linux/process_pid_test.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMaxPID(t *testing.T) {
|
||||
|
||||
max, err := ReadMaxPID("proc/sys_kernel_pid_max")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("max pid read fail", err)
|
||||
}
|
||||
|
||||
if max != 32768 {
|
||||
t.Error("unexpected value")
|
||||
}
|
||||
|
||||
t.Logf("%+v", max)
|
||||
}
|
||||
|
||||
func TestListPID(t *testing.T) {
|
||||
|
||||
list, err := ListPID("proc", 32768)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("list pid fail", err)
|
||||
}
|
||||
|
||||
var expected = []uint64{884, 3323, 4854, 5811}
|
||||
|
||||
if !reflect.DeepEqual(list, expected) {
|
||||
t.Error("not equal to expected", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", list)
|
||||
}
|
||||
303
vendor/github.com/c9s/goprocinfo/linux/process_stat.go
generated
vendored
Normal file
303
vendor/github.com/c9s/goprocinfo/linux/process_stat.go
generated
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Status information about the process.
|
||||
type ProcessStat struct {
|
||||
Pid uint64 `json:"pid"`
|
||||
Comm string `json:"comm"`
|
||||
State string `json:"state"`
|
||||
Ppid int64 `json:"ppid"`
|
||||
Pgrp int64 `json:"pgrp"`
|
||||
Session int64 `json:"session"`
|
||||
TtyNr int64 `json:"tty_nr"`
|
||||
Tpgid int64 `json:"tpgid"`
|
||||
Flags uint64 `json:"flags"`
|
||||
Minflt uint64 `json:"minflt"`
|
||||
Cminflt uint64 `json:"cminflt"`
|
||||
Majflt uint64 `json:"majflt"`
|
||||
Cmajflt uint64 `json:"cmajflt"`
|
||||
Utime uint64 `json:"utime"`
|
||||
Stime uint64 `json:"stime"`
|
||||
Cutime int64 `json:"cutime"`
|
||||
Cstime int64 `json:"cstime"`
|
||||
Priority int64 `json:"priority"`
|
||||
Nice int64 `json:"nice"`
|
||||
NumThreads int64 `json:"num_threads"`
|
||||
Itrealvalue int64 `json:"itrealvalue"`
|
||||
Starttime uint64 `json:"starttime"`
|
||||
Vsize uint64 `json:"vsize"`
|
||||
Rss int64 `json:"rss"`
|
||||
Rsslim uint64 `json:"rsslim"`
|
||||
Startcode uint64 `json:"startcode"`
|
||||
Endcode uint64 `json:"endcode"`
|
||||
Startstack uint64 `json:"startstack"`
|
||||
Kstkesp uint64 `json:"kstkesp"`
|
||||
Kstkeip uint64 `json:"kstkeip"`
|
||||
Signal uint64 `json:"signal"`
|
||||
Blocked uint64 `json:"blocked"`
|
||||
Sigignore uint64 `json:"sigignore"`
|
||||
Sigcatch uint64 `json:"sigcatch"`
|
||||
Wchan uint64 `json:"wchan"`
|
||||
Nswap uint64 `json:"nswap"`
|
||||
Cnswap uint64 `json:"cnswap"`
|
||||
ExitSignal int64 `json:"exit_signal"`
|
||||
Processor int64 `json:"processor"`
|
||||
RtPriority uint64 `json:"rt_priority"`
|
||||
Policy uint64 `json:"policy"`
|
||||
DelayacctBlkioTicks uint64 `json:"delayacct_blkio_ticks"`
|
||||
GuestTime uint64 `json:"guest_time"`
|
||||
CguestTime int64 `json:"cguest_time"`
|
||||
StartData uint64 `json:"start_data"`
|
||||
EndData uint64 `json:"end_data"`
|
||||
StartBrk uint64 `json:"start_brk"`
|
||||
ArgStart uint64 `json:"arg_start"`
|
||||
ArgEnd uint64 `json:"arg_end"`
|
||||
EnvStart uint64 `json:"env_start"`
|
||||
EnvEnd uint64 `json:"env_end"`
|
||||
ExitCode int64 `json:"exit_code"`
|
||||
}
|
||||
|
||||
var processStatRegExp = regexp.MustCompile("^(\\d+)( \\(.*?\\) )(.*)$")
|
||||
|
||||
func ReadProcessStat(path string) (*ProcessStat, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := string(b)
|
||||
|
||||
f := make([]string, 0, 32)
|
||||
|
||||
e := processStatRegExp.FindStringSubmatch(strings.TrimSpace(s))
|
||||
|
||||
// Inject process Pid
|
||||
f = append(f, e[1])
|
||||
|
||||
// Inject process Comm
|
||||
f = append(f, strings.TrimSpace(e[2]))
|
||||
|
||||
// Inject all remaining process info
|
||||
f = append(f, (strings.Fields(e[3]))...)
|
||||
|
||||
stat := ProcessStat{}
|
||||
|
||||
for i := 0; i < len(f); i++ {
|
||||
switch i {
|
||||
case 0:
|
||||
if stat.Pid, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 1:
|
||||
stat.Comm = f[i]
|
||||
case 2:
|
||||
stat.State = f[i]
|
||||
case 3:
|
||||
if stat.Ppid, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 4:
|
||||
if stat.Pgrp, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 5:
|
||||
if stat.Session, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 6:
|
||||
if stat.TtyNr, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 7:
|
||||
if stat.Tpgid, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 8:
|
||||
if stat.Flags, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 9:
|
||||
if stat.Minflt, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 10:
|
||||
if stat.Cminflt, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 11:
|
||||
if stat.Majflt, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 12:
|
||||
if stat.Cmajflt, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 13:
|
||||
if stat.Utime, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 14:
|
||||
if stat.Stime, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 15:
|
||||
if stat.Cutime, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 16:
|
||||
if stat.Cstime, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 17:
|
||||
if stat.Priority, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 18:
|
||||
if stat.Nice, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 19:
|
||||
if stat.NumThreads, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 20:
|
||||
if stat.Itrealvalue, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 21:
|
||||
if stat.Starttime, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 22:
|
||||
if stat.Vsize, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 23:
|
||||
if stat.Rss, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 24:
|
||||
if stat.Rsslim, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 25:
|
||||
if stat.Startcode, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 26:
|
||||
if stat.Endcode, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 27:
|
||||
if stat.Startstack, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 28:
|
||||
if stat.Kstkesp, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 29:
|
||||
if stat.Kstkeip, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 30:
|
||||
if stat.Signal, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 31:
|
||||
if stat.Blocked, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 32:
|
||||
if stat.Sigignore, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 33:
|
||||
if stat.Sigcatch, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 34:
|
||||
if stat.Wchan, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 35:
|
||||
if stat.Nswap, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 36:
|
||||
if stat.Cnswap, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 37:
|
||||
if stat.ExitSignal, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 38:
|
||||
if stat.Processor, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 39:
|
||||
if stat.RtPriority, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 40:
|
||||
if stat.Policy, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 41:
|
||||
if stat.DelayacctBlkioTicks, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 42:
|
||||
if stat.GuestTime, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 43:
|
||||
if stat.CguestTime, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 44:
|
||||
if stat.StartData, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 45:
|
||||
if stat.EndData, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 46:
|
||||
if stat.StartBrk, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 47:
|
||||
if stat.ArgStart, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 48:
|
||||
if stat.ArgEnd, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 49:
|
||||
if stat.EnvStart, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 50:
|
||||
if stat.EnvEnd, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 51:
|
||||
if stat.ExitCode, err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &stat, nil
|
||||
}
|
||||
193
vendor/github.com/c9s/goprocinfo/linux/process_stat_test.go
generated
vendored
Normal file
193
vendor/github.com/c9s/goprocinfo/linux/process_stat_test.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadProcessStat(t *testing.T) {
|
||||
|
||||
stat, err := ReadProcessStat("proc/3323/stat")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process stat read fail", err)
|
||||
}
|
||||
|
||||
expected := &ProcessStat{
|
||||
Pid: 3323,
|
||||
Comm: "(proftpd)",
|
||||
State: "S",
|
||||
Ppid: 1,
|
||||
Pgrp: 3323,
|
||||
Session: 3323,
|
||||
TtyNr: 0,
|
||||
Tpgid: -1,
|
||||
Flags: 4202816,
|
||||
Minflt: 1311,
|
||||
Cminflt: 57367,
|
||||
Majflt: 0,
|
||||
Cmajflt: 1,
|
||||
Utime: 23,
|
||||
Stime: 58,
|
||||
Cutime: 24,
|
||||
Cstime: 49,
|
||||
Priority: 20,
|
||||
Nice: 0,
|
||||
NumThreads: 1,
|
||||
Itrealvalue: 0,
|
||||
Starttime: 2789,
|
||||
Vsize: 16601088,
|
||||
Rss: 522,
|
||||
Rsslim: 4294967295,
|
||||
Startcode: 134512640,
|
||||
Endcode: 135222176,
|
||||
Startstack: 3217552592,
|
||||
Kstkesp: 3217551836,
|
||||
Kstkeip: 4118799382,
|
||||
Signal: 0,
|
||||
Blocked: 0,
|
||||
Sigignore: 272633856,
|
||||
Sigcatch: 8514799,
|
||||
Wchan: 0,
|
||||
Nswap: 0,
|
||||
Cnswap: 0,
|
||||
ExitSignal: 17,
|
||||
Processor: 7,
|
||||
RtPriority: 0,
|
||||
Policy: 0,
|
||||
DelayacctBlkioTicks: 1,
|
||||
GuestTime: 0,
|
||||
CguestTime: 0,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(stat, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", stat)
|
||||
}
|
||||
|
||||
func TestReadProcessStatWithSpace(t *testing.T) {
|
||||
|
||||
stat, err := ReadProcessStat("proc/884/stat")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process stat read fail", err)
|
||||
}
|
||||
|
||||
expected := &ProcessStat{
|
||||
Pid: 884,
|
||||
Comm: "(rs:main Q:Reg)",
|
||||
State: "S",
|
||||
Ppid: 1,
|
||||
Pgrp: 873,
|
||||
Session: 873,
|
||||
TtyNr: 0,
|
||||
Tpgid: -1,
|
||||
Flags: 4202816,
|
||||
Minflt: 561,
|
||||
Cminflt: 0,
|
||||
Majflt: 0,
|
||||
Cmajflt: 0,
|
||||
Utime: 68,
|
||||
Stime: 132,
|
||||
Cutime: 0,
|
||||
Cstime: 0,
|
||||
Priority: 20,
|
||||
Nice: 0,
|
||||
NumThreads: 4,
|
||||
Itrealvalue: 0,
|
||||
Starttime: 2161,
|
||||
Vsize: 255451136,
|
||||
Rss: 409,
|
||||
Rsslim: 18446744073709551615,
|
||||
Startcode: 1,
|
||||
Endcode: 1,
|
||||
Startstack: 0,
|
||||
Kstkesp: 0,
|
||||
Kstkeip: 0,
|
||||
Signal: 0,
|
||||
Blocked: 2146172671,
|
||||
Sigignore: 16781830,
|
||||
Sigcatch: 1133601,
|
||||
Wchan: 18446744073709551615,
|
||||
Nswap: 0,
|
||||
Cnswap: 0,
|
||||
ExitSignal: -1,
|
||||
Processor: 1,
|
||||
RtPriority: 0,
|
||||
Policy: 0,
|
||||
DelayacctBlkioTicks: 34,
|
||||
GuestTime: 0,
|
||||
CguestTime: 0,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(stat, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", stat)
|
||||
}
|
||||
|
||||
func TestReadProcessStatWithDoubleParentheses(t *testing.T) {
|
||||
|
||||
stat, err := ReadProcessStat("proc/4854/stat")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process stat read fail", err)
|
||||
}
|
||||
|
||||
expected := &ProcessStat{
|
||||
Pid: 4854,
|
||||
Comm: "((sd-pam))",
|
||||
State: "S",
|
||||
Ppid: 4853,
|
||||
Pgrp: 4853,
|
||||
Session: 4853,
|
||||
TtyNr: 0,
|
||||
Tpgid: -1,
|
||||
Flags: 1077944640,
|
||||
Minflt: 21,
|
||||
Cminflt: 0,
|
||||
Majflt: 0,
|
||||
Cmajflt: 0,
|
||||
Utime: 0,
|
||||
Stime: 0,
|
||||
Cutime: 0,
|
||||
Cstime: 0,
|
||||
Priority: 20,
|
||||
Nice: 0,
|
||||
NumThreads: 1,
|
||||
Itrealvalue: 0,
|
||||
Starttime: 4912,
|
||||
Vsize: 83931136,
|
||||
Rss: 405,
|
||||
Rsslim: 18446744073709551615,
|
||||
Startcode: 1,
|
||||
Endcode: 1,
|
||||
Startstack: 0,
|
||||
Kstkesp: 0,
|
||||
Kstkeip: 0,
|
||||
Signal: 0,
|
||||
Blocked: 0,
|
||||
Sigignore: 4096,
|
||||
Sigcatch: 0,
|
||||
Wchan: 18446744073709551615,
|
||||
Nswap: 0,
|
||||
Cnswap: 0,
|
||||
ExitSignal: 17,
|
||||
Processor: 7,
|
||||
RtPriority: 0,
|
||||
Policy: 0,
|
||||
DelayacctBlkioTicks: 0,
|
||||
GuestTime: 0,
|
||||
CguestTime: 0,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(stat, expected) {
|
||||
t.Errorf("not equal to expected %+v", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", stat)
|
||||
|
||||
}
|
||||
61
vendor/github.com/c9s/goprocinfo/linux/process_statm.go
generated
vendored
Normal file
61
vendor/github.com/c9s/goprocinfo/linux/process_statm.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Provides information about memory usage, measured in pages.
|
||||
type ProcessStatm struct {
|
||||
Size uint64 `json:"size"` // total program size
|
||||
Resident uint64 `json:"resident"` // resident set size
|
||||
Share uint64 `json:"share"` // shared pages
|
||||
Text uint64 `json:"text"` // text (code)
|
||||
Lib uint64 `json:"lib"` // library (unused in Linux 2.6)
|
||||
Data uint64 `json:"data"` // data + stack
|
||||
Dirty uint64 `json:"dirty"` // dirty pages (unused in Linux 2.6)
|
||||
}
|
||||
|
||||
func ReadProcessStatm(path string) (*ProcessStatm, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := string(b)
|
||||
f := strings.Fields(s)
|
||||
|
||||
statm := ProcessStatm{}
|
||||
|
||||
var n uint64
|
||||
|
||||
for i := 0; i < len(f); i++ {
|
||||
|
||||
if n, err = strconv.ParseUint(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch i {
|
||||
case 0:
|
||||
statm.Size = n
|
||||
case 1:
|
||||
statm.Resident = n
|
||||
case 2:
|
||||
statm.Share = n
|
||||
case 3:
|
||||
statm.Text = n
|
||||
case 4:
|
||||
statm.Lib = n
|
||||
case 5:
|
||||
statm.Data = n
|
||||
case 6:
|
||||
statm.Dirty = n
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &statm, nil
|
||||
}
|
||||
31
vendor/github.com/c9s/goprocinfo/linux/process_statm_test.go
generated
vendored
Normal file
31
vendor/github.com/c9s/goprocinfo/linux/process_statm_test.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadProcessStatm(t *testing.T) {
|
||||
|
||||
statm, err := ReadProcessStatm("proc/3323/statm")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process statm read fail", err)
|
||||
}
|
||||
|
||||
expected := &ProcessStatm{
|
||||
Size: 4053,
|
||||
Resident: 522,
|
||||
Share: 174,
|
||||
Text: 174,
|
||||
Lib: 0,
|
||||
Data: 286,
|
||||
Dirty: 0,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(statm, expected) {
|
||||
t.Error("not equal to expected", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", statm)
|
||||
}
|
||||
331
vendor/github.com/c9s/goprocinfo/linux/process_status.go
generated
vendored
Normal file
331
vendor/github.com/c9s/goprocinfo/linux/process_status.go
generated
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Provides much of the information from ProcessStatm and ProcessStat
|
||||
type ProcessStatus struct {
|
||||
Name string
|
||||
State string
|
||||
Tgid uint64
|
||||
Pid uint64
|
||||
PPid int64
|
||||
TracerPid uint64
|
||||
RealUid uint64
|
||||
EffectiveUid uint64
|
||||
SavedSetUid uint64
|
||||
FilesystemUid uint64
|
||||
RealGid uint64
|
||||
EffectiveGid uint64
|
||||
SavedSetGid uint64
|
||||
FilesystemGid uint64
|
||||
FDSize uint64
|
||||
Groups []int64
|
||||
VmPeak uint64
|
||||
VmSize uint64
|
||||
VmLck uint64
|
||||
VmHWM uint64
|
||||
VmRSS uint64
|
||||
VmData uint64
|
||||
VmStk uint64
|
||||
VmExe uint64
|
||||
VmLib uint64
|
||||
VmPTE uint64
|
||||
VmSwap uint64
|
||||
Threads uint64
|
||||
SigQLength uint64
|
||||
SigQLimit uint64
|
||||
SigPnd uint64
|
||||
ShdPnd uint64
|
||||
SigBlk uint64
|
||||
SigIgn uint64
|
||||
SigCgt uint64
|
||||
CapInh uint64
|
||||
CapPrm uint64
|
||||
CapEff uint64
|
||||
CapBnd uint64
|
||||
Seccomp uint8
|
||||
CpusAllowed []uint32
|
||||
MemsAllowed []uint32
|
||||
VoluntaryCtxtSwitches uint64
|
||||
NonvoluntaryCtxtSwitches uint64
|
||||
}
|
||||
|
||||
func ReadProcessStatus(path string) (*ProcessStatus, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status := ProcessStatus{}
|
||||
|
||||
lines := strings.Split(string(b), "\n")
|
||||
|
||||
for _, line := range lines {
|
||||
|
||||
if strings.Index(line, ":") == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
l := strings.Split(line, ":")
|
||||
|
||||
k := strings.TrimSpace(l[0])
|
||||
v := strings.TrimSpace(l[1])
|
||||
|
||||
switch k {
|
||||
case "Name":
|
||||
status.Name = v
|
||||
case "State":
|
||||
status.State = v
|
||||
case "Tgid":
|
||||
if status.Tgid, err = strconv.ParseUint(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "Pid":
|
||||
if status.Pid, err = strconv.ParseUint(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "PPid":
|
||||
if status.PPid, err = strconv.ParseInt(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "TracerPid":
|
||||
if status.TracerPid, err = strconv.ParseUint(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "Uid":
|
||||
if f := strings.Fields(v); len(f) == 4 {
|
||||
if status.RealUid, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.EffectiveUid, err = strconv.ParseUint(f[1], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.SavedSetUid, err = strconv.ParseUint(f[2], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.FilesystemUid, err = strconv.ParseUint(f[3], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "Gid":
|
||||
if f := strings.Fields(v); len(f) == 4 {
|
||||
if status.RealGid, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.EffectiveGid, err = strconv.ParseUint(f[1], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.SavedSetGid, err = strconv.ParseUint(f[2], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.FilesystemGid, err = strconv.ParseUint(f[3], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "FDSize":
|
||||
if status.FDSize, err = strconv.ParseUint(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "Groups":
|
||||
{
|
||||
|
||||
f := strings.Fields(v)
|
||||
status.Groups = make([]int64, len(f))
|
||||
|
||||
for i := range status.Groups {
|
||||
if status.Groups[i], err = strconv.ParseInt(f[i], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
case "VmPeak":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmPeak, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmSize":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmSize, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmLck":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmLck, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmHWM":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmHWM, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmRSS":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmRSS, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmData":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmData, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmStk":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmStk, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmExe":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmExe, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmLib":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmLib, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmPTE":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmPTE, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "VmSwap":
|
||||
{
|
||||
f := strings.Fields(v)
|
||||
if status.VmSwap, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case "Threads":
|
||||
if status.Threads, err = strconv.ParseUint(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "SigQ":
|
||||
{
|
||||
if f := strings.Split(v, "/"); len(f) == 2 {
|
||||
if status.SigQLength, err = strconv.ParseUint(f[0], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.SigQLimit, err = strconv.ParseUint(f[1], 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
case "SigPnd":
|
||||
if status.SigPnd, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "ShdPnd":
|
||||
if status.ShdPnd, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "SigBlk":
|
||||
if status.SigBlk, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "SigIgn":
|
||||
if status.SigIgn, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "SigCgt":
|
||||
if status.SigCgt, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "CapInh":
|
||||
if status.CapInh, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "CapPrm":
|
||||
if status.CapPrm, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "CapEff":
|
||||
if status.CapEff, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "CapBnd":
|
||||
if status.CapBnd, err = strconv.ParseUint(v, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "Seccomp":
|
||||
{
|
||||
|
||||
var n uint64
|
||||
|
||||
if n, err = strconv.ParseUint(v, 10, 8); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status.Seccomp = uint8(n)
|
||||
}
|
||||
case "Cpus_allowed":
|
||||
{
|
||||
|
||||
var n uint64
|
||||
|
||||
f := strings.Split(v, ",")
|
||||
status.CpusAllowed = make([]uint32, len(f))
|
||||
|
||||
for i := range status.CpusAllowed {
|
||||
if n, err = strconv.ParseUint(f[i], 16, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
status.CpusAllowed[i] = uint32(n)
|
||||
}
|
||||
|
||||
}
|
||||
case "Mems_allowed":
|
||||
{
|
||||
|
||||
var n uint64
|
||||
|
||||
f := strings.Split(v, ",")
|
||||
status.MemsAllowed = make([]uint32, len(f))
|
||||
|
||||
for i := range status.MemsAllowed {
|
||||
if n, err = strconv.ParseUint(f[i], 16, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
status.MemsAllowed[i] = uint32(n)
|
||||
}
|
||||
|
||||
}
|
||||
case "voluntary_ctxt_switches":
|
||||
if status.VoluntaryCtxtSwitches, err = strconv.ParseUint(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "nonvoluntary_ctxt_switches":
|
||||
if status.NonvoluntaryCtxtSwitches, err = strconv.ParseUint(v, 10, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &status, nil
|
||||
}
|
||||
68
vendor/github.com/c9s/goprocinfo/linux/process_status_test.go
generated
vendored
Normal file
68
vendor/github.com/c9s/goprocinfo/linux/process_status_test.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadProcessStatus(t *testing.T) {
|
||||
|
||||
status, err := ReadProcessStatus("proc/3323/status")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process io read fail", err)
|
||||
}
|
||||
|
||||
expected := &ProcessStatus{
|
||||
Name: "proftpd",
|
||||
State: "S (sleeping)",
|
||||
Tgid: 3323,
|
||||
Pid: 3323,
|
||||
PPid: 1,
|
||||
TracerPid: 0,
|
||||
RealUid: 0,
|
||||
EffectiveUid: 111,
|
||||
SavedSetUid: 0,
|
||||
FilesystemUid: 111,
|
||||
RealGid: 65534,
|
||||
EffectiveGid: 65534,
|
||||
SavedSetGid: 65534,
|
||||
FilesystemGid: 65534,
|
||||
FDSize: 32,
|
||||
Groups: []int64{2001, 65534},
|
||||
VmPeak: 16216,
|
||||
VmSize: 16212,
|
||||
VmLck: 0,
|
||||
VmHWM: 2092,
|
||||
VmRSS: 2088,
|
||||
VmData: 872,
|
||||
VmStk: 272,
|
||||
VmExe: 696,
|
||||
VmLib: 9416,
|
||||
VmPTE: 36,
|
||||
VmSwap: 0,
|
||||
Threads: 1,
|
||||
SigQLength: 0,
|
||||
SigQLimit: 12091,
|
||||
SigPnd: 0,
|
||||
ShdPnd: 0,
|
||||
SigBlk: 0,
|
||||
SigIgn: 272633856,
|
||||
SigCgt: 6450965743,
|
||||
CapInh: 0,
|
||||
CapPrm: 18446744073709551615,
|
||||
CapEff: 0,
|
||||
CapBnd: 18446744073709551615,
|
||||
Seccomp: 0,
|
||||
CpusAllowed: []uint32{255},
|
||||
VoluntaryCtxtSwitches: 5899,
|
||||
NonvoluntaryCtxtSwitches: 26,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(status, expected) {
|
||||
t.Error("not equal to expected", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", status)
|
||||
|
||||
}
|
||||
134
vendor/github.com/c9s/goprocinfo/linux/process_test.go
generated
vendored
Normal file
134
vendor/github.com/c9s/goprocinfo/linux/process_test.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadProcess(t *testing.T) {
|
||||
|
||||
p, err := ReadProcess(3323, "proc")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("process read fail", err)
|
||||
}
|
||||
|
||||
expected := &Process{
|
||||
Status: ProcessStatus{
|
||||
Name: "proftpd",
|
||||
State: "S (sleeping)",
|
||||
Tgid: 3323,
|
||||
Pid: 3323,
|
||||
PPid: 1,
|
||||
TracerPid: 0,
|
||||
RealUid: 0,
|
||||
EffectiveUid: 111,
|
||||
SavedSetUid: 0,
|
||||
FilesystemUid: 111,
|
||||
RealGid: 65534,
|
||||
EffectiveGid: 65534,
|
||||
SavedSetGid: 65534,
|
||||
FilesystemGid: 65534,
|
||||
FDSize: 32,
|
||||
Groups: []int64{2001, 65534},
|
||||
VmPeak: 16216,
|
||||
VmSize: 16212,
|
||||
VmLck: 0,
|
||||
VmHWM: 2092,
|
||||
VmRSS: 2088,
|
||||
VmData: 872,
|
||||
VmStk: 272,
|
||||
VmExe: 696,
|
||||
VmLib: 9416,
|
||||
VmPTE: 36,
|
||||
VmSwap: 0,
|
||||
Threads: 1,
|
||||
SigQLength: 0,
|
||||
SigQLimit: 12091,
|
||||
SigPnd: 0,
|
||||
ShdPnd: 0,
|
||||
SigBlk: 0,
|
||||
SigIgn: 272633856,
|
||||
SigCgt: 6450965743,
|
||||
CapInh: 0,
|
||||
CapPrm: 18446744073709551615,
|
||||
CapEff: 0,
|
||||
CapBnd: 18446744073709551615,
|
||||
Seccomp: 0,
|
||||
CpusAllowed: []uint32{255},
|
||||
VoluntaryCtxtSwitches: 5899,
|
||||
NonvoluntaryCtxtSwitches: 26,
|
||||
},
|
||||
Statm: ProcessStatm{
|
||||
Size: 4053,
|
||||
Resident: 522,
|
||||
Share: 174,
|
||||
Text: 174,
|
||||
Lib: 0,
|
||||
Data: 286,
|
||||
Dirty: 0,
|
||||
},
|
||||
Stat: ProcessStat{
|
||||
Pid: 3323,
|
||||
Comm: "(proftpd)",
|
||||
State: "S",
|
||||
Ppid: 1,
|
||||
Pgrp: 3323,
|
||||
Session: 3323,
|
||||
TtyNr: 0,
|
||||
Tpgid: -1,
|
||||
Flags: 4202816,
|
||||
Minflt: 1311,
|
||||
Cminflt: 57367,
|
||||
Majflt: 0,
|
||||
Cmajflt: 1,
|
||||
Utime: 23,
|
||||
Stime: 58,
|
||||
Cutime: 24,
|
||||
Cstime: 49,
|
||||
Priority: 20,
|
||||
Nice: 0,
|
||||
NumThreads: 1,
|
||||
Itrealvalue: 0,
|
||||
Starttime: 2789,
|
||||
Vsize: 16601088,
|
||||
Rss: 522,
|
||||
Rsslim: 4294967295,
|
||||
Startcode: 134512640,
|
||||
Endcode: 135222176,
|
||||
Startstack: 3217552592,
|
||||
Kstkesp: 3217551836,
|
||||
Kstkeip: 4118799382,
|
||||
Signal: 0,
|
||||
Blocked: 0,
|
||||
Sigignore: 272633856,
|
||||
Sigcatch: 8514799,
|
||||
Wchan: 0,
|
||||
Nswap: 0,
|
||||
Cnswap: 0,
|
||||
ExitSignal: 17,
|
||||
Processor: 7,
|
||||
RtPriority: 0,
|
||||
Policy: 0,
|
||||
DelayacctBlkioTicks: 1,
|
||||
GuestTime: 0,
|
||||
CguestTime: 0,
|
||||
},
|
||||
IO: ProcessIO{
|
||||
RChar: 3865585,
|
||||
WChar: 183294,
|
||||
Syscr: 6697,
|
||||
Syscw: 997,
|
||||
ReadBytes: 90112,
|
||||
WriteBytes: 45056,
|
||||
CancelledWriteBytes: 0,
|
||||
},
|
||||
Cmdline: "proftpd: (accepting connections)",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(p, expected) {
|
||||
t.Error("not equal to expected", expected)
|
||||
}
|
||||
|
||||
t.Logf("%+v", p)
|
||||
}
|
||||
82
vendor/github.com/c9s/goprocinfo/linux/sockstat.go
generated
vendored
Normal file
82
vendor/github.com/c9s/goprocinfo/linux/sockstat.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SockStat struct {
|
||||
// sockets:
|
||||
SocketsUsed uint64 `json:"sockets_used" field:"sockets.used"`
|
||||
|
||||
// TCP:
|
||||
TCPInUse uint64 `json:"tcp_in_use" field:"TCP.inuse"`
|
||||
TCPOrphan uint64 `json:"tcp_orphan" field:"TCP.orphan"`
|
||||
TCPTimeWait uint64 `json:"tcp_time_wait" field:"TCP.tw"`
|
||||
TCPAllocated uint64 `json:"tcp_allocated" field:"TCP.alloc"`
|
||||
TCPMemory uint64 `json:"tcp_memory" field:"TCP.mem"`
|
||||
|
||||
// UDP:
|
||||
UDPInUse uint64 `json:"udp_in_use" field:"UDP.inuse"`
|
||||
UDPMemory uint64 `json:"udp_memory" field:"UDP.mem"`
|
||||
|
||||
// UDPLITE:
|
||||
UDPLITEInUse uint64 `json:"udplite_in_use" field:"UDPLITE.inuse"`
|
||||
|
||||
// RAW:
|
||||
RAWInUse uint64 `json:"raw_in_use" field:"RAW.inuse"`
|
||||
|
||||
// FRAG:
|
||||
FRAGInUse uint64 `json:"frag_in_use" field:"FRAG.inuse"`
|
||||
FRAGMemory uint64 `json:"frag_memory" field:"FRAG.memory"`
|
||||
}
|
||||
|
||||
func ReadSockStat(path string) (*SockStat, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(data), "\n")
|
||||
|
||||
// Maps a meminfo metric to its value (i.e. MemTotal --> 100000)
|
||||
statMap := map[string]uint64{}
|
||||
|
||||
var sockStat SockStat = SockStat{}
|
||||
|
||||
for _, line := range lines {
|
||||
if strings.Index(line, ":") == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
statType := line[0:strings.Index(line, ":")] + "."
|
||||
|
||||
// The fields have this pattern: inuse 27 orphan 1 tw 23 alloc 31 mem 3
|
||||
// The stats are grouped into pairs and need to be parsed and placed into the stat map.
|
||||
key := ""
|
||||
for k, v := range strings.Fields(line[strings.Index(line, ":")+1:]) {
|
||||
// Every second field is a value.
|
||||
if (k+1)%2 != 0 {
|
||||
key = v
|
||||
continue
|
||||
}
|
||||
val, _ := strconv.ParseUint(v, 10, 64)
|
||||
statMap[statType+key] = val
|
||||
}
|
||||
}
|
||||
|
||||
elem := reflect.ValueOf(&sockStat).Elem()
|
||||
typeOfElem := elem.Type()
|
||||
|
||||
for i := 0; i < elem.NumField(); i++ {
|
||||
val, ok := statMap[typeOfElem.Field(i).Tag.Get("field")]
|
||||
if ok {
|
||||
elem.Field(i).SetUint(val)
|
||||
}
|
||||
}
|
||||
|
||||
return &sockStat, nil
|
||||
}
|
||||
19
vendor/github.com/c9s/goprocinfo/linux/sockstat_test.go
generated
vendored
Normal file
19
vendor/github.com/c9s/goprocinfo/linux/sockstat_test.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
import "reflect"
|
||||
|
||||
func TestSockStat(t *testing.T) {
|
||||
var expected = SockStat{231, 27, 1, 23, 31, 3, 19, 17, 0, 0, 0, 0}
|
||||
|
||||
sockStat, err := ReadSockStat("proc/sockstat")
|
||||
if err != nil {
|
||||
t.Fatal("sockstat read fail", err)
|
||||
}
|
||||
|
||||
t.Logf("%+v", sockStat)
|
||||
|
||||
if !reflect.DeepEqual(*sockStat, expected) {
|
||||
t.Error("not equal to expected")
|
||||
}
|
||||
}
|
||||
106
vendor/github.com/c9s/goprocinfo/linux/stat.go
generated
vendored
Normal file
106
vendor/github.com/c9s/goprocinfo/linux/stat.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Stat struct {
|
||||
CPUStatAll CPUStat `json:"cpu_all"`
|
||||
CPUStats []CPUStat `json:"cpus"`
|
||||
Interrupts uint64 `json:"intr"`
|
||||
ContextSwitches uint64 `json:"ctxt"`
|
||||
BootTime time.Time `json:"btime"`
|
||||
Processes uint64 `json:"processes"`
|
||||
ProcsRunning uint64 `json:"procs_running"`
|
||||
ProcsBlocked uint64 `json:"procs_blocked"`
|
||||
}
|
||||
|
||||
type CPUStat struct {
|
||||
Id string `json:"id"`
|
||||
User uint64 `json:"user"`
|
||||
Nice uint64 `json:"nice"`
|
||||
System uint64 `json:"system"`
|
||||
Idle uint64 `json:"idle"`
|
||||
IOWait uint64 `json:"iowait"`
|
||||
IRQ uint64 `json:"irq"`
|
||||
SoftIRQ uint64 `json:"softirq"`
|
||||
Steal uint64 `json:"steal"`
|
||||
Guest uint64 `json:"guest"`
|
||||
GuestNice uint64 `json:"guest_nice"`
|
||||
}
|
||||
|
||||
func createCPUStat(fields []string) *CPUStat {
|
||||
s := CPUStat{}
|
||||
s.Id = fields[0]
|
||||
|
||||
for i := 1; i < len(fields); i++ {
|
||||
v, _ := strconv.ParseUint(fields[i], 10, 64)
|
||||
switch i {
|
||||
case 1:
|
||||
s.User = v
|
||||
case 2:
|
||||
s.Nice = v
|
||||
case 3:
|
||||
s.System = v
|
||||
case 4:
|
||||
s.Idle = v
|
||||
case 5:
|
||||
s.IOWait = v
|
||||
case 6:
|
||||
s.IRQ = v
|
||||
case 7:
|
||||
s.SoftIRQ = v
|
||||
case 8:
|
||||
s.Steal = v
|
||||
case 9:
|
||||
s.Guest = v
|
||||
case 10:
|
||||
s.GuestNice = v
|
||||
}
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func ReadStat(path string) (*Stat, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content := string(b)
|
||||
lines := strings.Split(content, "\n")
|
||||
|
||||
var stat Stat = Stat{}
|
||||
|
||||
for i, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
if fields[0][:3] == "cpu" {
|
||||
if cpuStat := createCPUStat(fields); cpuStat != nil {
|
||||
if i == 0 {
|
||||
stat.CPUStatAll = *cpuStat
|
||||
} else {
|
||||
stat.CPUStats = append(stat.CPUStats, *cpuStat)
|
||||
}
|
||||
}
|
||||
} else if fields[0] == "intr" {
|
||||
stat.Interrupts, _ = strconv.ParseUint(fields[1], 10, 64)
|
||||
} else if fields[0] == "ctxt" {
|
||||
stat.ContextSwitches, _ = strconv.ParseUint(fields[1], 10, 64)
|
||||
} else if fields[0] == "btime" {
|
||||
seconds, _ := strconv.ParseInt(fields[1], 10, 64)
|
||||
stat.BootTime = time.Unix(seconds, 0)
|
||||
} else if fields[0] == "processes" {
|
||||
stat.Processes, _ = strconv.ParseUint(fields[1], 10, 64)
|
||||
} else if fields[0] == "procs_running" {
|
||||
stat.ProcsRunning, _ = strconv.ParseUint(fields[1], 10, 64)
|
||||
} else if fields[0] == "procs_blocked" {
|
||||
stat.ProcsBlocked, _ = strconv.ParseUint(fields[1], 10, 64)
|
||||
}
|
||||
}
|
||||
return &stat, nil
|
||||
}
|
||||
12
vendor/github.com/c9s/goprocinfo/linux/stat_test.go
generated
vendored
Normal file
12
vendor/github.com/c9s/goprocinfo/linux/stat_test.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCPUStat(t *testing.T) {
|
||||
stat, err := ReadStat("proc/stat")
|
||||
if err != nil {
|
||||
t.Fatal("stat read fail")
|
||||
}
|
||||
_ = stat
|
||||
t.Logf("%+v", stat)
|
||||
}
|
||||
43
vendor/github.com/c9s/goprocinfo/linux/uptime.go
generated
vendored
Normal file
43
vendor/github.com/c9s/goprocinfo/linux/uptime.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Uptime struct {
|
||||
Total float64 `json:"total"`
|
||||
Idle float64 `json:"idle"`
|
||||
}
|
||||
|
||||
func (self *Uptime) GetTotalDuration() time.Duration {
|
||||
return time.Duration(self.Total) * time.Second
|
||||
}
|
||||
|
||||
func (self *Uptime) GetIdleDuration() time.Duration {
|
||||
return time.Duration(self.Idle) * time.Second
|
||||
}
|
||||
|
||||
func (self *Uptime) CalculateIdle() float64 {
|
||||
// XXX
|
||||
// num2/(num1*N) # N = SMP CPU numbers
|
||||
return 0
|
||||
}
|
||||
|
||||
func ReadUptime(path string) (*Uptime, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields := strings.Fields(string(b))
|
||||
uptime := Uptime{}
|
||||
if uptime.Total, err = strconv.ParseFloat(fields[0], 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if uptime.Idle, err = strconv.ParseFloat(fields[1], 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &uptime, nil
|
||||
}
|
||||
22
vendor/github.com/c9s/goprocinfo/linux/uptime_test.go
generated
vendored
Normal file
22
vendor/github.com/c9s/goprocinfo/linux/uptime_test.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUptime(t *testing.T) {
|
||||
|
||||
uptime, err := ReadUptime("proc/uptime")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if uptime.Total == 0 {
|
||||
t.Fatal("uptime total read fail")
|
||||
}
|
||||
if uptime.Idle == 0 {
|
||||
t.Fatal("uptime idel read fail")
|
||||
}
|
||||
|
||||
t.Logf("Total: %+v", uptime.GetTotalDuration())
|
||||
t.Logf("Idle: %+v", uptime.GetIdleDuration())
|
||||
|
||||
t.Logf("%+v", uptime)
|
||||
}
|
||||
373
vendor/github.com/c9s/goprocinfo/linux/vmstat.go
generated
vendored
Normal file
373
vendor/github.com/c9s/goprocinfo/linux/vmstat.go
generated
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type VMStat struct {
|
||||
NrFreePages uint64 `json:"nr_free_pages"`
|
||||
NrAllocBatch uint64 `json:"nr_alloc_batch"`
|
||||
NrInactiveAnon uint64 `json:"nr_inactive_anon"`
|
||||
NrActiveAnon uint64 `json:"nr_active_anon"`
|
||||
NrInactiveFile uint64 `json:"nr_inactive_file"`
|
||||
NrActiveFile uint64 `json:"nr_active_file"`
|
||||
NrUnevictable uint64 `json:"nr_unevictable"`
|
||||
NrMlock uint64 `json:"nr_mlock"`
|
||||
NrAnonPages uint64 `json:"nr_anon_pages"`
|
||||
NrMapped uint64 `json:"nr_mapped"`
|
||||
NrFilePages uint64 `json:"nr_file_pages"`
|
||||
NrDirty uint64 `json:"nr_dirty"`
|
||||
NrWriteback uint64 `json:"nr_writeback"`
|
||||
NrSlabReclaimable uint64 `json:"nr_slab_reclaimable"`
|
||||
NrSlabUnreclaimable uint64 `json:"nr_slab_unreclaimable"`
|
||||
NrPageTablePages uint64 `json:"nr_page_table_pages"`
|
||||
NrKernelStack uint64 `json:"nr_kernel_stack"`
|
||||
NrUnstable uint64 `json:"nr_unstable"`
|
||||
NrBounce uint64 `json:"nr_bounce"`
|
||||
NrVmscanWrite uint64 `json:"nr_vmscan_write"`
|
||||
NrVmscanImmediateReclaim uint64 `json:"nr_vmscan_immediate_reclaim"`
|
||||
NrWritebackTemp uint64 `json:"nr_writeback_temp"`
|
||||
NrIsolatedAnon uint64 `json:"nr_isolated_anon"`
|
||||
NrIsolatedFile uint64 `json:"nr_isolated_file"`
|
||||
NrShmem uint64 `json:"nr_shmem"`
|
||||
NrDirtied uint64 `json:"nr_dirtied"`
|
||||
NrWritten uint64 `json:"nr_written"`
|
||||
NumaHit uint64 `json:"numa_hit"`
|
||||
NumaMiss uint64 `json:"numa_miss"`
|
||||
NumaForeign uint64 `json:"numa_foreign"`
|
||||
NumaInterleave uint64 `json:"numa_interleave"`
|
||||
NumaLocal uint64 `json:"numa_local"`
|
||||
NumaOther uint64 `json:"numa_other"`
|
||||
WorkingsetRefault uint64 `json:"workingset_refault"`
|
||||
WorkingsetActivate uint64 `json:"workingset_activate"`
|
||||
WorkingsetNodereclaim uint64 `json:"workingset_nodereclaim"`
|
||||
NrAnonTransparentHugepages uint64 `json:"nr_anon_transparent_hugepages"`
|
||||
NrFreeCma uint64 `json:"nr_free_cma"`
|
||||
NrDirtyThreshold uint64 `json:"nr_dirty_threshold"`
|
||||
NrDirtyBackgroundThreshold uint64 `json:"nr_dirty_background_threshold"`
|
||||
PagePagein uint64 `json:"pgpgin"`
|
||||
PagePageout uint64 `json:"pgpgout"`
|
||||
PageSwapin uint64 `json:"pswpin"`
|
||||
PageSwapout uint64 `json:"pswpout"`
|
||||
PageAllocDMA uint64 `json:"pgalloc_dma"`
|
||||
PageAllocDMA32 uint64 `json:"pgalloc_dma32"`
|
||||
PageAllocNormal uint64 `json:"pgalloc_normal"`
|
||||
PageAllocMovable uint64 `json:"pgalloc_movable"`
|
||||
PageFree uint64 `json:"pgfree"`
|
||||
PageActivate uint64 `json:"pgactivate"`
|
||||
PageDeactivate uint64 `json:"pgdeactivate"`
|
||||
PageFault uint64 `json:"pgfault"`
|
||||
PageMajorFault uint64 `json:"pgmajfault"`
|
||||
PageRefillDMA uint64 `json:"pgrefill_dma"`
|
||||
PageRefillDMA32 uint64 `json:"pgrefill_dma32"`
|
||||
PageRefillMormal uint64 `json:"pgrefill_normal"`
|
||||
PageRefillMovable uint64 `json:"pgrefill_movable"`
|
||||
PageStealKswapdDMA uint64 `json:"pgsteal_kswapd_dma"`
|
||||
PageStealKswapdDMA32 uint64 `json:"pgsteal_kswapd_dma32"`
|
||||
PageStealKswapdNormal uint64 `json:"pgsteal_kswapd_normal"`
|
||||
PageStealKswapdMovable uint64 `json:"pgsteal_kswapd_movable"`
|
||||
PageStealDirectDMA uint64 `json:"pgsteal_direct_dma"`
|
||||
PageStealDirectDMA32 uint64 `json:"pgsteal_direct_dma32"`
|
||||
PageStealDirectNormal uint64 `json:"pgsteal_direct_normal"`
|
||||
PageStealDirectMovable uint64 `json:"pgsteal_direct_movable"`
|
||||
PageScanKswapdDMA uint64 `json:"pgscan_kswapd_dma"`
|
||||
PageScanKswapdDMA32 uint64 `json:"pgscan_kswapd_dma32"`
|
||||
PageScanKswapdNormal uint64 `json:"pgscan_kswapd_normal"`
|
||||
PageScanKswapdMovable uint64 `json:"pgscan_kswapd_movable"`
|
||||
PageScanDirectDMA uint64 `json:"pgscan_direct_dma"`
|
||||
PageScanDirectDMA32 uint64 `json:"pgscan_direct_dma32"`
|
||||
PageScanDirectNormal uint64 `json:"pgscan_direct_normal"`
|
||||
PageScanDirectMovable uint64 `json:"pgscan_direct_movable"`
|
||||
PageScanDirectThrottle uint64 `json:"pgscan_direct_throttle"`
|
||||
ZoneReclaimFailed uint64 `json:"zone_reclaim_failed"`
|
||||
PageInodeSteal uint64 `json:"pginodesteal"`
|
||||
SlabsScanned uint64 `json:"slabs_scanned"`
|
||||
KswapdInodesteal uint64 `json:"kswapd_inodesteal"`
|
||||
KswapdLowWatermarkHitQuickly uint64 `json:"kswapd_low_wmark_hit_quickly"`
|
||||
KswapdHighWatermarkHitQuickly uint64 `json:"kswapd_high_wmark_hit_quickly"`
|
||||
PageoutRun uint64 `json:"pageoutrun"`
|
||||
AllocStall uint64 `json:"allocstall"`
|
||||
PageRotated uint64 `json:"pgrotated"`
|
||||
DropPagecache uint64 `json:"drop_pagecache"`
|
||||
DropSlab uint64 `json:"drop_slab"`
|
||||
NumaPteUpdates uint64 `json:"numa_pte_updates"`
|
||||
NumaHugePteUpdates uint64 `json:"numa_huge_pte_updates"`
|
||||
NumaHintFaults uint64 `json:"numa_hint_faults"`
|
||||
NumaHintFaults_local uint64 `json:"numa_hint_faults_local"`
|
||||
NumaPagesMigrated uint64 `json:"numa_pages_migrated"`
|
||||
PageMigrateSuccess uint64 `json:"pgmigrate_success"`
|
||||
PageMigrateFail uint64 `json:"pgmigrate_fail"`
|
||||
CompactMigrateScanned uint64 `json:"compact_migrate_scanned"`
|
||||
CompactFreeScanned uint64 `json:"compact_free_scanned"`
|
||||
CompactIsolated uint64 `json:"compact_isolated"`
|
||||
CompactStall uint64 `json:"compact_stall"`
|
||||
CompactFail uint64 `json:"compact_fail"`
|
||||
CompactSuccess uint64 `json:"compact_success"`
|
||||
HtlbBuddyAllocSuccess uint64 `json:"htlb_buddy_alloc_success"`
|
||||
HtlbBuddyAllocFail uint64 `json:"htlb_buddy_alloc_fail"`
|
||||
UnevictablePagesCulled uint64 `json:"unevictable_pgs_culled"`
|
||||
UnevictablePagesScanned uint64 `json:"unevictable_pgs_scanned"`
|
||||
UnevictablePagesRescued uint64 `json:"unevictable_pgs_rescued"`
|
||||
UnevictablePagesMlocked uint64 `json:"unevictable_pgs_mlocked"`
|
||||
UnevictablePagesMunlocked uint64 `json:"unevictable_pgs_munlocked"`
|
||||
UnevictablePagesCleared uint64 `json:"unevictable_pgs_cleared"`
|
||||
UnevictablePagesStranded uint64 `json:"unevictable_pgs_stranded"`
|
||||
THPFaultAlloc uint64 `json:"thp_fault_alloc"`
|
||||
THPFaultFallback uint64 `json:"thp_fault_fallback"`
|
||||
THPCollapseAlloc uint64 `json:"thp_collapse_alloc"`
|
||||
THPCollapseAllocFailed uint64 `json:"thp_collapse_alloc_failed"`
|
||||
THPSplit uint64 `json:"thp_split"`
|
||||
THPZeroPageAlloc uint64 `json:"thp_zero_page_alloc"`
|
||||
THPZeroPageAllocFailed uint64 `json:"thp_zero_page_alloc_failed"`
|
||||
}
|
||||
|
||||
func ReadVMStat(path string) (*VMStat, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content := string(b)
|
||||
lines := strings.Split(content, "\n")
|
||||
vmstat := VMStat{}
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != 2 {
|
||||
continue
|
||||
}
|
||||
name := fields[0]
|
||||
value, _ := strconv.ParseUint(fields[1], 10, 64)
|
||||
switch name {
|
||||
case "nr_free_pages":
|
||||
vmstat.NrFreePages = value
|
||||
case "nr_alloc_batch":
|
||||
vmstat.NrAllocBatch = value
|
||||
case "nr_inactive_anon":
|
||||
vmstat.NrInactiveAnon = value
|
||||
case "nr_active_anon":
|
||||
vmstat.NrActiveAnon = value
|
||||
case "nr_inactive_file":
|
||||
vmstat.NrInactiveFile = value
|
||||
case "nr_active_file":
|
||||
vmstat.NrActiveFile = value
|
||||
case "nr_unevictable":
|
||||
vmstat.NrUnevictable = value
|
||||
case "nr_mlock":
|
||||
vmstat.NrMlock = value
|
||||
case "nr_anon_pages":
|
||||
vmstat.NrAnonPages = value
|
||||
case "nr_mapped":
|
||||
vmstat.NrMapped = value
|
||||
case "nr_file_pages":
|
||||
vmstat.NrFilePages = value
|
||||
case "nr_dirty":
|
||||
vmstat.NrDirty = value
|
||||
case "nr_writeback":
|
||||
vmstat.NrWriteback = value
|
||||
case "nr_slab_reclaimable":
|
||||
vmstat.NrSlabReclaimable = value
|
||||
case "nr_slab_unreclaimable":
|
||||
vmstat.NrSlabUnreclaimable = value
|
||||
case "nr_page_table_pages":
|
||||
vmstat.NrPageTablePages = value
|
||||
case "nr_kernel_stack":
|
||||
vmstat.NrKernelStack = value
|
||||
case "nr_unstable":
|
||||
vmstat.NrUnstable = value
|
||||
case "nr_bounce":
|
||||
vmstat.NrBounce = value
|
||||
case "nr_vmscan_write":
|
||||
vmstat.NrVmscanWrite = value
|
||||
case "nr_vmscan_immediate_reclaim":
|
||||
vmstat.NrVmscanImmediateReclaim = value
|
||||
case "nr_writeback_temp":
|
||||
vmstat.NrWritebackTemp = value
|
||||
case "nr_isolated_anon":
|
||||
vmstat.NrIsolatedAnon = value
|
||||
case "nr_isolated_file":
|
||||
vmstat.NrIsolatedFile = value
|
||||
case "nr_shmem":
|
||||
vmstat.NrShmem = value
|
||||
case "nr_dirtied":
|
||||
vmstat.NrDirtied = value
|
||||
case "nr_written":
|
||||
vmstat.NrWritten = value
|
||||
case "numa_hit":
|
||||
vmstat.NumaHit = value
|
||||
case "numa_miss":
|
||||
vmstat.NumaMiss = value
|
||||
case "numa_foreign":
|
||||
vmstat.NumaForeign = value
|
||||
case "numa_interleave":
|
||||
vmstat.NumaInterleave = value
|
||||
case "numa_local":
|
||||
vmstat.NumaLocal = value
|
||||
case "numa_other":
|
||||
vmstat.NumaOther = value
|
||||
case "workingset_refault":
|
||||
vmstat.WorkingsetRefault = value
|
||||
case "workingset_activate":
|
||||
vmstat.WorkingsetActivate = value
|
||||
case "workingset_nodereclaim":
|
||||
vmstat.WorkingsetNodereclaim = value
|
||||
case "nr_anon_transparent_hugepages":
|
||||
vmstat.NrAnonTransparentHugepages = value
|
||||
case "nr_free_cma":
|
||||
vmstat.NrFreeCma = value
|
||||
case "nr_dirty_threshold":
|
||||
vmstat.NrDirtyThreshold = value
|
||||
case "nr_dirty_background_threshold":
|
||||
vmstat.NrDirtyBackgroundThreshold = value
|
||||
case "pgpgin":
|
||||
vmstat.PagePagein = value
|
||||
case "pgpgout":
|
||||
vmstat.PagePageout = value
|
||||
case "pswpin":
|
||||
vmstat.PageSwapin = value
|
||||
case "pswpout":
|
||||
vmstat.PageSwapout = value
|
||||
case "pgalloc_dma":
|
||||
vmstat.PageAllocDMA = value
|
||||
case "pgalloc_dma32":
|
||||
vmstat.PageAllocDMA32 = value
|
||||
case "pgalloc_normal":
|
||||
vmstat.PageAllocNormal = value
|
||||
case "pgalloc_movable":
|
||||
vmstat.PageAllocMovable = value
|
||||
case "pgfree":
|
||||
vmstat.PageFree = value
|
||||
case "pgactivate":
|
||||
vmstat.PageActivate = value
|
||||
case "pgdeactivate":
|
||||
vmstat.PageDeactivate = value
|
||||
case "pgfault":
|
||||
vmstat.PageFault = value
|
||||
case "pgmajfault":
|
||||
vmstat.PageMajorFault = value
|
||||
case "pgrefill_dma":
|
||||
vmstat.PageRefillDMA = value
|
||||
case "pgrefill_dma32":
|
||||
vmstat.PageRefillDMA32 = value
|
||||
case "pgrefill_normal":
|
||||
vmstat.PageRefillMormal = value
|
||||
case "pgrefill_movable":
|
||||
vmstat.PageRefillMovable = value
|
||||
case "pgsteal_kswapd_dma":
|
||||
vmstat.PageStealKswapdDMA = value
|
||||
case "pgsteal_kswapd_dma32":
|
||||
vmstat.PageStealKswapdDMA32 = value
|
||||
case "pgsteal_kswapd_normal":
|
||||
vmstat.PageStealKswapdNormal = value
|
||||
case "pgsteal_kswapd_movable":
|
||||
vmstat.PageStealKswapdMovable = value
|
||||
case "pgsteal_direct_dma":
|
||||
vmstat.PageStealDirectDMA = value
|
||||
case "pgsteal_direct_dma32":
|
||||
vmstat.PageStealDirectDMA32 = value
|
||||
case "pgsteal_direct_normal":
|
||||
vmstat.PageStealDirectNormal = value
|
||||
case "pgsteal_direct_movable":
|
||||
vmstat.PageStealDirectMovable = value
|
||||
case "pgscan_kswapd_dma":
|
||||
vmstat.PageScanKswapdDMA = value
|
||||
case "pgscan_kswapd_dma32":
|
||||
vmstat.PageScanKswapdDMA32 = value
|
||||
case "pgscan_kswapd_normal":
|
||||
vmstat.PageScanKswapdNormal = value
|
||||
case "pgscan_kswapd_movable":
|
||||
vmstat.PageScanKswapdMovable = value
|
||||
case "pgscan_direct_dma":
|
||||
vmstat.PageScanDirectDMA = value
|
||||
case "pgscan_direct_dma32":
|
||||
vmstat.PageScanDirectDMA32 = value
|
||||
case "pgscan_direct_normal":
|
||||
vmstat.PageScanDirectNormal = value
|
||||
case "pgscan_direct_movable":
|
||||
vmstat.PageScanDirectMovable = value
|
||||
case "pgscan_direct_throttle":
|
||||
vmstat.PageScanDirectThrottle = value
|
||||
case "zone_reclaim_failed":
|
||||
vmstat.ZoneReclaimFailed = value
|
||||
case "pginodesteal":
|
||||
vmstat.PageInodeSteal = value
|
||||
case "slabs_scanned":
|
||||
vmstat.SlabsScanned = value
|
||||
case "kswapd_inodesteal":
|
||||
vmstat.KswapdInodesteal = value
|
||||
case "kswapd_low_wmark_hit_quickly":
|
||||
vmstat.KswapdLowWatermarkHitQuickly = value
|
||||
case "kswapd_high_wmark_hit_quickly":
|
||||
vmstat.KswapdHighWatermarkHitQuickly = value
|
||||
case "pageoutrun":
|
||||
vmstat.PageoutRun = value
|
||||
case "allocstall":
|
||||
vmstat.AllocStall = value
|
||||
case "pgrotated":
|
||||
vmstat.PageRotated = value
|
||||
case "drop_pagecache":
|
||||
vmstat.DropPagecache = value
|
||||
case "drop_slab":
|
||||
vmstat.DropSlab = value
|
||||
case "numa_pte_updates":
|
||||
vmstat.NumaPteUpdates = value
|
||||
case "numa_huge_pte_updates":
|
||||
vmstat.NumaHugePteUpdates = value
|
||||
case "numa_hint_faults":
|
||||
vmstat.NumaHintFaults = value
|
||||
case "numa_hint_faults_local":
|
||||
vmstat.NumaHintFaults_local = value
|
||||
case "numa_pages_migrated":
|
||||
vmstat.NumaPagesMigrated = value
|
||||
case "pgmigrate_success":
|
||||
vmstat.PageMigrateSuccess = value
|
||||
case "pgmigrate_fail":
|
||||
vmstat.PageMigrateFail = value
|
||||
case "compact_migrate_scanned":
|
||||
vmstat.CompactMigrateScanned = value
|
||||
case "compact_free_scanned":
|
||||
vmstat.CompactFreeScanned = value
|
||||
case "compact_isolated":
|
||||
vmstat.CompactIsolated = value
|
||||
case "compact_stall":
|
||||
vmstat.CompactStall = value
|
||||
case "compact_fail":
|
||||
vmstat.CompactFail = value
|
||||
case "compact_success":
|
||||
vmstat.CompactSuccess = value
|
||||
case "htlb_buddy_alloc_success":
|
||||
vmstat.HtlbBuddyAllocSuccess = value
|
||||
case "htlb_buddy_alloc_fail":
|
||||
vmstat.HtlbBuddyAllocFail = value
|
||||
case "unevictable_pgs_culled":
|
||||
vmstat.UnevictablePagesCulled = value
|
||||
case "unevictable_pgs_scanned":
|
||||
vmstat.UnevictablePagesScanned = value
|
||||
case "unevictable_pgs_rescued":
|
||||
vmstat.UnevictablePagesRescued = value
|
||||
case "unevictable_pgs_mlocked":
|
||||
vmstat.UnevictablePagesMlocked = value
|
||||
case "unevictable_pgs_munlocked":
|
||||
vmstat.UnevictablePagesMunlocked = value
|
||||
case "unevictable_pgs_cleared":
|
||||
vmstat.UnevictablePagesCleared = value
|
||||
case "unevictable_pgs_stranded":
|
||||
vmstat.UnevictablePagesStranded = value
|
||||
case "thp_fault_alloc":
|
||||
vmstat.THPFaultAlloc = value
|
||||
case "thp_fault_fallback":
|
||||
vmstat.THPFaultFallback = value
|
||||
case "thp_collapse_alloc":
|
||||
vmstat.THPCollapseAlloc = value
|
||||
case "thp_collapse_alloc_failed":
|
||||
vmstat.THPCollapseAllocFailed = value
|
||||
case "thp_split":
|
||||
vmstat.THPSplit = value
|
||||
case "thp_zero_page_alloc":
|
||||
vmstat.THPZeroPageAlloc = value
|
||||
case "thp_zero_page_alloc_failed":
|
||||
vmstat.THPZeroPageAllocFailed = value
|
||||
}
|
||||
}
|
||||
return &vmstat, nil
|
||||
}
|
||||
12
vendor/github.com/c9s/goprocinfo/linux/vmstat_test.go
generated
vendored
Normal file
12
vendor/github.com/c9s/goprocinfo/linux/vmstat_test.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package linux
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestVMStat(t *testing.T) {
|
||||
vmstat, err := ReadVMStat("proc/vmstat")
|
||||
if err != nil {
|
||||
t.Fatal("vmstat read fail")
|
||||
}
|
||||
_ = vmstat
|
||||
t.Logf("%+v", vmstat)
|
||||
}
|
||||
7
vendor/manifest
vendored
7
vendor/manifest
vendored
@@ -52,6 +52,13 @@
|
||||
"revision": "fb6c0b0e1ff03057a054886141927cdce6239dec",
|
||||
"branch": "master"
|
||||
},
|
||||
{
|
||||
"importpath": "github.com/c9s/goprocinfo/linux",
|
||||
"repository": "https://github.com/c9s/goprocinfo",
|
||||
"revision": "19cb9f127a9c8d2034cf59ccb683cdb94b9deb6c",
|
||||
"branch": "master",
|
||||
"path": "/linux"
|
||||
},
|
||||
{
|
||||
"importpath": "github.com/certifi/gocertifi",
|
||||
"repository": "https://github.com/certifi/gocertifi",
|
||||
|
||||
Reference in New Issue
Block a user