| 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 | } |