blob: 3f2523371ab102f22947899d31fedc58f725666f [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// 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
14package procfs
15
16import (
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.
26type 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.
48type NetDev map[string]NetDevLine
49
50// NewNetDev returns kernel/system statistics read from /proc/net/dev.
51func 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.
61func (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.
66func (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.
71func 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.
99func (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.
188func (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}