|
14 | 14 | package procfs |
15 | 15 |
|
16 | 16 | import ( |
| 17 | + "bufio" |
| 18 | + "bytes" |
17 | 19 | "fmt" |
18 | | - "io/ioutil" |
| 20 | + "io" |
19 | 21 | "strconv" |
20 | 22 | "strings" |
| 23 | + |
| 24 | + "github.com/prometheus/procfs/internal/util" |
21 | 25 | ) |
22 | 26 |
|
23 | 27 | // For the proc file format details, |
24 | 28 | // see https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162 |
25 | 29 | // and https://elixir.bootlin.com/linux/v4.17/source/include/linux/netdevice.h#L2810. |
26 | 30 |
|
27 | | -// SoftnetEntry contains a single row of data from /proc/net/softnet_stat |
28 | | -type SoftnetEntry struct { |
| 31 | +// SoftnetStat contains a single row of data from /proc/net/softnet_stat |
| 32 | +type SoftnetStat struct { |
29 | 33 | // Number of processed packets |
30 | | - Processed uint |
| 34 | + Processed uint32 |
31 | 35 | // Number of dropped packets |
32 | | - Dropped uint |
| 36 | + Dropped uint32 |
33 | 37 | // Number of times processing packets ran out of quota |
34 | | - TimeSqueezed uint |
| 38 | + TimeSqueezed uint32 |
35 | 39 | } |
36 | 40 |
|
37 | | -// GatherSoftnetStats reads /proc/net/softnet_stat, parse the relevant columns, |
38 | | -// and then return a slice of SoftnetEntry's. |
39 | | -func (fs FS) GatherSoftnetStats() ([]SoftnetEntry, error) { |
40 | | - data, err := ioutil.ReadFile(fs.proc.Path("net/softnet_stat")) |
| 41 | +// NetSoftnetStat reads data from /proc/net/softnet_stat. |
| 42 | +func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) { |
| 43 | + b, err := util.ReadFileNoStat(fs.proc.Path("net/softnet_stat")) |
41 | 44 | if err != nil { |
42 | | - return nil, fmt.Errorf("error reading softnet %s: %s", fs.proc.Path("net/softnet_stat"), err) |
| 45 | + return nil, err |
43 | 46 | } |
44 | 47 |
|
45 | | - return parseSoftnetEntries(data) |
| 48 | + entries, err := parseSoftnet(bytes.NewReader(b)) |
| 49 | + if err != nil { |
| 50 | + return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %v", err) |
| 51 | + } |
| 52 | + |
| 53 | + return entries, nil |
46 | 54 | } |
47 | 55 |
|
48 | | -func parseSoftnetEntries(data []byte) ([]SoftnetEntry, error) { |
49 | | - lines := strings.Split(string(data), "\n") |
50 | | - entries := make([]SoftnetEntry, 0) |
51 | | - var err error |
52 | | - const ( |
53 | | - expectedColumns = 11 |
54 | | - ) |
55 | | - for _, line := range lines { |
56 | | - columns := strings.Fields(line) |
| 56 | +func parseSoftnet(r io.Reader) ([]SoftnetStat, error) { |
| 57 | + const expectedColumns = 11 |
| 58 | + |
| 59 | + s := bufio.NewScanner(r) |
| 60 | + |
| 61 | + var stats []SoftnetStat |
| 62 | + for s.Scan() { |
| 63 | + columns := strings.Fields(s.Text()) |
57 | 64 | width := len(columns) |
58 | | - if width == 0 { |
59 | | - continue |
60 | | - } |
61 | | - if width != expectedColumns { |
62 | | - return []SoftnetEntry{}, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedColumns) |
| 65 | + |
| 66 | + if width != 11 { |
| 67 | + return nil, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedColumns) |
63 | 68 | } |
64 | | - var entry SoftnetEntry |
65 | | - if entry, err = parseSoftnetEntry(columns); err != nil { |
66 | | - return []SoftnetEntry{}, err |
| 69 | + |
| 70 | + // We only parse the first three columns at the moment. |
| 71 | + us, err := parseHexUint32s(columns[0:3]) |
| 72 | + if err != nil { |
| 73 | + return nil, err |
67 | 74 | } |
68 | | - entries = append(entries, entry) |
| 75 | + |
| 76 | + stats = append(stats, SoftnetStat{ |
| 77 | + Processed: us[0], |
| 78 | + Dropped: us[1], |
| 79 | + TimeSqueezed: us[2], |
| 80 | + }) |
69 | 81 | } |
70 | 82 |
|
71 | | - return entries, nil |
| 83 | + return stats, nil |
72 | 84 | } |
73 | 85 |
|
74 | | -func parseSoftnetEntry(columns []string) (SoftnetEntry, error) { |
75 | | - var err error |
76 | | - var processed, dropped, timeSqueezed uint64 |
77 | | - if processed, err = strconv.ParseUint(columns[0], 16, 32); err != nil { |
78 | | - return SoftnetEntry{}, fmt.Errorf("Unable to parse column 0: %s", err) |
79 | | - } |
80 | | - if dropped, err = strconv.ParseUint(columns[1], 16, 32); err != nil { |
81 | | - return SoftnetEntry{}, fmt.Errorf("Unable to parse column 1: %s", err) |
82 | | - } |
83 | | - if timeSqueezed, err = strconv.ParseUint(columns[2], 16, 32); err != nil { |
84 | | - return SoftnetEntry{}, fmt.Errorf("Unable to parse column 2: %s", err) |
| 86 | +func parseHexUint32s(ss []string) ([]uint32, error) { |
| 87 | + us := make([]uint32, 0, len(ss)) |
| 88 | + for _, s := range ss { |
| 89 | + u, err := strconv.ParseUint(s, 16, 32) |
| 90 | + if err != nil { |
| 91 | + return nil, err |
| 92 | + } |
| 93 | + |
| 94 | + us = append(us, uint32(u)) |
85 | 95 | } |
86 | | - return SoftnetEntry{ |
87 | | - Processed: uint(processed), |
88 | | - Dropped: uint(dropped), |
89 | | - TimeSqueezed: uint(timeSqueezed), |
90 | | - }, nil |
| 96 | + |
| 97 | + return us, nil |
91 | 98 | } |
0 commit comments