net_dev.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. package procfs
  2. import (
  3. "bufio"
  4. "errors"
  5. "os"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. )
  10. // NetDevLine is single line parsed from /proc/net/dev or /proc/[pid]/net/dev.
  11. type NetDevLine struct {
  12. Name string `json:"name"` // The name of the interface.
  13. RxBytes uint64 `json:"rx_bytes"` // Cumulative count of bytes received.
  14. RxPackets uint64 `json:"rx_packets"` // Cumulative count of packets received.
  15. RxErrors uint64 `json:"rx_errors"` // Cumulative count of receive errors encountered.
  16. RxDropped uint64 `json:"rx_dropped"` // Cumulative count of packets dropped while receiving.
  17. RxFIFO uint64 `json:"rx_fifo"` // Cumulative count of FIFO buffer errors.
  18. RxFrame uint64 `json:"rx_frame"` // Cumulative count of packet framing errors.
  19. RxCompressed uint64 `json:"rx_compressed"` // Cumulative count of compressed packets received by the device driver.
  20. RxMulticast uint64 `json:"rx_multicast"` // Cumulative count of multicast frames received by the device driver.
  21. TxBytes uint64 `json:"tx_bytes"` // Cumulative count of bytes transmitted.
  22. TxPackets uint64 `json:"tx_packets"` // Cumulative count of packets transmitted.
  23. TxErrors uint64 `json:"tx_errors"` // Cumulative count of transmit errors encountered.
  24. TxDropped uint64 `json:"tx_dropped"` // Cumulative count of packets dropped while transmitting.
  25. TxFIFO uint64 `json:"tx_fifo"` // Cumulative count of FIFO buffer errors.
  26. TxCollisions uint64 `json:"tx_collisions"` // Cumulative count of collisions detected on the interface.
  27. TxCarrier uint64 `json:"tx_carrier"` // Cumulative count of carrier losses detected by the device driver.
  28. TxCompressed uint64 `json:"tx_compressed"` // Cumulative count of compressed packets transmitted by the device driver.
  29. }
  30. // NetDev is parsed from /proc/net/dev or /proc/[pid]/net/dev. The map keys
  31. // are interface names.
  32. type NetDev map[string]NetDevLine
  33. // NewNetDev returns kernel/system statistics read from /proc/net/dev.
  34. func NewNetDev() (NetDev, error) {
  35. fs, err := NewFS(DefaultMountPoint)
  36. if err != nil {
  37. return nil, err
  38. }
  39. return fs.NewNetDev()
  40. }
  41. // NewNetDev returns kernel/system statistics read from /proc/net/dev.
  42. func (fs FS) NewNetDev() (NetDev, error) {
  43. return newNetDev(fs.Path("net/dev"))
  44. }
  45. // NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev.
  46. func (p Proc) NewNetDev() (NetDev, error) {
  47. return newNetDev(p.path("net/dev"))
  48. }
  49. // newNetDev creates a new NetDev from the contents of the given file.
  50. func newNetDev(file string) (NetDev, error) {
  51. f, err := os.Open(file)
  52. if err != nil {
  53. return NetDev{}, err
  54. }
  55. defer f.Close()
  56. nd := NetDev{}
  57. s := bufio.NewScanner(f)
  58. for n := 0; s.Scan(); n++ {
  59. // Skip the 2 header lines.
  60. if n < 2 {
  61. continue
  62. }
  63. line, err := nd.parseLine(s.Text())
  64. if err != nil {
  65. return nd, err
  66. }
  67. nd[line.Name] = *line
  68. }
  69. return nd, s.Err()
  70. }
  71. // parseLine parses a single line from the /proc/net/dev file. Header lines
  72. // must be filtered prior to calling this method.
  73. func (nd NetDev) parseLine(rawLine string) (*NetDevLine, error) {
  74. parts := strings.SplitN(rawLine, ":", 2)
  75. if len(parts) != 2 {
  76. return nil, errors.New("invalid net/dev line, missing colon")
  77. }
  78. fields := strings.Fields(strings.TrimSpace(parts[1]))
  79. var err error
  80. line := &NetDevLine{}
  81. // Interface Name
  82. line.Name = strings.TrimSpace(parts[0])
  83. if line.Name == "" {
  84. return nil, errors.New("invalid net/dev line, empty interface name")
  85. }
  86. // RX
  87. line.RxBytes, err = strconv.ParseUint(fields[0], 10, 64)
  88. if err != nil {
  89. return nil, err
  90. }
  91. line.RxPackets, err = strconv.ParseUint(fields[1], 10, 64)
  92. if err != nil {
  93. return nil, err
  94. }
  95. line.RxErrors, err = strconv.ParseUint(fields[2], 10, 64)
  96. if err != nil {
  97. return nil, err
  98. }
  99. line.RxDropped, err = strconv.ParseUint(fields[3], 10, 64)
  100. if err != nil {
  101. return nil, err
  102. }
  103. line.RxFIFO, err = strconv.ParseUint(fields[4], 10, 64)
  104. if err != nil {
  105. return nil, err
  106. }
  107. line.RxFrame, err = strconv.ParseUint(fields[5], 10, 64)
  108. if err != nil {
  109. return nil, err
  110. }
  111. line.RxCompressed, err = strconv.ParseUint(fields[6], 10, 64)
  112. if err != nil {
  113. return nil, err
  114. }
  115. line.RxMulticast, err = strconv.ParseUint(fields[7], 10, 64)
  116. if err != nil {
  117. return nil, err
  118. }
  119. // TX
  120. line.TxBytes, err = strconv.ParseUint(fields[8], 10, 64)
  121. if err != nil {
  122. return nil, err
  123. }
  124. line.TxPackets, err = strconv.ParseUint(fields[9], 10, 64)
  125. if err != nil {
  126. return nil, err
  127. }
  128. line.TxErrors, err = strconv.ParseUint(fields[10], 10, 64)
  129. if err != nil {
  130. return nil, err
  131. }
  132. line.TxDropped, err = strconv.ParseUint(fields[11], 10, 64)
  133. if err != nil {
  134. return nil, err
  135. }
  136. line.TxFIFO, err = strconv.ParseUint(fields[12], 10, 64)
  137. if err != nil {
  138. return nil, err
  139. }
  140. line.TxCollisions, err = strconv.ParseUint(fields[13], 10, 64)
  141. if err != nil {
  142. return nil, err
  143. }
  144. line.TxCarrier, err = strconv.ParseUint(fields[14], 10, 64)
  145. if err != nil {
  146. return nil, err
  147. }
  148. line.TxCompressed, err = strconv.ParseUint(fields[15], 10, 64)
  149. if err != nil {
  150. return nil, err
  151. }
  152. return line, nil
  153. }
  154. // Total aggregates the values across interfaces and returns a new NetDevLine.
  155. // The Name field will be a sorted comma seperated list of interface names.
  156. func (nd NetDev) Total() NetDevLine {
  157. total := NetDevLine{}
  158. names := make([]string, 0, len(nd))
  159. for _, ifc := range nd {
  160. names = append(names, ifc.Name)
  161. total.RxBytes += ifc.RxBytes
  162. total.RxPackets += ifc.RxPackets
  163. total.RxPackets += ifc.RxPackets
  164. total.RxErrors += ifc.RxErrors
  165. total.RxDropped += ifc.RxDropped
  166. total.RxFIFO += ifc.RxFIFO
  167. total.RxFrame += ifc.RxFrame
  168. total.RxCompressed += ifc.RxCompressed
  169. total.RxMulticast += ifc.RxMulticast
  170. total.TxBytes += ifc.TxBytes
  171. total.TxPackets += ifc.TxPackets
  172. total.TxErrors += ifc.TxErrors
  173. total.TxDropped += ifc.TxDropped
  174. total.TxFIFO += ifc.TxFIFO
  175. total.TxCollisions += ifc.TxCollisions
  176. total.TxCarrier += ifc.TxCarrier
  177. total.TxCompressed += ifc.TxCompressed
  178. }
  179. sort.Strings(names)
  180. total.Name = strings.Join(names, ", ")
  181. return total
  182. }