mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-11-23 20:36:21 +01:00
commit
5e86b55c46
72
collector/cpu_freebsd.go
Normal file
72
collector/cpu_freebsd.go
Normal file
@ -0,0 +1,72 @@
|
||||
// +build !nocpu
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lkvm
|
||||
#include <fcntl.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/resource.h>
|
||||
*/
|
||||
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
|
||||
}
|
226
collector/devstat_freebsd.go
Normal file
226
collector/devstat_freebsd.go
Normal file
@ -0,0 +1,226 @@
|
||||
// +build !nodevstat
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -ldevstat -lkvm
|
||||
#include <devstat.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgeom.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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
|
||||
}
|
124
collector/filesystem_freebsd.go
Normal file
124
collector/filesystem_freebsd.go
Normal file
@ -0,0 +1,124 @@
|
||||
// +build !nofilesystem
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"regexp"
|
||||
"unsafe"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/log"
|
||||
)
|
||||
|
||||
/*
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/mount.h>
|
||||
#include <stdio.h>
|
||||
*/
|
||||
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
|
||||
}
|
@ -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 <stdlib.h>
|
||||
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
|
||||
}
|
||||
|
65
collector/loadavg_linux.go
Normal file
65
collector/loadavg_linux.go
Normal file
@ -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
|
||||
}
|
96
collector/meminfo_freebsd.go
Normal file
96
collector/meminfo_freebsd.go
Normal file
@ -0,0 +1,96 @@
|
||||
// +build !nomeminfo
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/log"
|
||||
)
|
||||
|
||||
/*
|
||||
#include <stddef.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
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
|
||||
}
|
110
collector/netdev_freebsd.go
Normal file
110
collector/netdev_freebsd.go
Normal file
@ -0,0 +1,110 @@
|
||||
// +build !nonetdev
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -D_IFI_OQDROPS
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
*/
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user