diff --git a/CHANGELOG.md b/CHANGELOG.md index c445503b..b3c464dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The cpufreq metrics now separate the `cpufreq` and `scaling` data based on what * [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 +* [FEATURE] Add diskstats collector for OpenBSD #1250 ## 0.17.0 / 2018-11-30 diff --git a/README.md b/README.md index 187e2758..3196ab3b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ bonding | Exposes the number of configured and active slaves of Linux bonding in boottime | Exposes system boot time derived from the `kern.boottime` sysctl. | Darwin, Dragonfly, FreeBSD, NetBSD, OpenBSD, Solaris conntrack | Shows conntrack statistics (does nothing if no `/proc/sys/net/netfilter/` present). | Linux cpu | Exposes CPU statistics | Darwin, Dragonfly, FreeBSD, Linux, Solaris -diskstats | Exposes disk I/O statistics. | Darwin, Linux +diskstats | Exposes disk I/O statistics. | Darwin, Linux, OpenBSD edac | Exposes error detection and correction statistics. | Linux entropy | Exposes available entropy. | Linux exec | Exposes execution statistics. | Dragonfly, FreeBSD diff --git a/collector/diskstats_common.go b/collector/diskstats_common.go new file mode 100644 index 00000000..7efb399a --- /dev/null +++ b/collector/diskstats_common.go @@ -0,0 +1,73 @@ +// Copyright 2019 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 !nodiskstats +// +build openbsd linux darwin + +package collector + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +const ( + diskSubsystem = "disk" +) + +var ( + diskLabelNames = []string{"device"} + + readsCompletedDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "reads_completed_total"), + "The total number of reads completed successfully.", + diskLabelNames, nil, + ) + + readBytesDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "read_bytes_total"), + "The total number of bytes read successfully.", + diskLabelNames, nil, + ) + + writesCompletedDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "writes_completed_total"), + "The total number of writes completed successfully.", + diskLabelNames, nil, + ) + + writtenBytesDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "written_bytes_total"), + "The total number of bytes written successfully.", + diskLabelNames, nil, + ) + + ioTimeSecondsDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "io_time_seconds_total"), + "Total seconds spent doing I/Os.", + diskLabelNames, nil, + ) + + readTimeSecondsDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "read_time_seconds_total"), + "The total number of seconds spent by all reads.", + diskLabelNames, + nil, + ) + + writeTimeSecondsDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "write_time_seconds_total"), + "This is the total number of seconds spent by all writes.", + diskLabelNames, + nil, + ) +) diff --git a/collector/diskstats_darwin.go b/collector/diskstats_darwin.go index a92de521..2c765827 100644 --- a/collector/diskstats_darwin.go +++ b/collector/diskstats_darwin.go @@ -22,10 +22,6 @@ import ( "github.com/prometheus/client_golang/prometheus" ) -const ( - diskSubsystem = "disk" -) - type typedDescFunc struct { typedDesc value func(stat *iostat.DriveStats) float64 @@ -47,12 +43,7 @@ func NewDiskstatsCollector() (Collector, error) { descs: []typedDescFunc{ { typedDesc: typedDesc{ - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "reads_completed_total"), - "The total number of reads completed successfully.", - diskLabelNames, - nil, - ), + desc: readsCompletedDesc, valueType: prometheus.CounterValue, }, value: func(stat *iostat.DriveStats) float64 { @@ -75,12 +66,7 @@ func NewDiskstatsCollector() (Collector, error) { }, { typedDesc: typedDesc{ - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "read_time_seconds_total"), - "The total number of seconds spent by all reads.", - diskLabelNames, - nil, - ), + desc: readTimeSecondsDesc, valueType: prometheus.CounterValue, }, value: func(stat *iostat.DriveStats) float64 { @@ -89,12 +75,7 @@ func NewDiskstatsCollector() (Collector, error) { }, { typedDesc: typedDesc{ - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "writes_completed_total"), - "The total number of writes completed successfully.", - diskLabelNames, - nil, - ), + desc: writesCompletedDesc, valueType: prometheus.CounterValue, }, value: func(stat *iostat.DriveStats) float64 { @@ -117,12 +98,7 @@ func NewDiskstatsCollector() (Collector, error) { }, { typedDesc: typedDesc{ - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "write_time_seconds_total"), - "This is the total number of seconds spent by all writes.", - diskLabelNames, - nil, - ), + desc: writeTimeSecondsDesc, valueType: prometheus.CounterValue, }, value: func(stat *iostat.DriveStats) float64 { @@ -131,12 +107,7 @@ func NewDiskstatsCollector() (Collector, error) { }, { typedDesc: typedDesc{ - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "read_bytes_total"), - "The total number of bytes read successfully.", - diskLabelNames, - nil, - ), + desc: readBytesDesc, valueType: prometheus.CounterValue, }, value: func(stat *iostat.DriveStats) float64 { @@ -145,12 +116,7 @@ func NewDiskstatsCollector() (Collector, error) { }, { typedDesc: typedDesc{ - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "written_bytes_total"), - "The total number of bytes written successfully.", - diskLabelNames, - nil, - ), + desc: writtenBytesDesc, valueType: prometheus.CounterValue, }, value: func(stat *iostat.DriveStats) float64 { diff --git a/collector/diskstats_linux.go b/collector/diskstats_linux.go index 8efffd9e..1d39f2bf 100644 --- a/collector/diskstats_linux.go +++ b/collector/diskstats_linux.go @@ -30,7 +30,6 @@ import ( ) const ( - diskSubsystem = "disk" diskSectorSize = 512 diskstatsFilename = "diskstats" ) @@ -70,12 +69,7 @@ func NewDiskstatsCollector() (Collector, error) { ignoredDevicesPattern: regexp.MustCompile(*ignoredDevices), descs: []typedFactorDesc{ { - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "reads_completed_total"), - "The total number of reads completed successfully.", - diskLabelNames, - nil, - ), valueType: prometheus.CounterValue, + desc: readsCompletedDesc, valueType: prometheus.CounterValue, }, { desc: prometheus.NewDesc( @@ -86,30 +80,15 @@ func NewDiskstatsCollector() (Collector, error) { ), valueType: prometheus.CounterValue, }, { - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "read_bytes_total"), - "The total number of bytes read successfully.", - diskLabelNames, - nil, - ), valueType: prometheus.CounterValue, + desc: readBytesDesc, valueType: prometheus.CounterValue, factor: diskSectorSize, }, { - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "read_time_seconds_total"), - "The total number of seconds spent by all reads.", - diskLabelNames, - nil, - ), valueType: prometheus.CounterValue, + desc: readTimeSecondsDesc, valueType: prometheus.CounterValue, factor: .001, }, { - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "writes_completed_total"), - "The total number of writes completed successfully.", - diskLabelNames, - nil, - ), valueType: prometheus.CounterValue, + desc: writesCompletedDesc, valueType: prometheus.CounterValue, }, { desc: prometheus.NewDesc( @@ -120,21 +99,11 @@ func NewDiskstatsCollector() (Collector, error) { ), valueType: prometheus.CounterValue, }, { - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "written_bytes_total"), - "The total number of bytes written successfully.", - diskLabelNames, - nil, - ), valueType: prometheus.CounterValue, + desc: writtenBytesDesc, valueType: prometheus.CounterValue, factor: diskSectorSize, }, { - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "write_time_seconds_total"), - "This is the total number of seconds spent by all writes.", - diskLabelNames, - nil, - ), valueType: prometheus.CounterValue, + desc: writeTimeSecondsDesc, valueType: prometheus.CounterValue, factor: .001, }, { @@ -146,12 +115,7 @@ func NewDiskstatsCollector() (Collector, error) { ), valueType: prometheus.GaugeValue, }, { - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "io_time_seconds_total"), - "Total seconds spent doing I/Os.", - diskLabelNames, - nil, - ), valueType: prometheus.CounterValue, + desc: ioTimeSecondsDesc, valueType: prometheus.CounterValue, factor: .001, }, { diff --git a/collector/diskstats_openbsd.go b/collector/diskstats_openbsd.go new file mode 100644 index 00000000..f17e2a8b --- /dev/null +++ b/collector/diskstats_openbsd.go @@ -0,0 +1,74 @@ +// Copyright 2019 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 !nodiskstats + +package collector + +import ( + "unsafe" + + "github.com/prometheus/client_golang/prometheus" + "golang.org/x/sys/unix" +) + +/* +#include +#include +*/ +import "C" + +type diskstatsCollector struct { + rxfer typedDesc + rbytes typedDesc + wxfer typedDesc + wbytes typedDesc + time typedDesc +} + +func init() { + registerCollector("diskstats", defaultEnabled, NewDiskstatsCollector) +} + +// NewDiskstatsCollector returns a new Collector exposing disk device stats. +func NewDiskstatsCollector() (Collector, error) { + return &diskstatsCollector{ + rxfer: typedDesc{readsCompletedDesc, prometheus.CounterValue}, + rbytes: typedDesc{readBytesDesc, prometheus.CounterValue}, + wxfer: typedDesc{writesCompletedDesc, prometheus.CounterValue}, + wbytes: typedDesc{writtenBytesDesc, prometheus.CounterValue}, + time: typedDesc{ioTimeSecondsDesc, prometheus.CounterValue}, + }, nil +} + +func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) (err error) { + diskstatsb, err := unix.SysctlRaw("hw.diskstats") + if err != nil { + return err + } + + ndisks := len(diskstatsb) / C.sizeof_struct_diskstats + diskstats := *(*[]C.struct_diskstats)(unsafe.Pointer(&diskstatsb)) + + for i := 0; i < ndisks; i++ { + diskname := C.GoString(&diskstats[i].ds_name[0]) + + ch <- c.rxfer.mustNewConstMetric(float64(diskstats[i].ds_rxfer), diskname) + ch <- c.rbytes.mustNewConstMetric(float64(diskstats[i].ds_rbytes), diskname) + ch <- c.wxfer.mustNewConstMetric(float64(diskstats[i].ds_wxfer), diskname) + ch <- c.wbytes.mustNewConstMetric(float64(diskstats[i].ds_wbytes), diskname) + time := float64(diskstats[i].ds_time.tv_sec) + float64(diskstats[i].ds_time.tv_usec)/1000000 + ch <- c.time.mustNewConstMetric(time, diskname) + } + return nil +}