Matthias Andreas Benkard | 832a54e | 2019-01-29 09:27:38 +0100 | [diff] [blame^] | 1 | // Copyright 2018 The Prometheus Authors |
| 2 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | // you may not use this file except in compliance with the License. |
| 4 | // You may obtain a copy of the License at |
| 5 | // |
| 6 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | // |
| 8 | // Unless required by applicable law or agreed to in writing, software |
| 9 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 11 | // See the License for the specific language governing permissions and |
| 12 | // limitations under the License. |
| 13 | |
| 14 | package procfs |
| 15 | |
| 16 | import ( |
| 17 | "bufio" |
| 18 | "errors" |
| 19 | "os" |
| 20 | "sort" |
| 21 | "strconv" |
| 22 | "strings" |
| 23 | ) |
| 24 | |
| 25 | // NetDevLine is single line parsed from /proc/net/dev or /proc/[pid]/net/dev. |
| 26 | type NetDevLine struct { |
| 27 | Name string `json:"name"` // The name of the interface. |
| 28 | RxBytes uint64 `json:"rx_bytes"` // Cumulative count of bytes received. |
| 29 | RxPackets uint64 `json:"rx_packets"` // Cumulative count of packets received. |
| 30 | RxErrors uint64 `json:"rx_errors"` // Cumulative count of receive errors encountered. |
| 31 | RxDropped uint64 `json:"rx_dropped"` // Cumulative count of packets dropped while receiving. |
| 32 | RxFIFO uint64 `json:"rx_fifo"` // Cumulative count of FIFO buffer errors. |
| 33 | RxFrame uint64 `json:"rx_frame"` // Cumulative count of packet framing errors. |
| 34 | RxCompressed uint64 `json:"rx_compressed"` // Cumulative count of compressed packets received by the device driver. |
| 35 | RxMulticast uint64 `json:"rx_multicast"` // Cumulative count of multicast frames received by the device driver. |
| 36 | TxBytes uint64 `json:"tx_bytes"` // Cumulative count of bytes transmitted. |
| 37 | TxPackets uint64 `json:"tx_packets"` // Cumulative count of packets transmitted. |
| 38 | TxErrors uint64 `json:"tx_errors"` // Cumulative count of transmit errors encountered. |
| 39 | TxDropped uint64 `json:"tx_dropped"` // Cumulative count of packets dropped while transmitting. |
| 40 | TxFIFO uint64 `json:"tx_fifo"` // Cumulative count of FIFO buffer errors. |
| 41 | TxCollisions uint64 `json:"tx_collisions"` // Cumulative count of collisions detected on the interface. |
| 42 | TxCarrier uint64 `json:"tx_carrier"` // Cumulative count of carrier losses detected by the device driver. |
| 43 | TxCompressed uint64 `json:"tx_compressed"` // Cumulative count of compressed packets transmitted by the device driver. |
| 44 | } |
| 45 | |
| 46 | // NetDev is parsed from /proc/net/dev or /proc/[pid]/net/dev. The map keys |
| 47 | // are interface names. |
| 48 | type NetDev map[string]NetDevLine |
| 49 | |
| 50 | // NewNetDev returns kernel/system statistics read from /proc/net/dev. |
| 51 | func NewNetDev() (NetDev, error) { |
| 52 | fs, err := NewFS(DefaultMountPoint) |
| 53 | if err != nil { |
| 54 | return nil, err |
| 55 | } |
| 56 | |
| 57 | return fs.NewNetDev() |
| 58 | } |
| 59 | |
| 60 | // NewNetDev returns kernel/system statistics read from /proc/net/dev. |
| 61 | func (fs FS) NewNetDev() (NetDev, error) { |
| 62 | return newNetDev(fs.Path("net/dev")) |
| 63 | } |
| 64 | |
| 65 | // NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev. |
| 66 | func (p Proc) NewNetDev() (NetDev, error) { |
| 67 | return newNetDev(p.path("net/dev")) |
| 68 | } |
| 69 | |
| 70 | // newNetDev creates a new NetDev from the contents of the given file. |
| 71 | func newNetDev(file string) (NetDev, error) { |
| 72 | f, err := os.Open(file) |
| 73 | if err != nil { |
| 74 | return NetDev{}, err |
| 75 | } |
| 76 | defer f.Close() |
| 77 | |
| 78 | nd := NetDev{} |
| 79 | s := bufio.NewScanner(f) |
| 80 | for n := 0; s.Scan(); n++ { |
| 81 | // Skip the 2 header lines. |
| 82 | if n < 2 { |
| 83 | continue |
| 84 | } |
| 85 | |
| 86 | line, err := nd.parseLine(s.Text()) |
| 87 | if err != nil { |
| 88 | return nd, err |
| 89 | } |
| 90 | |
| 91 | nd[line.Name] = *line |
| 92 | } |
| 93 | |
| 94 | return nd, s.Err() |
| 95 | } |
| 96 | |
| 97 | // parseLine parses a single line from the /proc/net/dev file. Header lines |
| 98 | // must be filtered prior to calling this method. |
| 99 | func (nd NetDev) parseLine(rawLine string) (*NetDevLine, error) { |
| 100 | parts := strings.SplitN(rawLine, ":", 2) |
| 101 | if len(parts) != 2 { |
| 102 | return nil, errors.New("invalid net/dev line, missing colon") |
| 103 | } |
| 104 | fields := strings.Fields(strings.TrimSpace(parts[1])) |
| 105 | |
| 106 | var err error |
| 107 | line := &NetDevLine{} |
| 108 | |
| 109 | // Interface Name |
| 110 | line.Name = strings.TrimSpace(parts[0]) |
| 111 | if line.Name == "" { |
| 112 | return nil, errors.New("invalid net/dev line, empty interface name") |
| 113 | } |
| 114 | |
| 115 | // RX |
| 116 | line.RxBytes, err = strconv.ParseUint(fields[0], 10, 64) |
| 117 | if err != nil { |
| 118 | return nil, err |
| 119 | } |
| 120 | line.RxPackets, err = strconv.ParseUint(fields[1], 10, 64) |
| 121 | if err != nil { |
| 122 | return nil, err |
| 123 | } |
| 124 | line.RxErrors, err = strconv.ParseUint(fields[2], 10, 64) |
| 125 | if err != nil { |
| 126 | return nil, err |
| 127 | } |
| 128 | line.RxDropped, err = strconv.ParseUint(fields[3], 10, 64) |
| 129 | if err != nil { |
| 130 | return nil, err |
| 131 | } |
| 132 | line.RxFIFO, err = strconv.ParseUint(fields[4], 10, 64) |
| 133 | if err != nil { |
| 134 | return nil, err |
| 135 | } |
| 136 | line.RxFrame, err = strconv.ParseUint(fields[5], 10, 64) |
| 137 | if err != nil { |
| 138 | return nil, err |
| 139 | } |
| 140 | line.RxCompressed, err = strconv.ParseUint(fields[6], 10, 64) |
| 141 | if err != nil { |
| 142 | return nil, err |
| 143 | } |
| 144 | line.RxMulticast, err = strconv.ParseUint(fields[7], 10, 64) |
| 145 | if err != nil { |
| 146 | return nil, err |
| 147 | } |
| 148 | |
| 149 | // TX |
| 150 | line.TxBytes, err = strconv.ParseUint(fields[8], 10, 64) |
| 151 | if err != nil { |
| 152 | return nil, err |
| 153 | } |
| 154 | line.TxPackets, err = strconv.ParseUint(fields[9], 10, 64) |
| 155 | if err != nil { |
| 156 | return nil, err |
| 157 | } |
| 158 | line.TxErrors, err = strconv.ParseUint(fields[10], 10, 64) |
| 159 | if err != nil { |
| 160 | return nil, err |
| 161 | } |
| 162 | line.TxDropped, err = strconv.ParseUint(fields[11], 10, 64) |
| 163 | if err != nil { |
| 164 | return nil, err |
| 165 | } |
| 166 | line.TxFIFO, err = strconv.ParseUint(fields[12], 10, 64) |
| 167 | if err != nil { |
| 168 | return nil, err |
| 169 | } |
| 170 | line.TxCollisions, err = strconv.ParseUint(fields[13], 10, 64) |
| 171 | if err != nil { |
| 172 | return nil, err |
| 173 | } |
| 174 | line.TxCarrier, err = strconv.ParseUint(fields[14], 10, 64) |
| 175 | if err != nil { |
| 176 | return nil, err |
| 177 | } |
| 178 | line.TxCompressed, err = strconv.ParseUint(fields[15], 10, 64) |
| 179 | if err != nil { |
| 180 | return nil, err |
| 181 | } |
| 182 | |
| 183 | return line, nil |
| 184 | } |
| 185 | |
| 186 | // Total aggregates the values across interfaces and returns a new NetDevLine. |
| 187 | // The Name field will be a sorted comma separated list of interface names. |
| 188 | func (nd NetDev) Total() NetDevLine { |
| 189 | total := NetDevLine{} |
| 190 | |
| 191 | names := make([]string, 0, len(nd)) |
| 192 | for _, ifc := range nd { |
| 193 | names = append(names, ifc.Name) |
| 194 | total.RxBytes += ifc.RxBytes |
| 195 | total.RxPackets += ifc.RxPackets |
| 196 | total.RxPackets += ifc.RxPackets |
| 197 | total.RxErrors += ifc.RxErrors |
| 198 | total.RxDropped += ifc.RxDropped |
| 199 | total.RxFIFO += ifc.RxFIFO |
| 200 | total.RxFrame += ifc.RxFrame |
| 201 | total.RxCompressed += ifc.RxCompressed |
| 202 | total.RxMulticast += ifc.RxMulticast |
| 203 | total.TxBytes += ifc.TxBytes |
| 204 | total.TxPackets += ifc.TxPackets |
| 205 | total.TxErrors += ifc.TxErrors |
| 206 | total.TxDropped += ifc.TxDropped |
| 207 | total.TxFIFO += ifc.TxFIFO |
| 208 | total.TxCollisions += ifc.TxCollisions |
| 209 | total.TxCarrier += ifc.TxCarrier |
| 210 | total.TxCompressed += ifc.TxCompressed |
| 211 | } |
| 212 | sort.Strings(names) |
| 213 | total.Name = strings.Join(names, ", ") |
| 214 | |
| 215 | return total |
| 216 | } |