Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move to uint64 for procnet, deal with MaxConn #75

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

### Changed
- Convert NetworkCountersInfo maps to uint64 [#75](https://github.com/elastic/go-sysinfo/pull/75)

### Deprecated

Expand Down
32 changes: 24 additions & 8 deletions providers/linux/procnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
)

// fillStruct is some reflection work that can dynamically fill one of our tagged `netstat` structs with netstat data
func fillStruct(str interface{}, data map[string]map[string]int64) {
func fillStruct(str interface{}, data map[string]map[string]uint64) {
val := reflect.ValueOf(str).Elem()
typ := reflect.TypeOf(str).Elem()

Expand All @@ -44,28 +44,44 @@ func fillStruct(str interface{}, data map[string]map[string]int64) {
}

// parseEntry parses two lines from the net files, the first line being keys, the second being values
func parseEntry(line1, line2 string) (map[string]int64, error) {
func parseEntry(line1, line2 string) (map[string]uint64, error) {
keyArr := strings.Split(strings.TrimSpace(line1), " ")
valueArr := strings.Split(strings.TrimSpace(line2), " ")

if len(keyArr) != len(valueArr) {
return nil, errors.New("key and value lines are mismatched")
}

counters := make(map[string]int64, len(valueArr))
counters := make(map[string]uint64, len(valueArr))
for iter, value := range valueArr {
parsed, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "error parsing string to int in line: %#v", valueArr)

// This if-else block is to deal with the MaxConn value in SNMP,
// which is a signed value according to RFC2012.
// This library emulates the behavior of the kernel: store all values as a uint, then cast to a signed value for printing
// Users of this library need to be aware that this value should be printed as a signed int or hex value to make it useful.
var parsed uint64
var err error
if strings.Contains(value, "-") {
signedParsed, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "error parsing string to int in line: %#v", valueArr)
}
parsed = uint64(signedParsed)
} else {
parsed, err = strconv.ParseUint(value, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "error parsing string to int in line: %#v", valueArr)
}
}

counters[keyArr[iter]] = parsed
}
return counters, nil
}

// parseNetFile parses an entire file, and returns a 2D map, representing how files are sorted by protocol
func parseNetFile(body string) (map[string]map[string]int64, error) {
fileMetrics := make(map[string]map[string]int64)
func parseNetFile(body string) (map[string]map[string]uint64, error) {
fileMetrics := make(map[string]map[string]uint64)
bodySplit := strings.Split(strings.TrimSpace(body), "\n")
// There should be an even number of lines. If not, something is wrong.
if len(bodySplit)%2 != 0 {
Expand Down
3 changes: 2 additions & 1 deletion providers/linux/procnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ UdpLite: 0 0 0 0 0 0 0 0`
fillStruct(&testOut, mapStr)

assert.NotEmpty(t, testOut.IP)
assert.Equal(t, int64(16755), testOut.UDP["InDatagrams"])
assert.Equal(t, uint64(16755), testOut.UDP["InDatagrams"])
assert.Equal(t, uint64(0xffffffffffffffff), testOut.TCP["MaxConn"])
}
17 changes: 9 additions & 8 deletions types/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@ type NetworkCounters interface {
}

// SNMP represents the data from /proc/net/snmp
// Note that according to RFC 2012,TCP.MaxConn, if present, is a signed value and should be cast to int64
type SNMP struct {
IP map[string]int64 `json:"ip" netstat:"Ip"`
ICMP map[string]int64 `json:"icmp" netstat:"Icmp"`
ICMPMsg map[string]int64 `json:"icmp_msg" netstat:"IcmpMsg"`
TCP map[string]int64 `json:"tcp" netstat:"Tcp"`
UDP map[string]int64 `json:"udp" netstat:"Udp"`
UDPLite map[string]int64 `json:"udp_lite" netstat:"UdpLite"`
IP map[string]uint64 `json:"ip" netstat:"Ip"`
ICMP map[string]uint64 `json:"icmp" netstat:"Icmp"`
ICMPMsg map[string]uint64 `json:"icmp_msg" netstat:"IcmpMsg"`
TCP map[string]uint64 `json:"tcp" netstat:"Tcp"`
UDP map[string]uint64 `json:"udp" netstat:"Udp"`
UDPLite map[string]uint64 `json:"udp_lite" netstat:"UdpLite"`
}

// Netstat represents the data from /proc/net/netstat
type Netstat struct {
TCPExt map[string]int64 `json:"tcp_ext" netstat:"TcpExt"`
IPExt map[string]int64 `json:"ip_ext" netstat:"IpExt"`
TCPExt map[string]uint64 `json:"tcp_ext" netstat:"TcpExt"`
IPExt map[string]uint64 `json:"ip_ext" netstat:"IpExt"`
}

// NetworkCountersInfo represents available network counters from /proc/net
Expand Down