// CgroupCPU returnes specified cgroup id CPU status. // containerid is same as docker id if you use docker. // If you use container via systemd.slice, you could use // containerid = docker-<container id>.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ func CgroupCPU(containerid string, base string) (*cpu.CPUTimesStat, error) { if len(base) == 0 { base = "/sys/fs/cgroup/cpuacct/docker" } path := path.Join(base, containerid, "cpuacct.stat") lines, err := common.ReadLines(path) if err != nil { return nil, err } // empty containerid means all cgroup if len(containerid) == 0 { containerid = "all" } ret := &cpu.CPUTimesStat{CPU: containerid} for _, line := range lines { fields := strings.Split(line, " ") if fields[0] == "user" { user, err := strconv.ParseFloat(fields[1], 64) if err == nil { ret.User = float64(user) } } if fields[0] == "system" { system, err := strconv.ParseFloat(fields[1], 64) if err == nil { ret.System = float64(system) } } } return ret, nil }
func DiskIOCounters() (map[string]DiskIOCountersStat, error) { filename := "/proc/diskstats" lines, err := common.ReadLines(filename) if err != nil { return nil, err } ret := make(map[string]DiskIOCountersStat, 0) empty := DiskIOCountersStat{} for _, line := range lines { fields := strings.Fields(line) name := fields[2] reads, err := strconv.ParseUint((fields[3]), 10, 64) if err != nil { return ret, err } rbytes, err := strconv.ParseUint((fields[5]), 10, 64) if err != nil { return ret, err } rtime, err := strconv.ParseUint((fields[6]), 10, 64) if err != nil { return ret, err } writes, err := strconv.ParseUint((fields[7]), 10, 64) if err != nil { return ret, err } wbytes, err := strconv.ParseUint((fields[9]), 10, 64) if err != nil { return ret, err } wtime, err := strconv.ParseUint((fields[10]), 10, 64) if err != nil { return ret, err } iotime, err := strconv.ParseUint((fields[12]), 10, 64) if err != nil { return ret, err } d := DiskIOCountersStat{ ReadBytes: rbytes * SectorSize, WriteBytes: wbytes * SectorSize, ReadCount: reads, WriteCount: writes, ReadTime: rtime, WriteTime: wtime, IoTime: iotime, } if d == empty { continue } d.Name = name d.SerialNumber = GetDiskSerialNumber(name) ret[name] = d } return ret, nil }
func (l *Lustre2) GetLustreProcStats(fileglob string, wanted_fields []*mapping, acc plugins.Accumulator) error { files, err := filepath.Glob(fileglob) if err != nil { return err } for _, file := range files { /* Turn /proc/fs/lustre/obdfilter/<ost_name>/stats and similar * into just the object store target name * Assumpion: the target name is always second to last, * which is true in Lustre 2.1->2.5 */ path := strings.Split(file, "/") name := path[len(path)-2] tags := map[string]string{ "name": name, } lines, err := common.ReadLines(file) if err != nil { return err } for _, line := range lines { fields := strings.Fields(line) for _, wanted := range wanted_fields { var data uint64 if fields[0] == wanted.inProc { wanted_field := wanted.field // if not set, assume field[1]. Shouldn't be field[0], as // that's a string if wanted_field == 0 { wanted_field = 1 } data, err = strconv.ParseUint((fields[wanted_field]), 10, 64) if err != nil { return err } report_name := wanted.inProc if wanted.reportAs != "" { report_name = wanted.reportAs } acc.Add(report_name, data, tags) } } } } return nil }
func getLSB() (*LSB, error) { ret := &LSB{} if common.PathExists("/etc/lsb-release") { contents, err := common.ReadLines("/etc/lsb-release") if err != nil { return ret, err // return empty } for _, line := range contents { field := strings.Split(line, "=") if len(field) < 2 { continue } switch field[0] { case "DISTRIB_ID": ret.ID = field[1] case "DISTRIB_RELEASE": ret.Release = field[1] case "DISTRIB_CODENAME": ret.Codename = field[1] case "DISTRIB_DESCRIPTION": ret.Description = field[1] } } } else if common.PathExists("/usr/bin/lsb_release") { out, err := exec.Command("/usr/bin/lsb_release").Output() if err != nil { return ret, err } for _, line := range strings.Split(string(out), "\n") { field := strings.Split(line, ":") if len(field) < 2 { continue } switch field[0] { case "Distributor ID": ret.ID = field[1] case "Release": ret.Release = field[1] case "Codename": ret.Codename = field[1] case "Description": ret.Description = field[1] } } } return ret, nil }
// Returns only one CPUInfoStat on FreeBSD func CPUInfo() ([]CPUInfoStat, error) { filename := "/var/run/dmesg.boot" lines, _ := common.ReadLines(filename) var ret []CPUInfoStat c := CPUInfoStat{} for _, line := range lines { if matches := regexp.MustCompile(`CPU:\s+(.+) \(([\d.]+).+\)`).FindStringSubmatch(line); matches != nil { c.ModelName = matches[1] t, err := strconv.ParseFloat(matches[2], 64) if err != nil { return ret, nil } c.Mhz = t } 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] t, err := strconv.ParseInt(matches[5], 10, 32) if err != nil { return ret, nil } c.Stepping = int32(t) } else if matches := regexp.MustCompile(`Features=.+<(.+)>`).FindStringSubmatch(line); matches != nil { for _, v := range strings.Split(matches[1], ",") { c.Flags = append(c.Flags, strings.ToLower(v)) } } else if matches := regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`).FindStringSubmatch(line); matches != nil { for _, v := range strings.Split(matches[1], ",") { c.Flags = append(c.Flags, strings.ToLower(v)) } } else if matches := regexp.MustCompile(`Logical CPUs per core: (\d+)`).FindStringSubmatch(line); matches != nil { // FIXME: no this line? t, err := strconv.ParseInt(matches[1], 10, 32) if err != nil { return ret, nil } c.Cores = int32(t) } } return append(ret, c), nil }
func SwapMemory() (*SwapMemoryStat, error) { sysinfo := &syscall.Sysinfo_t{} if err := syscall.Sysinfo(sysinfo); err != nil { return nil, err } ret := &SwapMemoryStat{ Total: uint64(sysinfo.Totalswap), Free: uint64(sysinfo.Freeswap), } ret.Used = ret.Total - ret.Free //check Infinity if ret.Total != 0 { ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0 } else { ret.UsedPercent = 0 } lines, _ := common.ReadLines("/proc/vmstat") for _, l := range lines { fields := strings.Fields(l) if len(fields) < 2 { continue } switch fields[0] { case "pswpin": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.Sin = value * 4 * 1024 case "pswpout": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.Sout = value * 4 * 1024 } } return ret, nil }
func VirtualMemory() (*VirtualMemoryStat, error) { filename := "/proc/meminfo" lines, _ := common.ReadLines(filename) ret := &VirtualMemoryStat{} for _, line := range lines { fields := strings.Split(line, ":") if len(fields) != 2 { continue } key := strings.TrimSpace(fields[0]) value := strings.TrimSpace(fields[1]) value = strings.Replace(value, " kB", "", -1) t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, err } switch key { case "MemTotal": ret.Total = t * 1024 case "MemFree": ret.Free = t * 1024 case "Buffers": ret.Buffers = t * 1024 case "Cached": ret.Cached = t * 1024 case "Active": ret.Active = t * 1024 case "Inactive": ret.Inactive = t * 1024 } } ret.Available = ret.Free + ret.Buffers + ret.Cached ret.Used = ret.Total - ret.Free ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0 return ret, nil }
// Get disk partitions. // should use setmntent(3) but this implement use /etc/mtab file func DiskPartitions(all bool) ([]DiskPartitionStat, error) { filename := "/etc/mtab" lines, err := common.ReadLines(filename) if err != nil { return nil, err } ret := make([]DiskPartitionStat, 0, len(lines)) for _, line := range lines { fields := strings.Fields(line) d := DiskPartitionStat{ Device: fields[0], Mountpoint: fields[1], Fstype: fields[2], Opts: fields[3], } ret = append(ret, d) } return ret, nil }
// NetIOCounters returnes network I/O statistics for every network // interface installed on the system. If pernic argument is false, // return only sum of all information (which name is 'all'). If true, // every network interface installed on the system is returned // separately. func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { filename := "/proc/net/dev" lines, err := common.ReadLines(filename) if err != nil { return nil, err } statlen := len(lines) - 1 ret := make([]NetIOCountersStat, 0, statlen) for _, line := range lines[2:] { parts := strings.SplitN(line, ":", 2) if len(parts) != 2 { continue } interfaceName := strings.TrimSpace(parts[0]) if interfaceName == "" { continue } fields := strings.Fields(strings.TrimSpace(parts[1])) bytesRecv, err := strconv.ParseUint(fields[0], 10, 64) if err != nil { return ret, err } packetsRecv, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { return ret, err } errIn, err := strconv.ParseUint(fields[2], 10, 64) if err != nil { return ret, err } dropIn, err := strconv.ParseUint(fields[3], 10, 64) if err != nil { return ret, err } bytesSent, err := strconv.ParseUint(fields[8], 10, 64) if err != nil { return ret, err } packetsSent, err := strconv.ParseUint(fields[9], 10, 64) if err != nil { return ret, err } errOut, err := strconv.ParseUint(fields[10], 10, 64) if err != nil { return ret, err } dropOut, err := strconv.ParseUint(fields[13], 10, 64) if err != nil { return ret, err } nic := NetIOCountersStat{ Name: interfaceName, BytesRecv: bytesRecv, PacketsRecv: packetsRecv, Errin: errIn, Dropin: dropIn, BytesSent: bytesSent, PacketsSent: packetsSent, Errout: errOut, Dropout: dropOut, } ret = append(ret, nic) } if pernic == false { return getNetIOCountersAll(ret) } return ret, nil }
func CgroupMem(containerid string, base string) (*CgroupMemStat, error) { if len(base) == 0 { base = "/sys/fs/cgroup/memory/docker" } statfile := path.Join(base, containerid, "memory.stat") if _, err := os.Stat(statfile); os.IsNotExist(err) { statfile = path.Join("/sys/fs/cgroup/memory/system.slice", "docker-"+containerid+".scope", "memory.stat") } // empty containerid means all cgroup if len(containerid) == 0 { containerid = "all" } lines, err := common.ReadLines(statfile) if err != nil { return nil, err } ret := &CgroupMemStat{ContainerID: containerid} for _, line := range lines { fields := strings.Split(line, " ") v, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } switch fields[0] { case "cache": ret.Cache = v case "rss": ret.RSS = v case "rss_huge": ret.RSSHuge = v case "mapped_file": ret.MappedFile = v case "pgpgin": ret.Pgpgin = v case "pgpgout": ret.Pgpgout = v case "pgfault": ret.Pgfault = v case "pgmajfault": ret.Pgmajfault = v case "inactive_anon": ret.InactiveAnon = v case "active_anon": ret.ActiveAnon = v case "inactive_file": ret.InactiveFile = v case "active_file": ret.ActiveFile = v case "unevictable": ret.Unevictable = v case "hierarchical_memory_limit": ret.HierarchicalMemoryLimit = v case "total_cache": ret.TotalCache = v case "total_rss": ret.TotalRSS = v case "total_rss_huge": ret.TotalRSSHuge = v case "total_mapped_file": ret.TotalMappedFile = v case "total_pgpgin": ret.TotalPgpgIn = v case "total_pgpgout": ret.TotalPgpgOut = v case "total_pgfault": ret.TotalPgFault = v case "total_pgmajfault": ret.TotalPgMajFault = v case "total_inactive_anon": ret.TotalInactiveAnon = v case "total_active_anon": ret.TotalActiveAnon = v case "total_inactive_file": ret.TotalInactiveFile = v case "total_active_file": ret.TotalActiveFile = v case "total_unevictable": ret.TotalUnevictable = v } } return ret, nil }
func GetVirtualization() (string, string, error) { var system string var role string if common.PathExists("/proc/xen") { system = "xen" role = "guest" // assume guest if common.PathExists("/proc/xen/capabilities") { contents, err := common.ReadLines("/proc/xen/capabilities") if err == nil { if common.StringContains(contents, "control_d") { role = "host" } } } } if common.PathExists("/proc/modules") { contents, err := common.ReadLines("/proc/modules") if err == nil { if common.StringContains(contents, "kvm") { system = "kvm" role = "host" } else if common.StringContains(contents, "vboxdrv") { system = "vbox" role = "host" } else if common.StringContains(contents, "vboxguest") { system = "vbox" role = "guest" } } } if common.PathExists("/proc/cpuinfo") { contents, err := common.ReadLines("/proc/cpuinfo") if err == nil { if common.StringContains(contents, "QEMU Virtual CPU") || common.StringContains(contents, "Common KVM processor") || common.StringContains(contents, "Common 32-bit KVM processor") { system = "kvm" role = "guest" } } } if common.PathExists("/proc/bc/0") { system = "openvz" role = "host" } else if common.PathExists("/proc/vz") { system = "openvz" role = "guest" } // not use dmidecode because it requires root if common.PathExists("/proc/self/status") { contents, err := common.ReadLines("/proc/self/status") if err == nil { if common.StringContains(contents, "s_context:") || common.StringContains(contents, "VxID:") { system = "linux-vserver" } // TODO: guest or host } } if common.PathExists("/proc/self/cgroup") { contents, err := common.ReadLines("/proc/self/cgroup") if err == nil { if common.StringContains(contents, "lxc") || common.StringContains(contents, "docker") { system = "lxc" role = "guest" } else if common.PathExists("/usr/bin/lxc-version") { // TODO: which system = "lxc" role = "host" } } } return system, role, nil }
func GetPlatformInformation() (platform string, family string, version string, err error) { lsb, err := getLSB() if err != nil { lsb = &LSB{} } if common.PathExists("/etc/oracle-release") { platform = "oracle" contents, err := common.ReadLines("/etc/oracle-release") if err == nil { version = getRedhatishVersion(contents) } } else if common.PathExists("/etc/enterprise-release") { platform = "oracle" contents, err := common.ReadLines("/etc/enterprise-release") if err == nil { version = getRedhatishVersion(contents) } } else if common.PathExists("/etc/debian_version") { if lsb.ID == "Ubuntu" { platform = "ubuntu" version = lsb.Release } else if lsb.ID == "LinuxMint" { platform = "linuxmint" version = lsb.Release } else { if common.PathExists("/usr/bin/raspi-config") { platform = "raspbian" } else { platform = "debian" } contents, err := common.ReadLines("/etc/debian_version") if err == nil { version = contents[0] } } } else if common.PathExists("/etc/redhat-release") { contents, err := common.ReadLines("/etc/redhat-release") if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } } else if common.PathExists("/etc/system-release") { contents, err := common.ReadLines("/etc/system-release") if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } } else if common.PathExists("/etc/gentoo-release") { platform = "gentoo" contents, err := common.ReadLines("/etc/gentoo-release") if err == nil { version = getRedhatishVersion(contents) } // TODO: suse detection // TODO: slackware detecion } else if common.PathExists("/etc/arch-release") { platform = "arch" // TODO: exherbo detection } else if lsb.ID == "RedHat" { platform = "redhat" version = lsb.Release } else if lsb.ID == "Amazon" { platform = "amazon" version = lsb.Release } else if lsb.ID == "ScientificSL" { platform = "scientific" version = lsb.Release } else if lsb.ID == "XenServer" { platform = "xenserver" version = lsb.Release } else if lsb.ID != "" { platform = strings.ToLower(lsb.ID) version = lsb.Release } switch platform { case "debian", "ubuntu", "linuxmint", "raspbian": family = "debian" case "fedora": family = "fedora" case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm": family = "rhel" case "suse": family = "suse" case "gentoo": family = "gentoo" case "slackware": family = "slackware" case "arch": family = "arch" case "exherbo": family = "exherbo" } return platform, family, version, nil }
func CPUInfo() ([]CPUInfoStat, error) { filename := "/proc/cpuinfo" lines, _ := common.ReadLines(filename) var ret []CPUInfoStat var c CPUInfoStat for _, line := range lines { fields := strings.Split(line, ":") if len(fields) < 2 { if c.VendorID != "" { ret = append(ret, c) } continue } key := strings.TrimSpace(fields[0]) value := strings.TrimSpace(fields[1]) switch key { case "processor": c = CPUInfoStat{} t, err := strconv.ParseInt(value, 10, 64) if err != nil { return ret, err } c.CPU = int32(t) case "vendor_id": c.VendorID = value case "cpu family": c.Family = value case "model": c.Model = value case "model name": c.ModelName = value case "stepping": t, err := strconv.ParseInt(value, 10, 64) if err != nil { return ret, err } c.Stepping = int32(t) case "cpu MHz": t, err := strconv.ParseFloat(value, 64) if err != nil { return ret, err } c.Mhz = t case "cache size": t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64) if err != nil { return ret, err } c.CacheSize = int32(t) case "physical id": c.PhysicalID = value case "core id": c.CoreID = value case "cpu cores": t, err := strconv.ParseInt(value, 10, 64) if err != nil { return ret, err } c.Cores = int32(t) case "flags": c.Flags = strings.Split(value, ",") } } return ret, nil }