diff --git a/CHANGELOG.md b/CHANGELOG.md index 08a9bf4d..9237e249 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ * [CHANGE] Split cpufreq metrics into a separate collector #1253 * [ENHANCEMENT] Add Infiniband counters #1120 * [ENHANCEMENT] Move network_up labels into new metric network_info #1236 +* [ENHANCEMENT] Use 64-bit counters for Darwin netstat * [FEATURE] Add a flag to disable exporter metrics #1148 * [FEATURE] Add kstat-based Solaris metrics for boottime, cpu and zfs collectors #1197 * [FEATURE] Add uname collector for FreeBSD #1239 diff --git a/collector/netdev_darwin.go b/collector/netdev_darwin.go index 9e7a14b5..b02ed401 100644 --- a/collector/netdev_darwin.go +++ b/collector/netdev_darwin.go @@ -16,52 +16,101 @@ package collector import ( + "bytes" + "encoding/binary" "errors" + "net" "regexp" "strconv" "github.com/prometheus/common/log" + "golang.org/x/sys/unix" ) -/* -#include -#include -#include -#include -#include -*/ -import "C" - func getNetDevStats(ignore *regexp.Regexp) (map[string]map[string]string, error) { netDev := map[string]map[string]string{} - var ifap, ifa *C.struct_ifaddrs - if C.getifaddrs(&ifap) == -1 { - return nil, errors.New("getifaddrs() failed") + ifs, err := net.Interfaces() + if err != nil { + return nil, errors.New("net.Interfaces() failed") } - defer C.freeifaddrs(ifap) - for ifa = ifap; ifa != nil; ifa = ifa.ifa_next { - if ifa.ifa_addr.sa_family == C.AF_LINK { - dev := C.GoString(ifa.ifa_name) - if ignore.MatchString(dev) { - log.Debugf("Ignoring device: %s", dev) - continue - } - - devStats := map[string]string{} - data := (*C.struct_if_data)(ifa.ifa_data) - devStats["receive_packets"] = strconv.FormatUint(uint64(data.ifi_ipackets), 10) - devStats["transmit_packets"] = strconv.FormatUint(uint64(data.ifi_opackets), 10) - devStats["receive_errs"] = strconv.FormatUint(uint64(data.ifi_ierrors), 10) - devStats["transmit_errs"] = strconv.FormatUint(uint64(data.ifi_oerrors), 10) - devStats["receive_bytes"] = strconv.FormatUint(uint64(data.ifi_ibytes), 10) - devStats["transmit_bytes"] = strconv.FormatUint(uint64(data.ifi_obytes), 10) - devStats["receive_multicast"] = strconv.FormatUint(uint64(data.ifi_imcasts), 10) - devStats["transmit_multicast"] = strconv.FormatUint(uint64(data.ifi_omcasts), 10) - netDev[dev] = devStats + for _, iface := range ifs { + ifaceData, err := getIfaceData(iface.Index) + if err != nil { + log.Debugf("failed to load data for interface %q: %v", iface.Name, err) + continue } + + if ignore.MatchString(iface.Name) { + log.Debugf("Ignoring device: %s", iface.Name) + continue + } + + devStats := map[string]string{} + devStats["receive_packets"] = strconv.FormatUint(ifaceData.Data.Ipackets, 10) + devStats["transmit_packets"] = strconv.FormatUint(ifaceData.Data.Opackets, 10) + devStats["receive_errs"] = strconv.FormatUint(ifaceData.Data.Ierrors, 10) + devStats["transmit_errs"] = strconv.FormatUint(ifaceData.Data.Oerrors, 10) + devStats["receive_bytes"] = strconv.FormatUint(ifaceData.Data.Ibytes, 10) + devStats["transmit_bytes"] = strconv.FormatUint(ifaceData.Data.Obytes, 10) + devStats["receive_multicast"] = strconv.FormatUint(ifaceData.Data.Imcasts, 10) + devStats["transmit_multicast"] = strconv.FormatUint(ifaceData.Data.Omcasts, 10) + netDev[iface.Name] = devStats } return netDev, nil } + +func getIfaceData(index int) (*ifMsghdr2, error) { + var data ifMsghdr2 + rawData, err := unix.SysctlRaw("net", unix.AF_ROUTE, 0, 0, unix.NET_RT_IFLIST2, index) + if err != nil { + return nil, err + } + err = binary.Read(bytes.NewReader(rawData), binary.LittleEndian, &data) + return &data, err +} + +type ifMsghdr2 struct { + Msglen uint16 + Version uint8 + Type uint8 + Addrs int32 + Flags int32 + Index uint16 + _ [2]byte + SndLen int32 + SndMaxlen int32 + SndDrops int32 + Timer int32 + Data ifData64 +} + +type ifData64 struct { + Type uint8 + Typelen uint8 + Physical uint8 + Addrlen uint8 + Hdrlen uint8 + Recvquota uint8 + Xmitquota uint8 + Unused1 uint8 + Mtu uint32 + Metric uint32 + Baudrate uint64 + Ipackets uint64 + Ierrors uint64 + Opackets uint64 + Oerrors uint64 + Collisions uint64 + Ibytes uint64 + Obytes uint64 + Imcasts uint64 + Omcasts uint64 + Iqdrops uint64 + Noproto uint64 + Recvtiming uint32 + Xmittiming uint32 + Lastchange unix.Timeval32 +}