// Collect reads cpu.stat for cgroups and per process cpu.stat // entries for all processes in the cgroup func (s *PerCgroupStat) Collect() { file, err := os.Open(s.path + "/" + "cpu.stat") defer file.Close() if err != nil { return } scanner := bufio.NewScanner(file) for scanner.Scan() { f := regexp.MustCompile("\\s+").Split(scanner.Text(), 2) if f[0] == "nr_periods" { s.NrPeriods.Set(misc.ParseUint(f[1])) } if f[0] == "nr_throttled" { s.NrThrottled.Set(misc.ParseUint(f[1])) } if f[0] == "throttled_time" { s.ThrottledTime.Set(misc.ParseUint(f[1])) } } s.CfsPeriodUs.Set( float64(misc.ReadUintFromFile( s.path + "/" + "cpu.cfs_period_us"))) // negative values of quota indicate no quota. // it is not possible for this variable to be zero s.CfsQuotaUs.Set( float64(misc.ReadUintFromFile( s.path + "/" + "cpu.cfs_quota_us"))) // Calculate approximate cumulative CPU usage for all // processes within this cgroup by calculating difference // between sum number of ticks. // We reset between loops because PIDs within cgroup can // change and sum-counter from previous run can be // unreliable s.getCgroupCPUTimes() time.Sleep(time.Millisecond * 1000) s.getCgroupCPUTimes() // Expose summary metrics for easy json access s.UsageCount.Set(s.usage()) s.UserspaceCount.Set(s.userspace()) s.KernelCount.Set(s.kernel()) s.TotalCount.Set(s.Quota()) s.ThrottleCount.Set(s.Throttle()) // Reset counters s.Utime.Reset() s.Stime.Reset() }
// Collect reads memory.stat and uses reflection to populate PerCgroupStat func (s *PerCgroupStat) Collect() { file, err := os.Open(s.path + "/" + "memory.stat") if err != nil { fmt.Println(err) return } d := map[string]*metrics.Gauge{} // Get all fields we care about r := reflect.ValueOf(s).Elem() typeOfT := r.Type() for i := 0; i < r.NumField(); i++ { f := r.Field(i) if f.Kind().String() == "ptr" && f.Type().Elem() == reflect.TypeOf(metrics.Gauge{}) { d[strings.ToLower(typeOfT.Field(i).Name)] = f.Interface().(*metrics.Gauge) } } scanner := bufio.NewScanner(file) for scanner.Scan() { f := regexp.MustCompile("[\\s]+").Split(scanner.Text(), 2) g, ok := d[strings.ToLower(f[0])] if ok { parseCgroupMemLine(g, f) } } s.Soft_Limit_In_Bytes.Set( float64(misc.ReadUintFromFile( s.path + "/" + "memory.soft_limit_in_bytes"))) s.UsageInBytes.Set(s.Usage()) }
// Collect reads /proc/net/dev to gather statistics for interfaces. // Collect reads /sysfs to figure out interface capabilities. // Collect is generally called directly when the package is initialized. func (s *InterfaceStat) Collect() { file, err := os.Open(root + "proc/net/dev") defer file.Close() if err != nil { return } var rx [8]uint64 var tx [8]uint64 scanner := bufio.NewScanner(file) scanner.Scan() for scanner.Scan() { f := strings.Split(scanner.Text(), ":") if len(f) < 2 { continue } dev := strings.TrimSpace(f[0]) rest := f[1] fmt.Sscanf(rest, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", &rx[0], &rx[1], &rx[2], &rx[3], &rx[4], &rx[5], &rx[6], &rx[7], &tx[0], &tx[1], &tx[2], &tx[3], &tx[4], &tx[5], &tx[6], &tx[7]) o, ok := s.Interfaces[dev] if !ok { o = NewPerInterfaceStat(s.m, dev) s.Interfaces[dev] = o } d := o.Metrics d.RXbytes.Set(rx[0]) d.RXpackets.Set(rx[1]) d.RXerrs.Set(rx[2]) d.RXdrop.Set(rx[3]) d.RXfifo.Set(rx[4]) d.RXframe.Set(rx[5]) d.RXcompressed.Set(rx[6]) d.RXmulticast.Set(rx[7]) d.TXbytes.Set(tx[0]) d.TXpackets.Set(tx[1]) d.TXerrs.Set(tx[2]) d.TXdrop.Set(tx[3]) d.TXfifo.Set(tx[4]) d.TXframe.Set(tx[5]) d.TXcompressed.Set(tx[6]) d.TXmulticast.Set(tx[7]) speed := misc.ReadUintFromFile(root + "sys/class/net/" + dev + "/speed") if speed > 0 { d.Speed.Set(float64(speed)) } } }
// Collect walks through /proc/diskstats and updates relevant metrics func (s *DiskStat) Collect() { file, err := os.Open(root + "proc/diskstats") defer file.Close() if err != nil { return } var blkdev string var major, minor uint64 var f [11]uint64 scanner := bufio.NewScanner(file) for scanner.Scan() { fmt.Sscanf(scanner.Text(), "%d %d %s %d %d %d %d %d %d %d %d %d %d %d", &major, &minor, &blkdev, &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9], &f[10]) // skip loop/ram/dm drives if major == 1 || major == 7 || major == 253 { continue } // skip collecting for individual partitions _, ok := s.blkdevs[blkdev] if !ok { continue } o, ok := s.Disks[blkdev] if !ok { o = NewPerDiskStat(s.m, blkdev) s.Disks[blkdev] = o } sectorSize := misc.ReadUintFromFile(root + "sys/block/" + blkdev + "/queue/hw_sector_size") o.ReadCompleted.Set(f[0]) o.ReadMerged.Set(f[1]) o.ReadSectors.Set(f[2]) o.ReadSpentMsecs.Set(f[3]) o.WriteCompleted.Set(f[4]) o.WriteMerged.Set(f[5]) o.WriteSectors.Set(f[6]) o.WriteSpentMsecs.Set(f[7]) o.IOInProgress.Set(float64(f[8])) o.IOSpentMsecs.Set(f[9]) o.WeightedIOSpentMsecs.Set(f[10]) o.SectorSize.Set(float64(sectorSize)) } }