diff --git a/collector/bonding.go b/collector/bonding_linux.go similarity index 100% rename from collector/bonding.go rename to collector/bonding_linux.go diff --git a/collector/bonding_test.go b/collector/bonding_linux_test.go similarity index 100% rename from collector/bonding_test.go rename to collector/bonding_linux_test.go diff --git a/collector/cpu_freebsd.go b/collector/cpu_freebsd.go new file mode 100644 index 00000000..632f0959 --- /dev/null +++ b/collector/cpu_freebsd.go @@ -0,0 +1,72 @@ +// +build !nocpu + +package collector + +import ( + "errors" + "os" + "strconv" + "unsafe" + + "github.com/prometheus/client_golang/prometheus" +) + +/* +#cgo LDFLAGS: -lkvm +#include +#include +#include +#include +#include +*/ +import "C" + +type statCollector struct { + cpu *prometheus.CounterVec +} + +func init() { + Factories["cpu"] = NewStatCollector +} + +// Takes a prometheus registry and returns a new Collector exposing +// CPU stats. +func NewStatCollector() (Collector, error) { + return &statCollector{ + cpu: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Name: "cpu_seconds_total", + Help: "Seconds the CPU spent in each mode.", + }, + []string{"cpu", "mode"}, + ), + }, nil +} + +// Expose CPU stats using KVM. +func (c *statCollector) Update(ch chan<- prometheus.Metric) (err error) { + if os.Geteuid() != 0 && os.Getegid() != 2 { + return errors.New("caller should be either root user or kmem group to access /dev/mem") + } + + var errbuf *C.char + kd := C.kvm_open(nil, nil, nil, C.O_RDONLY, errbuf) + if errbuf != nil { + return errors.New("failed to call kvm_open()") + } + defer C.kvm_close(kd) + + ncpus := C.kvm_getncpus(kd) + for i := 0; i < int(ncpus); i++ { + pcpu := C.kvm_getpcpu(kd, C.int(i)) + cp_time := ((*C.struct_pcpu)(unsafe.Pointer(pcpu))).pc_cp_time + c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "user"}).Set(float64(cp_time[C.CP_USER])) + c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "nice"}).Set(float64(cp_time[C.CP_NICE])) + c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "system"}).Set(float64(cp_time[C.CP_SYS])) + c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "interrupt"}).Set(float64(cp_time[C.CP_INTR])) + c.cpu.With(prometheus.Labels{"cpu": strconv.Itoa(i), "mode": "idle"}).Set(float64(cp_time[C.CP_IDLE])) + } + c.cpu.Collect(ch) + return err +} diff --git a/collector/devstat_freebsd.go b/collector/devstat_freebsd.go new file mode 100644 index 00000000..2b9300c0 --- /dev/null +++ b/collector/devstat_freebsd.go @@ -0,0 +1,226 @@ +// +build !nodevstat + +package collector + +import ( + "errors" + "fmt" + + "github.com/prometheus/client_golang/prometheus" +) + +/* +#cgo LDFLAGS: -ldevstat -lkvm +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + uint64_t read; + uint64_t write; + uint64_t free; +} Bytes; + +typedef struct { + uint64_t other; + uint64_t read; + uint64_t write; + uint64_t free; +} Transfers; + +typedef struct { + double other; + double read; + double write; + double free; +} Duration; + +typedef struct { + char device[DEVSTAT_NAME_LEN]; + int unit; + Bytes bytes; + Transfers transfers; + Duration duration; + long busyTime; + uint64_t blocks; +} Stats; + +int _get_ndevs() { + struct statinfo current; + int num_devices; + + current.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); + if (current.dinfo == NULL) + return -2; + + devstat_checkversion(NULL); + + if (devstat_getdevs(NULL, ¤t) == -1) + return -1; + + return current.dinfo->numdevs; +} + +Stats _get_stats(int i) { + struct statinfo current; + int num_devices; + + current.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); + devstat_getdevs(NULL, ¤t); + + num_devices = current.dinfo->numdevs; + Stats stats; + uint64_t bytes_read, bytes_write, bytes_free; + uint64_t transfers_other, transfers_read, transfers_write, transfers_free; + long double duration_other, duration_read, duration_write, duration_free; + long double busy_time; + uint64_t blocks; + + strcpy(stats.device, current.dinfo->devices[i].device_name); + stats.unit = current.dinfo->devices[i].unit_number; + devstat_compute_statistics(¤t.dinfo->devices[i], + NULL, + 1.0, + DSM_TOTAL_BYTES_READ, &bytes_read, + DSM_TOTAL_BYTES_WRITE, &bytes_write, + DSM_TOTAL_BYTES_FREE, &bytes_free, + DSM_TOTAL_TRANSFERS_OTHER, &transfers_other, + DSM_TOTAL_TRANSFERS_READ, &transfers_read, + DSM_TOTAL_TRANSFERS_WRITE, &transfers_write, + DSM_TOTAL_TRANSFERS_FREE, &transfers_free, + DSM_TOTAL_DURATION_OTHER, &duration_other, + DSM_TOTAL_DURATION_READ, &duration_read, + DSM_TOTAL_DURATION_WRITE, &duration_write, + DSM_TOTAL_DURATION_FREE, &duration_free, + DSM_TOTAL_BUSY_TIME, &busy_time, + DSM_TOTAL_BLOCKS, &blocks, + DSM_NONE); + + stats.bytes.read = bytes_read; + stats.bytes.write = bytes_write; + stats.bytes.free = bytes_free; + stats.transfers.other = transfers_other; + stats.transfers.read = transfers_read; + stats.transfers.write = transfers_write; + stats.transfers.free = transfers_free; + stats.duration.other = duration_other; + stats.duration.read = duration_read; + stats.duration.write = duration_write; + stats.duration.free = duration_free; + stats.busyTime = busy_time; + stats.blocks = blocks; + + return stats; +} +*/ +import "C" + +const ( + devstatSubsystem = "devstat" +) + +type devstatCollector struct { + bytes *prometheus.CounterVec + bytes_total *prometheus.CounterVec + transfers *prometheus.CounterVec + duration *prometheus.CounterVec + busyTime *prometheus.CounterVec + blocks *prometheus.CounterVec +} + +func init() { + Factories["devstat"] = NewDevstatCollector +} + +// Takes a prometheus registry and returns a new Collector exposing +// Device stats. +func NewDevstatCollector() (Collector, error) { + return &devstatCollector{ + bytes: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Subsystem: devstatSubsystem, + Name: "bytes_total", + Help: "The total number of bytes in transactions.", + }, + []string{"device", "type"}, + ), + transfers: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Subsystem: devstatSubsystem, + Name: "transfers_total", + Help: "The total number of transactions.", + }, + []string{"device", "type"}, + ), + duration: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Subsystem: devstatSubsystem, + Name: "duration_seconds_total", + Help: "The total duration of transactions in seconds.", + }, + []string{"device", "type"}, + ), + busyTime: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Subsystem: devstatSubsystem, + Name: "busy_time_seconds_total", + Help: "Total time the device had one or more transactions outstanding in seconds.", + }, + []string{"device"}, + ), + blocks: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Subsystem: devstatSubsystem, + Name: "blocks_transferred_total", + Help: "The total number of blocks transferred.", + }, + []string{"device"}, + ), + }, nil +} + +func (c *devstatCollector) Update(ch chan<- prometheus.Metric) (err error) { + count := C._get_ndevs() + if count == -1 { + return errors.New("devstat_getdevs() failed") + } + if count == -2 { + return errors.New("calloc() failed") + } + + for i := C.int(0); i < count; i++ { + stats := C._get_stats(i) + device := fmt.Sprintf("%s%d", C.GoString(&stats.device[0]), stats.unit) + // Free metrics are disabled for now, please see PR #88 for more details. + c.bytes.With(prometheus.Labels{"device": device, "type": "read"}).Set(float64(stats.bytes.read)) + c.bytes.With(prometheus.Labels{"device": device, "type": "write"}).Set(float64(stats.bytes.write)) + //c.bytes.With(prometheus.Labels{"device": device, "type": "free"}).Set(float64(stats.bytes.free)) + c.transfers.With(prometheus.Labels{"device": device, "type": "other"}).Set(float64(stats.transfers.other)) + c.transfers.With(prometheus.Labels{"device": device, "type": "read"}).Set(float64(stats.transfers.read)) + c.transfers.With(prometheus.Labels{"device": device, "type": "write"}).Set(float64(stats.transfers.write)) + //c.transfers.With(prometheus.Labels{"device": device, "type": "free"}).Set(float64(stats.transfers.free)) + c.duration.With(prometheus.Labels{"device": device, "type": "other"}).Set(float64(stats.duration.other)) + c.duration.With(prometheus.Labels{"device": device, "type": "read"}).Set(float64(stats.duration.read)) + c.duration.With(prometheus.Labels{"device": device, "type": "write"}).Set(float64(stats.duration.write)) + //c.duration.With(prometheus.Labels{"device": device, "type": "free"}).Set(float64(stats.duration.free)) + c.busyTime.With(prometheus.Labels{"device": device}).Set(float64(stats.busyTime)) + c.blocks.With(prometheus.Labels{"device": device}).Set(float64(stats.blocks)) + } + + c.bytes.Collect(ch) + c.transfers.Collect(ch) + c.duration.Collect(ch) + c.busyTime.Collect(ch) + c.blocks.Collect(ch) + + return err +} diff --git a/collector/diskstats.go b/collector/diskstats_linux.go similarity index 100% rename from collector/diskstats.go rename to collector/diskstats_linux.go diff --git a/collector/diskstats_test.go b/collector/diskstats_linux_test.go similarity index 100% rename from collector/diskstats_test.go rename to collector/diskstats_linux_test.go diff --git a/collector/filesystem_freebsd.go b/collector/filesystem_freebsd.go new file mode 100644 index 00000000..c1bd6280 --- /dev/null +++ b/collector/filesystem_freebsd.go @@ -0,0 +1,124 @@ +// +build !nofilesystem + +package collector + +import ( + "errors" + "flag" + "regexp" + "unsafe" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/log" +) + +/* +#include +#include +#include +#include +*/ +import "C" + +const ( + filesystemSubsystem = "filesystem" +) + +var ( + ignoredMountPoints = flag.String("collector.filesystem.ignored-mount-points", "^/(dev)($|/)", "Regexp of mount points to ignore for filesystem collector.") +) + +type filesystemCollector struct { + ignoredMountPointsPattern *regexp.Regexp + + size, free, avail, files, filesFree *prometheus.GaugeVec +} + +func init() { + Factories["filesystem"] = NewFilesystemCollector +} + +// Takes a prometheus registry and returns a new Collector exposing +// Filesystems stats. +func NewFilesystemCollector() (Collector, error) { + var filesystemLabelNames = []string{"filesystem"} + + return &filesystemCollector{ + ignoredMountPointsPattern: regexp.MustCompile(*ignoredMountPoints), + size: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Subsystem: filesystemSubsystem, + Name: "size_bytes", + Help: "Filesystem size in bytes.", + }, + filesystemLabelNames, + ), + free: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Subsystem: filesystemSubsystem, + Name: "free_bytes", + Help: "Filesystem free space in bytes.", + }, + filesystemLabelNames, + ), + avail: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Subsystem: filesystemSubsystem, + Name: "avail_bytes", + Help: "Filesystem space available to non-root users in bytes.", + }, + filesystemLabelNames, + ), + files: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Subsystem: filesystemSubsystem, + Name: "file_nodes", + Help: "Filesystem total file nodes.", + }, + filesystemLabelNames, + ), + filesFree: prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: Namespace, + Subsystem: filesystemSubsystem, + Name: "file_free_nodes", + Help: "Filesystem total free file nodes.", + }, + filesystemLabelNames, + ), + }, nil +} + +// Expose filesystem fullness. +func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) { + var mntbuf *C.struct_statfs + count := C.getmntinfo(&mntbuf, C.MNT_NOWAIT) + if count == 0 { + return errors.New("getmntinfo() failed") + } + + mnt := (*[1 << 30]C.struct_statfs)(unsafe.Pointer(mntbuf)) + for i := 0; i < int(count); i++ { + name := C.GoString(&mnt[i].f_mntonname[0]) + if c.ignoredMountPointsPattern.MatchString(name) { + log.Debugf("Ignoring mount point: %s", name) + continue + } + c.size.WithLabelValues(name).Set(float64(mnt[i].f_blocks) * float64(mnt[i].f_bsize)) + c.free.WithLabelValues(name).Set(float64(mnt[i].f_bfree) * float64(mnt[i].f_bsize)) + c.avail.WithLabelValues(name).Set(float64(mnt[i].f_bavail) * float64(mnt[i].f_bsize)) + c.files.WithLabelValues(name).Set(float64(mnt[i].f_files)) + c.filesFree.WithLabelValues(name).Set(float64(mnt[i].f_ffree)) + } + + c.size.Collect(ch) + c.free.Collect(ch) + c.avail.Collect(ch) + c.files.Collect(ch) + c.filesFree.Collect(ch) + return err +} diff --git a/collector/filesystem.go b/collector/filesystem_linux.go similarity index 100% rename from collector/filesystem.go rename to collector/filesystem_linux.go diff --git a/collector/interrupts.go b/collector/interrupts_linux.go similarity index 100% rename from collector/interrupts.go rename to collector/interrupts_linux.go diff --git a/collector/interrupts_test.go b/collector/interrupts_linux_test.go similarity index 100% rename from collector/interrupts_test.go rename to collector/interrupts_linux_test.go diff --git a/collector/lastlogin.go b/collector/lastlogin_linux.go similarity index 100% rename from collector/lastlogin.go rename to collector/lastlogin_linux.go diff --git a/collector/loadavg.go b/collector/loadavg.go index bdf72988..5ead9e90 100644 --- a/collector/loadavg.go +++ b/collector/loadavg.go @@ -1,20 +1,18 @@ // +build !noloadavg +// +build !linux package collector import ( + "errors" "fmt" - "io/ioutil" - "strconv" - "strings" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/log" ) -const ( - procLoad = "/proc/loadavg" -) +// #include +import "C" type loadavgCollector struct { metric prometheus.Gauge @@ -25,7 +23,7 @@ func init() { } // Takes a prometheus registry and returns a new Collector exposing -// load, seconds since last login and a list of tags as specified by config. +// load1 stat. func NewLoadavgCollector() (Collector, error) { return &loadavgCollector{ metric: prometheus.NewGauge(prometheus.GaugeOpts{ @@ -48,18 +46,12 @@ func (c *loadavgCollector) Update(ch chan<- prometheus.Metric) (err error) { } func getLoad1() (float64, error) { - data, err := ioutil.ReadFile(procLoad) - if err != nil { - return 0, err + var loadavg [1]C.double + samples := C.getloadavg(&loadavg[0], 1) + if samples > 0 { + return float64(loadavg[0]), nil + } else { + return 0, errors.New("failed to get load average") } - return parseLoad(string(data)) -} -func parseLoad(data string) (float64, error) { - parts := strings.Fields(data) - load, err := strconv.ParseFloat(parts[0], 64) - if err != nil { - return 0, fmt.Errorf("Could not parse load '%s': %s", parts[0], err) - } - return load, nil } diff --git a/collector/loadavg_linux.go b/collector/loadavg_linux.go new file mode 100644 index 00000000..bdf72988 --- /dev/null +++ b/collector/loadavg_linux.go @@ -0,0 +1,65 @@ +// +build !noloadavg + +package collector + +import ( + "fmt" + "io/ioutil" + "strconv" + "strings" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/log" +) + +const ( + procLoad = "/proc/loadavg" +) + +type loadavgCollector struct { + metric prometheus.Gauge +} + +func init() { + Factories["loadavg"] = NewLoadavgCollector +} + +// Takes a prometheus registry and returns a new Collector exposing +// load, seconds since last login and a list of tags as specified by config. +func NewLoadavgCollector() (Collector, error) { + return &loadavgCollector{ + metric: prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "load1", + Help: "1m load average.", + }), + }, nil +} + +func (c *loadavgCollector) Update(ch chan<- prometheus.Metric) (err error) { + load, err := getLoad1() + if err != nil { + return fmt.Errorf("Couldn't get load: %s", err) + } + log.Debugf("Set node_load: %f", load) + c.metric.Set(load) + c.metric.Collect(ch) + return err +} + +func getLoad1() (float64, error) { + data, err := ioutil.ReadFile(procLoad) + if err != nil { + return 0, err + } + return parseLoad(string(data)) +} + +func parseLoad(data string) (float64, error) { + parts := strings.Fields(data) + load, err := strconv.ParseFloat(parts[0], 64) + if err != nil { + return 0, fmt.Errorf("Could not parse load '%s': %s", parts[0], err) + } + return load, nil +} diff --git a/collector/loadavg_test.go b/collector/loadavg_linux_test.go similarity index 100% rename from collector/loadavg_test.go rename to collector/loadavg_linux_test.go diff --git a/collector/meminfo_freebsd.go b/collector/meminfo_freebsd.go new file mode 100644 index 00000000..fca410cc --- /dev/null +++ b/collector/meminfo_freebsd.go @@ -0,0 +1,96 @@ +// +build !nomeminfo + +package collector + +import ( + "errors" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/log" +) + +/* +#include +#include + +int _sysctl(const char* name) { + int val; + size_t size = sizeof(val); + int res = sysctlbyname(name, &val, &size, NULL, 0); + if (res == -1) { + return -1; + } + if (size != sizeof(val)) { + return -2; + } + return val; +} +*/ +import "C" + +const ( + memInfoSubsystem = "memory" +) + +type meminfoCollector struct { + metrics map[string]prometheus.Gauge +} + +func init() { + Factories["meminfo"] = NewMeminfoCollector +} + +// Takes a prometheus registry and returns a new Collector exposing +// Memory stats. +func NewMeminfoCollector() (Collector, error) { + return &meminfoCollector{ + metrics: map[string]prometheus.Gauge{}, + }, nil +} + +func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) (err error) { + var pages map[string]C.int + pages = make(map[string]C.int) + + size := C._sysctl(C.CString("vm.stats.vm.v_page_size")) + if size == -1 { + return errors.New("sysctl(vm.stats.vm.v_page_size) failed") + } + if size == -2 { + return errors.New("sysctl(vm.stats.vm.v_page_size) failed, wrong buffer size") + } + + pages["active"] = C._sysctl(C.CString("vm.stats.vm.v_active_count")) + pages["inactive"] = C._sysctl(C.CString("vm.stats.vm.v_inactive_count")) + pages["wire"] = C._sysctl(C.CString("vm.stats.vm.v_wire_count")) + pages["cache"] = C._sysctl(C.CString("vm.stats.vm.v_cache_count")) + pages["free"] = C._sysctl(C.CString("vm.stats.vm.v_free_count")) + pages["swappgsin"] = C._sysctl(C.CString("vm.stats.vm.v_swappgsin")) + pages["swappgsout"] = C._sysctl(C.CString("vm.stats.vm.v_swappgsout")) + pages["total"] = C._sysctl(C.CString("vm.stats.vm.v_page_count")) + + for key := range pages { + if pages[key] == -1 { + return errors.New("sysctl() failed for " + key) + } + if pages[key] == -2 { + return errors.New("sysctl() failed for " + key + ", wrong buffer size") + } + } + + log.Debugf("Set node_mem: %#v", pages) + for k, v := range pages { + if _, ok := c.metrics[k]; !ok { + c.metrics[k] = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: Namespace, + Subsystem: memInfoSubsystem, + Name: k, + Help: k + " from sysctl()", + }) + } + // Convert metrics to kB (same as Linux meminfo). + c.metrics[k].Set(float64(v) * float64(size)) + c.metrics[k].Collect(ch) + } + return err +} diff --git a/collector/meminfo.go b/collector/meminfo_linux.go similarity index 100% rename from collector/meminfo.go rename to collector/meminfo_linux.go diff --git a/collector/meminfo_test.go b/collector/meminfo_linux_test.go similarity index 100% rename from collector/meminfo_test.go rename to collector/meminfo_linux_test.go diff --git a/collector/netdev_freebsd.go b/collector/netdev_freebsd.go new file mode 100644 index 00000000..68a96bd3 --- /dev/null +++ b/collector/netdev_freebsd.go @@ -0,0 +1,110 @@ +// +build !nonetdev + +package collector + +import ( + "errors" + "fmt" + "strconv" + + "github.com/prometheus/client_golang/prometheus" +) + +/* +#cgo CFLAGS: -D_IFI_OQDROPS +#include +#include +#include +#include +#include +*/ +import "C" + +const ( + netDevSubsystem = "network" +) + +type netDevCollector struct { + metrics map[string]*prometheus.CounterVec +} + +func init() { + Factories["netdev"] = NewNetDevCollector +} + +// Takes a prometheus registry and returns a new Collector exposing +// Network device stats. +func NewNetDevCollector() (Collector, error) { + return &netDevCollector{ + metrics: map[string]*prometheus.CounterVec{}, + }, nil +} + +func (c *netDevCollector) Update(ch chan<- prometheus.Metric) (err error) { + netDev, err := getNetDevStats() + if err != nil { + return fmt.Errorf("couldn't get netstats: %s", err) + } + for direction, devStats := range netDev { + for dev, stats := range devStats { + for t, value := range stats { + key := direction + "_" + t + if _, ok := c.metrics[key]; !ok { + c.metrics[key] = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: Namespace, + Subsystem: netDevSubsystem, + Name: key, + Help: fmt.Sprintf("%s %s from getifaddrs().", t, direction), + }, + []string{"device"}, + ) + } + v, err := strconv.ParseFloat(value, 64) + if err != nil { + return fmt.Errorf("invalid value %s in netstats: %s", value, err) + } + c.metrics[key].WithLabelValues(dev).Set(v) + } + } + } + for _, m := range c.metrics { + m.Collect(ch) + } + return err +} + +func getNetDevStats() (map[string]map[string]map[string]string, error) { + netDev := map[string]map[string]map[string]string{} + netDev["transmit"] = map[string]map[string]string{} + netDev["receive"] = map[string]map[string]string{} + + var ifap, ifa *C.struct_ifaddrs + if C.getifaddrs(&ifap) == -1 { + return nil, errors.New("getifaddrs() failed") + } + defer C.freeifaddrs(ifap) + + for ifa = ifap; ifa != nil; ifa = ifa.ifa_next { + if ifa.ifa_addr.sa_family == C.AF_LINK { + receive := map[string]string{} + transmit := map[string]string{} + data := (*C.struct_if_data)(ifa.ifa_data) + receive["packets"] = strconv.Itoa(int(data.ifi_ipackets)) + transmit["packets"] = strconv.Itoa(int(data.ifi_opackets)) + receive["errs"] = strconv.Itoa(int(data.ifi_ierrors)) + transmit["errs"] = strconv.Itoa(int(data.ifi_oerrors)) + receive["bytes"] = strconv.Itoa(int(data.ifi_ibytes)) + transmit["bytes"] = strconv.Itoa(int(data.ifi_obytes)) + receive["multicast"] = strconv.Itoa(int(data.ifi_imcasts)) + transmit["multicast"] = strconv.Itoa(int(data.ifi_omcasts)) + receive["drop"] = strconv.Itoa(int(data.ifi_iqdrops)) + transmit["drop"] = strconv.Itoa(int(data.ifi_oqdrops)) + + netDev["receive"][C.GoString(ifa.ifa_name)] = receive + netDev["transmit"][C.GoString(ifa.ifa_name)] = transmit + } + } + + return netDev, nil +} diff --git a/collector/netdev.go b/collector/netdev_linux.go similarity index 100% rename from collector/netdev.go rename to collector/netdev_linux.go diff --git a/collector/netdev_test.go b/collector/netdev_linux_test.go similarity index 100% rename from collector/netdev_test.go rename to collector/netdev_linux_test.go diff --git a/collector/netstat.go b/collector/netstat_linux.go similarity index 100% rename from collector/netstat.go rename to collector/netstat_linux.go diff --git a/collector/netstat_test.go b/collector/netstat_linux_test.go similarity index 100% rename from collector/netstat_test.go rename to collector/netstat_linux_test.go diff --git a/collector/stat.go b/collector/stat_linux.go similarity index 100% rename from collector/stat.go rename to collector/stat_linux.go diff --git a/collector/tcpstat.go b/collector/tcpstat_linux.go similarity index 100% rename from collector/tcpstat.go rename to collector/tcpstat_linux.go diff --git a/collector/tcpstat_test.go b/collector/tcpstat_linux_test.go similarity index 100% rename from collector/tcpstat_test.go rename to collector/tcpstat_linux_test.go