mirror of
https://github.com/prometheus/node_exporter.git
synced 2025-02-02 08:42:31 -08: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 !noloadavg
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/log"
|
"github.com/prometheus/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// #include <stdlib.h>
|
||||||
procLoad = "/proc/loadavg"
|
import "C"
|
||||||
)
|
|
||||||
|
|
||||||
type loadavgCollector struct {
|
type loadavgCollector struct {
|
||||||
metric prometheus.Gauge
|
metric prometheus.Gauge
|
||||||
|
@ -25,7 +23,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a prometheus registry and returns a new Collector exposing
|
// 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) {
|
func NewLoadavgCollector() (Collector, error) {
|
||||||
return &loadavgCollector{
|
return &loadavgCollector{
|
||||||
metric: prometheus.NewGauge(prometheus.GaugeOpts{
|
metric: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
@ -48,18 +46,12 @@ func (c *loadavgCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLoad1() (float64, error) {
|
func getLoad1() (float64, error) {
|
||||||
data, err := ioutil.ReadFile(procLoad)
|
var loadavg [1]C.double
|
||||||
if err != nil {
|
samples := C.getloadavg(&loadavg[0], 1)
|
||||||
return 0, err
|
if samples > 0 {
|
||||||
}
|
return float64(loadavg[0]), nil
|
||||||
return parseLoad(string(data))
|
} else {
|
||||||
|
return 0, errors.New("failed to get load average")
|
||||||
}
|
}
|
||||||
|
|
||||||
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 a new issue