From 5b605dc1a36dc1eb97e30eb01604ecae6d251f22 Mon Sep 17 00:00:00 2001 From: WAKAYAMA Shirou Date: Fri, 18 Apr 2014 16:34:47 +0900 Subject: [PATCH] initial import. --- .gitignore | 1 - README.rst | 10 ++++++++++ common.go | 27 +++++++++++++++++++++++++++ cpu.go | 31 +++++++++++++++++++++++++++++++ cpu_freebsd.go | 14 ++++++++++++++ cpu_linux.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ cpu_test.go | 35 +++++++++++++++++++++++++++++++++++ disk.go | 26 ++++++++++++++++++++++++++ disk_test.go | 18 ++++++++++++++++++ disk_unix.go | 27 +++++++++++++++++++++++++++ host.go | 38 ++++++++++++++++++++++++++++++++++++++ host_test.go | 17 +++++++++++++++++ load.go | 14 ++++++++++++++ load_freebsd.go | 40 ++++++++++++++++++++++++++++++++++++++++ load_linux.go | 40 ++++++++++++++++++++++++++++++++++++++++ load_test.go | 20 ++++++++++++++++++++ mem.go | 31 +++++++++++++++++++++++++++++++ mem_linux.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ mem_test.go | 29 +++++++++++++++++++++++++++++ 19 files changed, 518 insertions(+), 1 deletion(-) create mode 100644 README.rst create mode 100644 common.go create mode 100644 cpu.go create mode 100644 cpu_freebsd.go create mode 100644 cpu_linux.go create mode 100644 cpu_test.go create mode 100644 disk.go create mode 100644 disk_test.go create mode 100644 disk_unix.go create mode 100644 host.go create mode 100644 host_test.go create mode 100644 load.go create mode 100644 load_freebsd.go create mode 100644 load_linux.go create mode 100644 load_test.go create mode 100644 mem.go create mode 100644 mem_linux.go create mode 100644 mem_test.go diff --git a/.gitignore b/.gitignore index f7561ac..1f2308d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ *~ #* -pesand diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..4a804b2 --- /dev/null +++ b/README.rst @@ -0,0 +1,10 @@ +gopsutil: psutil for golang +============================== + + + + +- psutil: http://pythonhosted.org/psutil/ +- dstat: https://github.com/dagwieers/dstat +- gosiger: https://github.com/cloudfoundry/gosigar/ +- goprocinfo: https://github.com/c9s/goprocinfo diff --git a/common.go b/common.go new file mode 100644 index 0000000..57281d6 --- /dev/null +++ b/common.go @@ -0,0 +1,27 @@ +package main + +import ( + "bufio" + "os" + "strings" +) + +// Read contents from file and split by new line. +func ReadLines(filename string) ([]string, error) { + f, err := os.Open(filename) + if err != nil { + return []string{""}, err + } + defer f.Close() + + ret := make([]string, 0) + + r := bufio.NewReader(f) + line, err := r.ReadString('\n') + for err == nil { + ret = append(ret, strings.Trim(line, "\n")) + line, err = r.ReadString('\n') + } + + return ret, err +} diff --git a/cpu.go b/cpu.go new file mode 100644 index 0000000..236616b --- /dev/null +++ b/cpu.go @@ -0,0 +1,31 @@ +package main + +import ( + "runtime" +) + +type CPU struct{} + +type CPU_Times struct { + Cpu string `json:"cpu"` + User uint64 `json:"user"` + System uint64 `json:"system"` + Idle uint64 `json:"idle"` + Nice uint64 `json:"nice"` + Iowait uint64 `json:"iowait"` + Irq uint64 `json:"irq"` + Softirq uint64 `json:"softirq"` + Steal uint64 `json:"steal"` + Guest uint64 `json:"guest"` + Guest_nice uint64 `json:"guest_nice"` + Stolen uint64 `json:"stolen"` +} + +func NewCPU() CPU { + p := CPU{} + return p +} + +func (c CPU) Cpu_counts() (int, error) { + return runtime.NumCPU(), nil +} diff --git a/cpu_freebsd.go b/cpu_freebsd.go new file mode 100644 index 0000000..33ff0d9 --- /dev/null +++ b/cpu_freebsd.go @@ -0,0 +1,14 @@ +// +build freebsd + +package main + +import ( + "fmt" +) + +func (c CPU) Cpu_times() map[string]string { + ret := make(map[string]string) + + fmt.Println("FreeBSD") + return ret +} diff --git a/cpu_linux.go b/cpu_linux.go new file mode 100644 index 0000000..a58b694 --- /dev/null +++ b/cpu_linux.go @@ -0,0 +1,50 @@ +// +build linux + +package main + +import ( + "strconv" + "strings" +) + +func (c CPU) Cpu_times() ([]CPU_Times, error) { + ret := make([]CPU_Times, 0) + + filename := "/proc/stat" + lines, _ := ReadLines(filename) + for _, line := range lines { + fields := strings.Fields(line) + + if strings.HasPrefix(fields[0], "cpu") == false { + continue + } + + cpu := fields[0] + if cpu == "cpu" { + cpu = "cpu-total" + } + user, _ := strconv.ParseUint(fields[1], 10, 64) + nice, _ := strconv.ParseUint(fields[2], 10, 64) + system, _ := strconv.ParseUint(fields[3], 10, 64) + idle, _ := strconv.ParseUint(fields[4], 10, 64) + iowait, _ := strconv.ParseUint(fields[5], 10, 64) + irq, _ := strconv.ParseUint(fields[6], 10, 64) + softirq, _ := strconv.ParseUint(fields[7], 10, 64) + stolen, _ := strconv.ParseUint(fields[8], 10, 64) + ct := CPU_Times{ + Cpu: cpu, + User: user, + Nice: nice, + System: system, + Idle: idle, + Iowait: iowait, + Irq: irq, + Softirq: softirq, + Stolen: stolen, + } + + ret = append(ret, ct) + } + + return ret, nil +} diff --git a/cpu_test.go b/cpu_test.go new file mode 100644 index 0000000..76fdf24 --- /dev/null +++ b/cpu_test.go @@ -0,0 +1,35 @@ +package main + +import ( + "testing" +) + +func TestCpu_times(t *testing.T) { + cpu := NewCPU() + + v, err := cpu.Cpu_times() + if err != nil { + t.Errorf("error %v", err) + } + if len(v) == 0 { + t.Errorf("could not get CPUs ", err) + } + + for _, vv := range v { + if vv.User == 0 { + t.Errorf("could not get CPU User: %v", vv) + } + } +} + +func TestCpu_counts(t *testing.T) { + cpu := NewCPU() + + v, err := cpu.Cpu_counts() + if err != nil { + t.Errorf("error %v", err) + } + if v == 0 { + t.Errorf("could not get CPU counts: %v", v) + } +} diff --git a/disk.go b/disk.go new file mode 100644 index 0000000..58edb09 --- /dev/null +++ b/disk.go @@ -0,0 +1,26 @@ +package main + +type Disk struct{} + +type Disk_usage struct { + Path string `json:"path"` + Total uint64 `json:"total"` + Free uint64 `json:"free"` + Available uint64 `json:"available"` + Used uint64 `json:"used"` + Percent float64 `json:"percent"` +} + +type Disk_IO_Counters struct { + ReadCount uint64 `json:"readCount"` + WriteCount uint64 `json:"writeCount"` + ReadBytes uint64 `json:"readBytes"` + WriteBytes uint64 `json:"writeBytes"` + ReadTime uint64 `json:"readTime"` + WriteTime uint64 `json:"writeTime"` +} + +func NewDisk() Disk { + d := Disk{} + return d +} diff --git a/disk_test.go b/disk_test.go new file mode 100644 index 0000000..5bb3e0b --- /dev/null +++ b/disk_test.go @@ -0,0 +1,18 @@ +package main + +import ( + "encoding/json" + "fmt" + "testing" +) + +func TestDisk_usage(t *testing.T) { + disk := NewDisk() + + v, err := disk.Disk_usage("/") + if err != nil { + t.Errorf("error %v", err) + } + d, _ := json.Marshal(v) + fmt.Printf("%s\n", d) +} diff --git a/disk_unix.go b/disk_unix.go new file mode 100644 index 0000000..053760c --- /dev/null +++ b/disk_unix.go @@ -0,0 +1,27 @@ +// +build freebsd linux + +package main + +import "syscall" + +func (d Disk) Disk_usage(path string) (Disk_usage, error) { + stat := syscall.Statfs_t{} + err := syscall.Statfs(path, &stat) + if err != nil { + return Disk_usage{Path: path}, err + } + + bsize := stat.Bsize / 512 + + ret := Disk_usage{ + Path: path, + Total: (uint64(stat.Blocks) * uint64(bsize)) >> 1, + Free: (uint64(stat.Bfree) * uint64(bsize)) >> 1, + Available: (uint64(stat.Bavail) * uint64(bsize)) >> 1, + } + + ret.Used = (ret.Total - ret.Free) + ret.Percent = (float64(ret.Used) / float64(ret.Total)) * 100.0 + + return ret, nil +} diff --git a/host.go b/host.go new file mode 100644 index 0000000..9a5f3bd --- /dev/null +++ b/host.go @@ -0,0 +1,38 @@ +package main + +import ( + "os" + "syscall" +) + +type Host struct{} + +type HostInfo struct { + Hostname string `json:"hostname"` + Uptime int64 `json:"uptime"` + Procs uint64 `json:"procs"` +} + +func NewHost() Host { + h := Host{} + return h +} + +func (h Host) HostInfo() (HostInfo, error) { + ret := HostInfo{} + sysinfo := &syscall.Sysinfo_t{} + + if err := syscall.Sysinfo(sysinfo); err != nil { + return ret, err + } + + hostname, err := os.Hostname() + if err != nil { + return ret, err + } + ret.Hostname = hostname + ret.Uptime = sysinfo.Uptime + ret.Procs = uint64(sysinfo.Procs) + + return ret, nil +} diff --git a/host_test.go b/host_test.go new file mode 100644 index 0000000..a4ed734 --- /dev/null +++ b/host_test.go @@ -0,0 +1,17 @@ +package main + +import ( + "testing" +) + +func TestHostInfo(t *testing.T) { + host := NewHost() + + v, err := host.HostInfo() + if err != nil { + t.Errorf("error %v", err) + } + if v.Uptime == 0 { + t.Errorf("Could not get uptime %v", v) + } +} diff --git a/load.go b/load.go new file mode 100644 index 0000000..59304f3 --- /dev/null +++ b/load.go @@ -0,0 +1,14 @@ +package main + +type Load struct{} + +type LoadAvg struct { + Load1 float64 `json:"load1"` + Load5 float64 `json:"load5"` + Load15 float64 `json:"load15"` +} + +func NewLoad() Load { + l := Load{} + return l +} diff --git a/load_freebsd.go b/load_freebsd.go new file mode 100644 index 0000000..6ff5698 --- /dev/null +++ b/load_freebsd.go @@ -0,0 +1,40 @@ +// +build freebsd + +package main + +import ( + "exec" + "strconv" + "strings" +) + +func (l Load) LoadAvg() (LoadAvg, error) { + out, err := exec.Command("/sbin/sysctl", "-n", "vm.loadavg").Output() + if err != nil { + return LoadAvg{}, err + } + v := strings.Replace(string(out), "{ ", "", 1) + v = strings.Replace(string(v), " }", "", 1) + values := strings.Fields(string(v)) + + load1, err := strconv.ParseFloat(values[0], 32) + if err != nil { + return LoadAvg{}, err + } + load5, err := strconv.ParseFloat(values[1], 32) + if err != nil { + return LoadAvg{}, err + } + load15, err := strconv.ParseFloat(values[2], 32) + if err != nil { + return LoadAvg{}, err + } + + ret := LoadAvg{ + Load1: float32(load1), + Load5: float32(load5), + Load15: float32(load15), + } + + return ret, nil +} diff --git a/load_linux.go b/load_linux.go new file mode 100644 index 0000000..62287bf --- /dev/null +++ b/load_linux.go @@ -0,0 +1,40 @@ +// +build linux + +package main + +import ( + "io/ioutil" + "strconv" + "strings" +) + +func (l Load) LoadAvg() (LoadAvg, error) { + filename := "/proc/loadavg" + line, err := ioutil.ReadFile(filename) + if err != nil { + return LoadAvg{}, err + } + + values := strings.Fields(string(line)) + + load1, err := strconv.ParseFloat(values[0], 64) + if err != nil { + return LoadAvg{}, err + } + load5, err := strconv.ParseFloat(values[1], 64) + if err != nil { + return LoadAvg{}, err + } + load15, err := strconv.ParseFloat(values[2], 64) + if err != nil { + return LoadAvg{}, err + } + + ret := LoadAvg{ + Load1: load1, + Load5: load5, + Load15: load15, + } + + return ret, nil +} diff --git a/load_test.go b/load_test.go new file mode 100644 index 0000000..503bd3d --- /dev/null +++ b/load_test.go @@ -0,0 +1,20 @@ +// +build linux + +package main + +import ( + "testing" +) + +func TestLoad(t *testing.T) { + load := NewLoad() + + v, err := load.LoadAvg() + if err != nil { + t.Errorf("error %v", err) + } + + if v.Load1 == 0 || v.Load5 == 0 || v.Load15 == 0 { + t.Errorf("error load: %v", v) + } +} diff --git a/mem.go b/mem.go new file mode 100644 index 0000000..5efe9bd --- /dev/null +++ b/mem.go @@ -0,0 +1,31 @@ +package main + +type Mem struct{} + +type Virtual_memory struct { + Total uint64 `json:"total"` + Available uint64 `json:"available"` + Used uint64 `json:"used"` + UsedPercent float64 `json:"usedPercent"` + Free uint64 `json:"free"` + Active uint64 `json:"active"` + Inactive uint64 `json:"inactive"` + Buffers uint64 `json:"buffers"` + Cached uint64 `json:"cached"` + Wired uint64 `json:"wired"` + Shared uint64 `json:"shared"` +} + +type Swap_memory struct { + Total uint64 `json:"total"` + Used uint64 `json:"used"` + Free uint64 `json:"free"` + UsedPercent float64 `json:"usedPercent"` + Sin uint64 `json:"sin"` + Sout uint64 `json:"sout"` +} + +func NewMem() Mem { + m := Mem{} + return m +} diff --git a/mem_linux.go b/mem_linux.go new file mode 100644 index 0000000..4170d2f --- /dev/null +++ b/mem_linux.go @@ -0,0 +1,51 @@ +// +build freebsd linux + +package main + +import ( + "syscall" +) + +func (m Mem) Virtual_memory() (Virtual_memory, error) { + ret := Virtual_memory{} + sysinfo := &syscall.Sysinfo_t{} + + if err := syscall.Sysinfo(sysinfo); err != nil { + return ret, err + } + ret.Total = uint64(sysinfo.Totalram) + ret.Free = uint64(sysinfo.Freeram) + ret.Shared = uint64(sysinfo.Sharedram) + ret.Buffers = uint64(sysinfo.Bufferram) + + ret.Used = ret.Total - ret.Free + + // TODO: platform independent + ret.Available = ret.Free + ret.Buffers + ret.Cached + + ret.Used = ret.Total - ret.Free + ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 + + /* + kern := buffers + cached + ret.ActualFree = ret.Free + kern + ret.ActualUsed = ret.Used - kern + */ + + return ret, nil +} + +func (m Mem) Swap_memory() (Swap_memory, error) { + ret := Swap_memory{} + sysinfo := &syscall.Sysinfo_t{} + + if err := syscall.Sysinfo(sysinfo); err != nil { + return ret, err + } + ret.Total = sysinfo.Totalswap + ret.Free = sysinfo.Freeswap + ret.Used = ret.Total - ret.Free + ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0 + + return ret, nil +} diff --git a/mem_test.go b/mem_test.go new file mode 100644 index 0000000..13f0c61 --- /dev/null +++ b/mem_test.go @@ -0,0 +1,29 @@ +package main + +import ( + "encoding/json" + "fmt" + "testing" +) + +func TestVirtual_memory(t *testing.T) { + mem := NewMem() + + v, err := mem.Virtual_memory() + if err != nil { + t.Errorf("error %v", err) + } + d, _ := json.Marshal(v) + fmt.Printf("%s\n", d) +} + +func TestSwap_memory(t *testing.T) { + mem := NewMem() + + v, err := mem.Swap_memory() + if err != nil { + t.Errorf("error %v", err) + } + d, _ := json.Marshal(v) + fmt.Printf("%s\n", d) +}