func parseStatLine()

in metric/system/cgroup/cgv2/io.go [110:170]


func parseStatLine(line string, resolveDevIDs bool) ([]string, IOStat, bool, error) {
	devIds := []string{}
	stats := IOStat{}
	foundMetrics := false
	// cautiously iterate over a line to find the components
	// under certain conditions, the stat.io will combine different loopback devices onto a single line,
	// 7:7 7:6 7:5 7:4 rbytes=556032 wbytes=0 rios=78 wios=0 dbytes=0 dios=0
	// we can also get lines without metrics, like
	//  7:7 7:6 7:5 7:4
	for _, component := range strings.Split(line, " ") {
		if strings.Contains(component, ":") {
			var major, minor uint64
			_, err := fmt.Sscanf(component, "%d:%d", &major, &minor)
			if err != nil {
				return nil, IOStat{}, false, fmt.Errorf("could not read device ID: %s: %w", component, err)
			}

			var found bool
			var devName string
			// try to find the device name associated with the major/minor pair
			// This isn't guaranteed to work, for a number of reasons, so we'll need to fall back
			if resolveDevIDs {
				found, devName, _ = fetchDeviceName(major, minor)
			}

			if found {
				devIds = append(devIds, devName)
			} else {
				devIds = append(devIds, component)
			}
		} else if strings.Contains(component, "=") {
			foundMetrics = true
			counterSplit := strings.Split(component, "=")
			if len(counterSplit) < 2 {
				continue
			}
			name := counterSplit[0]
			counter, err := strconv.ParseUint(counterSplit[1], 10, 64)
			if err != nil {
				return nil, IOStat{}, false, fmt.Errorf("error parsing counter '%s' in stat: %w", counterSplit[1], err)
			}
			switch name {
			case "rbytes":
				stats.Read.Bytes = counter
			case "wbytes":
				stats.Write.Bytes = counter
			case "rios":
				stats.Read.IOs = counter
			case "wios":
				stats.Write.IOs = counter
			case "dbytes":
				stats.Discarded.Bytes = counter
			case "dios":
				stats.Discarded.IOs = counter
			}

		}

	}
	return devIds, stats, foundMetrics, nil
}