diff --git a/README.rst b/README.rst index c14d2ef..ac67d54 100644 --- a/README.rst +++ b/README.rst @@ -102,7 +102,7 @@ Current Status - disk_partitions (linux, freebsd, windows) - disk_io_counters (linux) - disk_usage (linux, freebsd, windows) - - net_io_counters (linux, windows) + - net_io_counters (linux, freebsd, windows) - boot_time (linux, freebsd, windows(but little broken)) - users (linux, freebsd) - pids (linux, freebsd) diff --git a/common.go b/common.go index 4c41064..da96eb8 100644 --- a/common.go +++ b/common.go @@ -58,19 +58,19 @@ func byteToString(orig []byte) string { } // Parse to int32 without error -func parseInt32(val string) int32 { +func mustParseInt32(val string) int32 { vv, _ := strconv.ParseInt(val, 10, 32) return int32(vv) } // Parse to uint64 without error -func parseUint64(val string) uint64 { +func mustParseUint64(val string) uint64 { vv, _ := strconv.ParseInt(val, 10, 64) return uint64(vv) } // Parse to Float64 without error -func parseFloat64(val string) float64 { +func mustParseFloat64(val string) float64 { vv, _ := strconv.ParseFloat(val, 64) return vv } diff --git a/cpu_freebsd.go b/cpu_freebsd.go index a416824..acc9951 100644 --- a/cpu_freebsd.go +++ b/cpu_freebsd.go @@ -62,12 +62,12 @@ func CPUInfo() ([]CPUInfoStat, error) { for _, line := range lines { if matches := regexp.MustCompile(`CPU:\s+(.+) \(([\d.]+).+\)`).FindStringSubmatch(line); matches != nil { c.ModelName = matches[1] - c.Mhz = parseFloat64(matches[2]) + c.Mhz = mustParseFloat64(matches[2]) } else if matches := regexp.MustCompile(`Origin = "(.+)" Id = (.+) Family = (.+) Model = (.+) Stepping = (.+)`).FindStringSubmatch(line); matches != nil { c.VendorID = matches[1] c.Family = matches[3] c.Model = matches[4] - c.Stepping = parseInt32(matches[5]) + c.Stepping = mustParseInt32(matches[5]) } else if matches := regexp.MustCompile(`Features=.+<(.+)>`).FindStringSubmatch(line); matches != nil { for _, v := range strings.Split(matches[1], ",") { c.Flags = append(c.Flags, strings.ToLower(v)) @@ -78,7 +78,7 @@ func CPUInfo() ([]CPUInfoStat, error) { } } else if matches := regexp.MustCompile(`Logical CPUs per core: (\d+)`).FindStringSubmatch(line); matches != nil { // FIXME: no this line? - c.Cores = parseInt32(matches[1]) + c.Cores = mustParseInt32(matches[1]) } } diff --git a/cpu_linux.go b/cpu_linux.go index 74e3e20..5ec5f88 100644 --- a/cpu_linux.go +++ b/cpu_linux.go @@ -46,7 +46,7 @@ func CPUInfo() ([]CPUInfoStat, error) { switch key { case "processor": c = CPUInfoStat{} - c.CPU = parseInt32(value) + c.CPU = mustParseInt32(value) case "vendor_id": c.VendorID = value case "cpu family": @@ -56,17 +56,17 @@ func CPUInfo() ([]CPUInfoStat, error) { case "model name": c.ModelName = value case "stepping": - c.Stepping = parseInt32(value) + c.Stepping = mustParseInt32(value) case "cpu MHz": - c.Mhz = parseFloat64(value) + c.Mhz = mustParseFloat64(value) case "cache size": - c.CacheSize = parseInt32(strings.Replace(value, " KB", "", 1)) + c.CacheSize = mustParseInt32(strings.Replace(value, " KB", "", 1)) case "physical id": c.PhysicalID = value case "core id": c.CoreID = value case "cpu cores": - c.Cores = parseInt32(value) + c.Cores = mustParseInt32(value) case "flags": c.Flags = strings.Split(value, ",") } diff --git a/disk_linux.go b/disk_linux.go index 58f7eaf..6a7ceeb 100644 --- a/disk_linux.go +++ b/disk_linux.go @@ -69,12 +69,12 @@ func DiskIOCounters() (map[string]DiskIOCountersStat, error) { for _, line := range lines { fields := strings.Fields(line) name := fields[2] - reads := parseUint64(fields[3]) - rbytes := parseUint64(fields[5]) - rtime := parseUint64(fields[6]) - writes := parseUint64(fields[7]) - wbytes := parseUint64(fields[9]) - wtime := parseUint64(fields[10]) + reads := mustParseUint64(fields[3]) + rbytes := mustParseUint64(fields[5]) + rtime := mustParseUint64(fields[6]) + writes := mustParseUint64(fields[7]) + wbytes := mustParseUint64(fields[9]) + wtime := mustParseUint64(fields[10]) if stringContains(partitions, name) { d := DiskIOCountersStat{ Name: name, diff --git a/host.go b/host.go index d90c03f..ae3b327 100644 --- a/host.go +++ b/host.go @@ -8,7 +8,7 @@ import ( // This is not in the psutil but it useful. type HostInfoStat struct { Hostname string `json:"hostname"` - Uptime int64 `json:"uptime"` + Uptime uint64 `json:"uptime"` Procs uint64 `json:"procs"` // number of processes OS string `json:"os"` // ex: freebsd, linux Platform string `json:"platform"` // ex: ubuntu, linuxmint diff --git a/host_freebsd.go b/host_freebsd.go index 96a7832..71f05f8 100644 --- a/host_freebsd.go +++ b/host_freebsd.go @@ -7,19 +7,41 @@ import ( "encoding/binary" "io/ioutil" "os" + "os/exec" + "runtime" "strconv" "strings" "unsafe" ) func HostInfo() (*HostInfoStat, error) { - ret := &HostInfoStat{} + ret := &HostInfoStat{ + OS: runtime.GOOS, + PlatformFamily: "freebsd", + } hostname, err := os.Hostname() - ret.Hostname = hostname if err != nil { return ret, err } + ret.Hostname = hostname + + out, err := exec.Command("uname", "-s").Output() + if err == nil { + ret.Platform = strings.ToLower(strings.TrimSpace(string(out))) + } + + out, err = exec.Command("uname", "-r").Output() + if err == nil { + ret.PlatformVersion = strings.ToLower(strings.TrimSpace(string(out))) + } + + values, err := doSysctrl("kern.boottime") + if err == nil { + // ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014 + v := strings.Replace(values[2], ",", "", 1) + ret.Uptime = mustParseUint64(v) + } return ret, nil } diff --git a/host_linux.go b/host_linux.go index 7f56e7f..6733d39 100644 --- a/host_linux.go +++ b/host_linux.go @@ -38,16 +38,20 @@ func HostInfo() (*HostInfoStat, error) { ret.PlatformFamily = family ret.PlatformVersion = version } + uptime, err := BootTime() + if err == nil { + ret.Uptime = uptime + } return ret, nil } -func BootTime() (int64, error) { +func BootTime() (uint64, error) { sysinfo := &syscall.Sysinfo_t{} if err := syscall.Sysinfo(sysinfo); err != nil { return 0, err } - return int64(sysinfo.Uptime), nil + return uint64(sysinfo.Uptime), nil } func Users() ([]UserStat, error) { diff --git a/host_windows.go b/host_windows.go index b3eea4c..8921187 100644 --- a/host_windows.go +++ b/host_windows.go @@ -26,7 +26,7 @@ func HostInfo() (*HostInfoStat, error) { return ret, syscall.GetLastError() } - ret.Uptime = int64(uptimemsec) / 1000 + ret.Uptime = uint64(uptimemsec) / 1000 procs, err := Pids() if err != nil { @@ -38,7 +38,7 @@ func HostInfo() (*HostInfoStat, error) { return ret, nil } -func BootTime() (int64, error) { +func BootTime() (uint64, error) { var lpSystemTimeAsFileTime FILETIME r, _, _ := procGetSystemTimeAsFileTime.Call(uintptr(unsafe.Pointer(&lpSystemTimeAsFileTime))) @@ -56,7 +56,7 @@ func BootTime() (int64, error) { } uptime := uint64(u) / 1000 - return int64(pt - uptime), nil + return uint64(pt - uptime), nil } func Users() ([]UserStat, error) { diff --git a/mem_freebsd.go b/mem_freebsd.go index 16e0f02..f3851c1 100644 --- a/mem_freebsd.go +++ b/mem_freebsd.go @@ -10,7 +10,7 @@ import ( func VirtualMemory() (*VirtualMemoryStat, error) { pageSize, _ := doSysctrl("vm.stats.vm.v_page_size") - p := parseUint64(pageSize[0]) + p := mustParseUint64(pageSize[0]) pageCount, _ := doSysctrl("vm.stats.vm.v_page_count") free, _ := doSysctrl("vm.stats.vm.v_free_count") @@ -21,13 +21,13 @@ func VirtualMemory() (*VirtualMemoryStat, error) { wired, _ := doSysctrl("vm.stats.vm.v_wire_count") ret := &VirtualMemoryStat{ - Total: parseUint64(pageCount[0]) * p, - Free: parseUint64(free[0]) * p, - Active: parseUint64(active[0]) * p, - Inactive: parseUint64(inactive[0]) * p, - Cached: parseUint64(cache[0]) * p, - Buffers: parseUint64(buffer[0]), - Wired: parseUint64(wired[0]) * p, + Total: mustParseUint64(pageCount[0]) * p, + Free: mustParseUint64(free[0]) * p, + Active: mustParseUint64(active[0]) * p, + Inactive: mustParseUint64(inactive[0]) * p, + Cached: mustParseUint64(cache[0]) * p, + Buffers: mustParseUint64(buffer[0]), + Wired: mustParseUint64(wired[0]) * p, } // TODO: platform independent (worked freebsd?) @@ -57,10 +57,10 @@ func SwapMemory() (*SwapMemoryStat, error) { u := strings.Replace(values[4], "%", "", 1) ret = &SwapMemoryStat{ - Total: parseUint64(values[1]), - Used: parseUint64(values[2]), - Free: parseUint64(values[3]), - UsedPercent: parseFloat64(u), + Total: mustParseUint64(values[1]), + Used: mustParseUint64(values[2]), + Free: mustParseUint64(values[3]), + UsedPercent: mustParseFloat64(u), } } diff --git a/net_freebsd.go b/net_freebsd.go index fb0a3f0..27257c9 100644 --- a/net_freebsd.go +++ b/net_freebsd.go @@ -3,9 +3,43 @@ package gopsutil import ( - "errors" + "os/exec" + "strings" ) func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { - return nil, errors.New("not implemented yet") + out, err := exec.Command("/usr/bin/netstat", "-ibdn").Output() + if err != nil { + return nil, err + } + + lines := strings.Split(string(out), "\n") + ret := make([]NetIOCountersStat, 0, len(lines)-1) + + for _, line := range lines { + values := strings.Fields(line) + if len(values) < 1 || values[0] == "Name" { + continue + } + base := 1 + // sometimes Address is ommitted + if len(values) < 13 { + base = 0 + } + + n := NetIOCountersStat{ + Name: values[0], + PacketsRecv: mustParseUint64(values[base+3]), + Errin: mustParseUint64(values[base+4]), + Dropin: mustParseUint64(values[base+5]), + BytesRecv: mustParseUint64(values[base+6]), + PacketsSent: mustParseUint64(values[base+7]), + Errout: mustParseUint64(values[base+8]), + BytesSent: mustParseUint64(values[base+9]), + Dropout: mustParseUint64(values[base+11]), + } + ret = append(ret, n) + } + + return ret, nil } diff --git a/net_linux.go b/net_linux.go index 20c08a6..efde2d3 100644 --- a/net_linux.go +++ b/net_linux.go @@ -24,13 +24,13 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { } nic := NetIOCountersStat{ Name: strings.Trim(fields[0], ":"), - BytesRecv: parseUint64(fields[1]), - Errin: parseUint64(fields[2]), - Dropin: parseUint64(fields[3]), - BytesSent: parseUint64(fields[9]), - PacketsSent: parseUint64(fields[10]), - Errout: parseUint64(fields[11]), - Dropout: parseUint64(fields[12]), + BytesRecv: mustParseUint64(fields[1]), + Errin: mustParseUint64(fields[2]), + Dropin: mustParseUint64(fields[3]), + BytesSent: mustParseUint64(fields[9]), + PacketsSent: mustParseUint64(fields[10]), + Errout: mustParseUint64(fields[11]), + Dropout: mustParseUint64(fields[12]), } ret = append(ret, nic) } diff --git a/process_linux.go b/process_linux.go index 764ace2..f271a3b 100644 --- a/process_linux.go +++ b/process_linux.go @@ -234,25 +234,25 @@ func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) { v := strings.Trim(field[1], " kB") // remove last "kB" switch field[0] { case "Size": - m.Size = parseUint64(v) + m.Size = mustParseUint64(v) case "Rss": - m.Rss = parseUint64(v) + m.Rss = mustParseUint64(v) case "Pss": - m.Pss = parseUint64(v) + m.Pss = mustParseUint64(v) case "Shared_Clean": - m.SharedClean = parseUint64(v) + m.SharedClean = mustParseUint64(v) case "Shared_Dirty": - m.SharedDirty = parseUint64(v) + m.SharedDirty = mustParseUint64(v) case "Private_Clean": - m.PrivateClean = parseUint64(v) + m.PrivateClean = mustParseUint64(v) case "Private_Dirty": - m.PrivateDirty = parseUint64(v) + m.PrivateDirty = mustParseUint64(v) case "Referenced": - m.Referenced = parseUint64(v) + m.Referenced = mustParseUint64(v) case "Anonymous": - m.Anonymous = parseUint64(v) + m.Anonymous = mustParseUint64(v) case "Swap": - m.Swap = parseUint64(v) + m.Swap = mustParseUint64(v) } } return m @@ -301,7 +301,7 @@ func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) { } o := &OpenFilesStat{ Path: filepath, - Fd: parseUint64(fd), + Fd: mustParseUint64(fd), } openfiles = append(openfiles, o) } @@ -368,13 +368,13 @@ func (p *Process) fillFromIO() (*IOCountersStat, error) { } switch field[0] { case "rchar": - ret.ReadCount = parseInt32(strings.Trim(field[1], " \t")) + ret.ReadCount = mustParseInt32(strings.Trim(field[1], " \t")) case "wchar": - ret.WriteCount = parseInt32(strings.Trim(field[1], " \t")) + ret.WriteCount = mustParseInt32(strings.Trim(field[1], " \t")) case "read_bytes": - ret.ReadBytes = parseInt32(strings.Trim(field[1], " \t")) + ret.ReadBytes = mustParseInt32(strings.Trim(field[1], " \t")) case "write_bytes": - ret.WriteBytes = parseInt32(strings.Trim(field[1], " \t")) + ret.WriteBytes = mustParseInt32(strings.Trim(field[1], " \t")) } } @@ -391,8 +391,8 @@ func (p *Process) fillFromStatm() (*MemoryInfoStat, *MemoryInfoExStat, error) { } fields := strings.Split(string(contents), " ") - rss := parseUint64(fields[0]) * PAGESIZE - vms := parseUint64(fields[1]) * PAGESIZE + rss := mustParseUint64(fields[0]) * PAGESIZE + vms := mustParseUint64(fields[1]) * PAGESIZE memInfo := &MemoryInfoStat{ RSS: rss, VMS: vms, @@ -400,10 +400,10 @@ func (p *Process) fillFromStatm() (*MemoryInfoStat, *MemoryInfoExStat, error) { memInfoEx := &MemoryInfoExStat{ RSS: rss, VMS: vms, - Shared: parseUint64(fields[2]) * PAGESIZE, - Text: parseUint64(fields[3]) * PAGESIZE, - Lib: parseUint64(fields[4]) * PAGESIZE, - Dirty: parseUint64(fields[5]) * PAGESIZE, + Shared: mustParseUint64(fields[2]) * PAGESIZE, + Text: mustParseUint64(fields[3]) * PAGESIZE, + Lib: mustParseUint64(fields[4]) * PAGESIZE, + Dirty: mustParseUint64(fields[5]) * PAGESIZE, } return memInfo, memInfoEx, nil @@ -443,18 +443,18 @@ func (p *Process) fillFromStatus() (string, string, []int32, []int32, int32, *Nu // case "PPid": // filled by fillFromStat case "Uid": for _, i := range strings.Split(field[1], "\t") { - uids = append(uids, parseInt32(i)) + uids = append(uids, mustParseInt32(i)) } case "Gid": for _, i := range strings.Split(field[1], "\t") { - gids = append(gids, parseInt32(i)) + gids = append(gids, mustParseInt32(i)) } case "Threads": - numThreads = parseInt32(field[1]) + numThreads = mustParseInt32(field[1]) case "voluntary_ctxt_switches": - vol = parseInt32(field[1]) + vol = mustParseInt32(field[1]) case "nonvoluntary_ctxt_switches": - unvol = parseInt32(field[1]) + unvol = mustParseInt32(field[1]) } } @@ -477,10 +477,10 @@ func (p *Process) fillFromStat() (string, int32, *CPUTimesStat, int64, int32, er termmap, err := getTerminalMap() terminal := "" if err == nil { - terminal = termmap[parseUint64(fields[6])] + terminal = termmap[mustParseUint64(fields[6])] } - ppid := parseInt32(fields[3]) + ppid := mustParseInt32(fields[3]) utime, _ := strconv.ParseFloat(fields[13], 64) stime, _ := strconv.ParseFloat(fields[14], 64) @@ -491,10 +491,10 @@ func (p *Process) fillFromStat() (string, int32, *CPUTimesStat, int64, int32, er } bootTime, _ := BootTime() - ctime := ((parseUint64(fields[21]) / uint64(CLOCK_TICKS)) + uint64(bootTime)) * 1000 + ctime := ((mustParseUint64(fields[21]) / uint64(CLOCK_TICKS)) + uint64(bootTime)) * 1000 createTime := int64(ctime) - // p.Nice = parseInt32(fields[18]) + // p.Nice = mustParseInt32(fields[18]) // use syscall instead of parse Stat file snice, _ := syscall.Getpriority(PRIO_PROCESS, int(pid)) nice := int32(snice) // FIXME: is this true?