From 2f78568fdbfd601a592b750d40cefe35708663ea Mon Sep 17 00:00:00 2001 From: Alex Kristiansen Date: Fri, 10 Jan 2020 12:27:22 -0800 Subject: [PATCH 1/2] Move to uint64, deal with MaxConn --- providers/linux/procnet.go | 32 ++++++++++++++++++++++++-------- providers/linux/procnet_test.go | 3 ++- types/host.go | 17 +++++++++-------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/providers/linux/procnet.go b/providers/linux/procnet.go index 685d7804..a2cc2867 100644 --- a/providers/linux/procnet.go +++ b/providers/linux/procnet.go @@ -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() @@ -44,7 +44,7 @@ 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), " ") @@ -52,20 +52,36 @@ func parseEntry(line1, line2 string) (map[string]int64, error) { 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 { diff --git a/providers/linux/procnet_test.go b/providers/linux/procnet_test.go index d09a1890..4773a3b2 100644 --- a/providers/linux/procnet_test.go +++ b/providers/linux/procnet_test.go @@ -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"]) } diff --git a/types/host.go b/types/host.go index 80db2c8a..b7472fe6 100644 --- a/types/host.go +++ b/types/host.go @@ -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 From 5851d54c836b0b27d6d91bfd0e7b6c0974a18fb5 Mon Sep 17 00:00:00 2001 From: Alex Kristiansen Date: Fri, 10 Jan 2020 16:08:58 -0800 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e989960..ddf12898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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