Improve perf of interface stats parsing

This commit is contained in:
Jimmi Dyson 2015-11-26 10:45:10 +00:00
parent fe7e8563b7
commit 360c73c6fd

View File

@ -149,38 +149,70 @@ func isIgnoredDevice(ifName string) bool {
const netstatsLine = `%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d` const netstatsLine = `%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d`
func scanInterfaceStats(netStatsFile string) ([]info.InterfaceStats, error) { func scanInterfaceStats(netStatsFile string) ([]info.InterfaceStats, error) {
var (
bkt uint64
)
stats := []info.InterfaceStats{}
file, err := os.Open(netStatsFile) file, err := os.Open(netStatsFile)
if err != nil { if err != nil {
return stats, fmt.Errorf("failure opening %s: %v", netStatsFile, err) return nil, fmt.Errorf("failure opening %s: %v", netStatsFile, err)
} }
defer file.Close() defer file.Close()
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
// Discard header lines
for i := 0; i < 2; i++ {
if b := scanner.Scan(); !b {
return nil, scanner.Err()
}
}
stats := []info.InterfaceStats{}
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
line = strings.Replace(line, ":", "", -1) line = strings.Replace(line, ":", "", -1)
i := info.InterfaceStats{} fields := strings.Fields(line)
// If the format of the line is invalid then don't trust any of the stats
_, err := fmt.Sscanf(line, netstatsLine, // in this file.
&i.Name, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt, if len(fields) != 17 {
&bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt) return nil, fmt.Errorf("invalid interface stats line: %v", line)
if err == nil && !isIgnoredDevice(i.Name) {
stats = append(stats, i)
} }
devName := fields[0]
if isIgnoredDevice(devName) {
continue
}
i := info.InterfaceStats{
Name: devName,
}
statFields := append(fields[1:5], fields[9:13]...)
statPointers := []*uint64{
&i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped,
&i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped,
}
err := setInterfaceStatValues(statFields, statPointers)
if err != nil {
return nil, fmt.Errorf("cannot parse interface stats (%v): %v", err, line)
}
stats = append(stats, i)
} }
return stats, nil return stats, nil
} }
func setInterfaceStatValues(fields []string, pointers []*uint64) error {
for i, v := range fields {
val, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return err
}
*pointers[i] = val
}
return nil
}
func tcpStatsFromProc(rootFs string, pid int, file string) (info.TcpStat, error) { func tcpStatsFromProc(rootFs string, pid int, file string) (info.TcpStat, error) {
tcpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file) tcpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file)
@ -221,8 +253,7 @@ func scanTcpStats(tcpStatsFile string) (info.TcpStat, error) {
scanner.Split(bufio.ScanLines) scanner.Split(bufio.ScanLines)
// Discard header line // Discard header line
b := scanner.Scan() if b := scanner.Scan(); !b {
if !b {
return stats, scanner.Err() return stats, scanner.Err()
} }