From 5c28ab044d88b51a653ae1bf8d6c30f58a32b7c2 Mon Sep 17 00:00:00 2001 From: Derek Marcotte Date: Tue, 28 Feb 2017 16:23:10 -0500 Subject: [PATCH] Add BSD exec statistics collector (#457) * First pass of a sysctl_bsd source, exec_bsd + exec metrics * Incorportate PR feedback, including removing pre-build descriptions, unit conversion callback. * Remove redundant cached_description field, per PR feedback * Incorporate PR feedback --- README.md | 1 + collector/exec_bsd.go | 98 +++++++++++++++++++++++++++++++++++++++++ collector/sysctl_bsd.go | 70 +++++++++++++++++++++++++++++ node_exporter.go | 2 +- 4 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 collector/exec_bsd.go create mode 100644 collector/sysctl_bsd.go diff --git a/README.md b/README.md index 0c4822f8..9d742d88 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ cpu | Exposes CPU statistics | Darwin, Dragonfly, FreeBSD diskstats | Exposes disk I/O statistics from `/proc/diskstats`. | Linux edac | Exposes error detection and correction statistics. | Linux entropy | Exposes available entropy. | Linux +exec | Exposes execution statistics. | Dragonfly, FreeBSD filefd | Exposes file descriptor statistics from `/proc/sys/fs/file-nr`. | Linux filesystem | Exposes filesystem statistics, such as disk space used. | Darwin, Dragonfly, FreeBSD, Linux, OpenBSD hwmon | Expose hardware monitoring and sensor data from `/sys/class/hwmon/`. | Linux diff --git a/collector/exec_bsd.go b/collector/exec_bsd.go new file mode 100644 index 00000000..0c794583 --- /dev/null +++ b/collector/exec_bsd.go @@ -0,0 +1,98 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build freebsd dragonfly +// +build !noexec + +package collector + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type execCollector struct { + sysctls []bsdSysctl +} + +func init() { + Factories["exec"] = NewExecCollector +} + +// NewExecCollector returns a new Collector exposing system execution statistics +func NewExecCollector() (Collector, error) { + // From sys/vm/vm_meter.c: + // All are of type CTLTYPE_UINT. + // + // vm.stats.sys.v_swtch: Context switches + // vm.stats.sys.v_trap: Traps + // vm.stats.sys.v_syscall: System calls + // vm.stats.sys.v_intr: Device interrupts + // vm.stats.sys.v_soft: Software interrupts + // vm.stats.vm.v_forks: Number of fork() calls + + return &execCollector{ + sysctls: []bsdSysctl{ + { + name: "context_switches_total", + description: "Context switches since system boot. Resets at architeture unsigned integer.", + mib: "vm.stats.sys.v_swtch", + }, + { + name: "traps_total", + description: "Traps since system boot. Resets at architeture unsigned integer.", + mib: "vm.stats.sys.v_trap", + }, + { + name: "system_calls_total", + description: "System calls since system boot. Resets at architeture unsigned integer.", + mib: "vm.stats.sys.v_syscall", + }, + { + name: "device_interrupts_total", + description: "Device interrupts since system boot. Resets at architeture unsigned integer.", + mib: "vm.stats.sys.v_intr", + }, + { + name: "software_interrupts_total", + description: "Software interrupts since system boot. Resets at architeture unsigned integer.", + mib: "vm.stats.sys.v_soft", + }, + { + name: "forks_total", + description: "Number of fork() calls since system boot. Resets at architeture unsigned integer.", + mib: "vm.stats.vm.v_forks", + }, + }, + }, nil +} + +// Update pushes exec statistics onto ch +func (c *execCollector) Update(ch chan<- prometheus.Metric) (err error) { + for _, m := range c.sysctls { + v, err := m.Value() + if err != nil { + return err + } + + // We "know" all of our sysctls are CounterValues, let's skip + // parsing them + ch <- prometheus.MustNewConstMetric( + prometheus.NewDesc( + prometheus.BuildFQName(Namespace, "exec", m.name), + m.description, + nil, nil, + ), prometheus.CounterValue, v) + } + + return nil +} diff --git a/collector/sysctl_bsd.go b/collector/sysctl_bsd.go new file mode 100644 index 00000000..fcb8af5c --- /dev/null +++ b/collector/sysctl_bsd.go @@ -0,0 +1,70 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build freebsd dragonfly +// +build !nomeminfo + +package collector + +import ( + "github.com/prometheus/client_golang/prometheus" + "golang.org/x/sys/unix" +) + +type bsdSysctlType uint8 + +// BSD-specific sysctl value types. There is an impedience mismatch between +// native C types, e.g. int vs long, and the golang unix.Sysctl variables + +const ( + // Default to uint32. + bsdSysctlTypeUint32 bsdSysctlType = iota + bsdSysctlTypeUint64 +) + +// Contains all the info needed to map a single bsd-sysctl to a prometheus value. +type bsdSysctl struct { + // Prometheus name + name string + + // Simple prometheus description + description string + + // Prometheus type + valueType prometheus.ValueType + + // Sysctl name + mib string + + // Sysctl data-type + dataType bsdSysctlType +} + +func (b bsdSysctl) Value() (float64, error) { + var tmp32 uint32 + var tmp64 uint64 + var err error + + switch b.dataType { + case bsdSysctlTypeUint32: + tmp32, err = unix.SysctlUint32(b.mib) + tmp64 = uint64(tmp32) + case bsdSysctlTypeUint64: + tmp64, err = unix.SysctlUint64(b.mib) + } + if err != nil { + return 0, err + } + + return float64(tmp64), nil +} diff --git a/node_exporter.go b/node_exporter.go index ec69c053..1a505cfd 100644 --- a/node_exporter.go +++ b/node_exporter.go @@ -32,7 +32,7 @@ import ( ) const ( - defaultCollectors = "conntrack,cpu,diskstats,entropy,edac,filefd,filesystem,hwmon,infiniband,loadavg,mdadm,meminfo,netdev,netstat,sockstat,stat,textfile,time,uname,vmstat,wifi,zfs" + defaultCollectors = "conntrack,cpu,diskstats,entropy,edac,exec,filefd,filesystem,hwmon,infiniband,loadavg,mdadm,meminfo,netdev,netstat,sockstat,stat,textfile,time,uname,vmstat,wifi,zfs" ) var (