2015-09-26 08:36:40 -07:00
// Copyright 2015 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.
2021-10-03 04:35:24 -07:00
//go:build !nodiskstats
2015-05-12 04:06:41 -07:00
// +build !nodiskstats
2014-06-04 04:12:34 -07:00
package collector
import (
"fmt"
"regexp"
2020-11-14 02:53:51 -08:00
"github.com/go-kit/log"
"github.com/go-kit/log/level"
2014-06-04 04:12:34 -07:00
"github.com/prometheus/client_golang/prometheus"
2021-09-28 01:14:12 -07:00
"github.com/prometheus/procfs/blockdevice"
2017-08-12 06:07:24 -07:00
"gopkg.in/alecthomas/kingpin.v2"
2014-06-04 04:12:34 -07:00
)
const (
2021-09-28 01:14:12 -07:00
secondsPerTick = 1.0 / 1000.0
2022-03-07 14:24:08 -08:00
2022-03-10 16:43:07 -08:00
// Read sectors and write sectors are the "standard UNIX 512-byte sectors, not any device- or filesystem-specific block size."
// See also https://www.kernel.org/doc/Documentation/block/stat.txt
2022-03-07 14:24:08 -08:00
unixSectorSize = 512.0
2014-06-04 04:12:34 -07:00
)
var (
2017-08-12 06:07:24 -07:00
ignoredDevices = kingpin . Flag ( "collector.diskstats.ignored-devices" , "Regexp of devices to ignore for diskstats." ) . Default ( "^(ram|loop|fd|(h|s|v|xv)d[a-z]|nvme\\d+n\\d+p)\\d+$" ) . String ( )
2014-06-04 04:12:34 -07:00
)
2018-01-17 08:55:55 -08:00
type typedFactorDesc struct {
desc * prometheus . Desc
valueType prometheus . ValueType
}
func ( d * typedFactorDesc ) mustNewConstMetric ( value float64 , labels ... string ) prometheus . Metric {
return prometheus . MustNewConstMetric ( d . desc , d . valueType , value , labels ... )
}
2014-06-04 04:12:34 -07:00
type diskstatsCollector struct {
ignoredDevicesPattern * regexp . Regexp
2021-09-28 01:14:12 -07:00
fs blockdevice . FS
infoDesc typedFactorDesc
2018-01-17 08:55:55 -08:00
descs [ ] typedFactorDesc
2019-12-31 08:19:37 -08:00
logger log . Logger
2014-06-04 04:12:34 -07:00
}
func init ( ) {
2017-09-28 06:06:26 -07:00
registerCollector ( "diskstats" , defaultEnabled , NewDiskstatsCollector )
2014-06-04 04:12:34 -07:00
}
2017-02-28 08:44:53 -08:00
// NewDiskstatsCollector returns a new Collector exposing disk device stats.
2018-10-15 08:24:28 -07:00
// Docs from https://www.kernel.org/doc/Documentation/iostats.txt
2019-12-31 08:19:37 -08:00
func NewDiskstatsCollector ( logger log . Logger ) ( Collector , error ) {
2014-11-24 18:00:17 -08:00
var diskLabelNames = [ ] string { "device" }
2021-09-28 01:14:12 -07:00
fs , err := blockdevice . NewFS ( * procPath , * sysPath )
if err != nil {
return nil , fmt . Errorf ( "failed to open sysfs: %w" , err )
}
2014-11-24 18:00:17 -08:00
return & diskstatsCollector {
2014-06-04 04:12:34 -07:00
ignoredDevicesPattern : regexp . MustCompile ( * ignoredDevices ) ,
2021-09-28 01:14:12 -07:00
fs : fs ,
infoDesc : typedFactorDesc {
desc : prometheus . NewDesc ( prometheus . BuildFQName ( namespace , diskSubsystem , "info" ) ,
"Info of /sys/block/<block_device>." ,
[ ] string { "device" , "major" , "minor" } ,
nil ,
) , valueType : prometheus . GaugeValue ,
} ,
2018-01-17 08:55:55 -08:00
descs : [ ] typedFactorDesc {
2016-12-28 06:21:31 -08:00
{
2019-02-06 02:36:22 -08:00
desc : readsCompletedDesc , valueType : prometheus . CounterValue ,
2016-12-28 06:21:31 -08:00
} ,
{
desc : prometheus . NewDesc (
2018-01-17 08:55:55 -08:00
prometheus . BuildFQName ( namespace , diskSubsystem , "reads_merged_total" ) ,
2018-10-15 08:24:28 -07:00
"The total number of reads merged." ,
2016-12-28 06:21:31 -08:00
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
{
2019-02-06 02:36:22 -08:00
desc : readBytesDesc , valueType : prometheus . CounterValue ,
2016-12-28 06:21:31 -08:00
} ,
{
2019-02-06 02:36:22 -08:00
desc : readTimeSecondsDesc , valueType : prometheus . CounterValue ,
2016-12-28 06:21:31 -08:00
} ,
{
2019-02-06 02:36:22 -08:00
desc : writesCompletedDesc , valueType : prometheus . CounterValue ,
2016-12-28 06:21:31 -08:00
} ,
{
desc : prometheus . NewDesc (
2018-01-17 08:55:55 -08:00
prometheus . BuildFQName ( namespace , diskSubsystem , "writes_merged_total" ) ,
2018-10-15 08:24:28 -07:00
"The number of writes merged." ,
2016-12-28 06:21:31 -08:00
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
{
2019-02-06 02:36:22 -08:00
desc : writtenBytesDesc , valueType : prometheus . CounterValue ,
2016-12-28 06:21:31 -08:00
} ,
{
2019-02-06 02:36:22 -08:00
desc : writeTimeSecondsDesc , valueType : prometheus . CounterValue ,
2016-12-28 06:21:31 -08:00
} ,
{
desc : prometheus . NewDesc (
2017-09-28 06:06:26 -07:00
prometheus . BuildFQName ( namespace , diskSubsystem , "io_now" ) ,
2016-12-28 06:21:31 -08:00
"The number of I/Os currently in progress." ,
diskLabelNames ,
nil ,
) , valueType : prometheus . GaugeValue ,
} ,
{
2019-02-06 02:36:22 -08:00
desc : ioTimeSecondsDesc , valueType : prometheus . CounterValue ,
2016-12-28 06:21:31 -08:00
} ,
{
desc : prometheus . NewDesc (
2018-01-17 08:55:55 -08:00
prometheus . BuildFQName ( namespace , diskSubsystem , "io_time_weighted_seconds_total" ) ,
2018-10-15 08:24:28 -07:00
"The weighted # of seconds spent doing I/Os." ,
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
{
desc : prometheus . NewDesc (
prometheus . BuildFQName ( namespace , diskSubsystem , "discards_completed_total" ) ,
"The total number of discards completed successfully." ,
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
{
desc : prometheus . NewDesc (
prometheus . BuildFQName ( namespace , diskSubsystem , "discards_merged_total" ) ,
"The total number of discards merged." ,
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
{
desc : prometheus . NewDesc (
prometheus . BuildFQName ( namespace , diskSubsystem , "discarded_sectors_total" ) ,
2018-10-30 10:45:00 -07:00
"The total number of sectors discarded successfully." ,
2018-10-15 08:24:28 -07:00
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
{
desc : prometheus . NewDesc (
prometheus . BuildFQName ( namespace , diskSubsystem , "discard_time_seconds_total" ) ,
"This is the total number of seconds spent by all discards." ,
2016-12-28 06:21:31 -08:00
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
2019-11-25 11:16:15 -08:00
{
desc : prometheus . NewDesc (
prometheus . BuildFQName ( namespace , diskSubsystem , "flush_requests_total" ) ,
"The total number of flush requests completed successfully" ,
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
{
desc : prometheus . NewDesc (
prometheus . BuildFQName ( namespace , diskSubsystem , "flush_requests_time_seconds_total" ) ,
"This is the total number of seconds spent by all flush requests." ,
diskLabelNames ,
nil ,
) , valueType : prometheus . CounterValue ,
} ,
2014-11-24 18:00:17 -08:00
} ,
2019-12-31 08:19:37 -08:00
logger : logger ,
2014-11-24 18:00:17 -08:00
} , nil
2014-06-04 04:12:34 -07:00
}
2016-12-28 06:21:31 -08:00
func ( c * diskstatsCollector ) Update ( ch chan <- prometheus . Metric ) error {
2021-09-28 01:14:12 -07:00
diskStats , err := c . fs . ProcDiskstats ( )
2014-06-04 04:12:34 -07:00
if err != nil {
2020-06-15 13:27:14 -07:00
return fmt . Errorf ( "couldn't get diskstats: %w" , err )
2014-06-04 04:12:34 -07:00
}
2014-11-24 18:00:17 -08:00
2021-09-28 01:14:12 -07:00
for _ , stats := range diskStats {
dev := stats . DeviceName
2014-06-04 04:12:34 -07:00
if c . ignoredDevicesPattern . MatchString ( dev ) {
2021-09-28 01:14:12 -07:00
level . Debug ( c . logger ) . Log ( "msg" , "Ignoring device" , "device" , dev , "pattern" , c . ignoredDevicesPattern )
2014-06-04 04:12:34 -07:00
continue
}
2014-11-24 18:00:17 -08:00
2021-09-28 01:14:12 -07:00
ch <- c . infoDesc . mustNewConstMetric ( 1.0 , dev , fmt . Sprint ( stats . MajorNumber ) , fmt . Sprint ( stats . MinorNumber ) )
statCount := stats . IoStatsCount - 3 // Total diskstats record count, less MajorNumber, MinorNumber and DeviceName
for i , val := range [ ] float64 {
float64 ( stats . ReadIOs ) ,
float64 ( stats . ReadMerges ) ,
2022-03-07 14:24:08 -08:00
float64 ( stats . ReadSectors ) * unixSectorSize ,
2021-09-28 01:14:12 -07:00
float64 ( stats . ReadTicks ) * secondsPerTick ,
float64 ( stats . WriteIOs ) ,
float64 ( stats . WriteMerges ) ,
2022-03-07 14:24:08 -08:00
float64 ( stats . WriteSectors ) * unixSectorSize ,
2021-09-28 01:14:12 -07:00
float64 ( stats . WriteTicks ) * secondsPerTick ,
float64 ( stats . IOsInProgress ) ,
float64 ( stats . IOsTotalTicks ) * secondsPerTick ,
float64 ( stats . WeightedIOTicks ) * secondsPerTick ,
float64 ( stats . DiscardIOs ) ,
float64 ( stats . DiscardMerges ) ,
float64 ( stats . DiscardSectors ) ,
float64 ( stats . DiscardTicks ) * secondsPerTick ,
float64 ( stats . FlushRequestsCompleted ) ,
float64 ( stats . TimeSpentFlushing ) * secondsPerTick ,
} {
if i >= statCount {
2018-10-30 10:45:00 -07:00
break
}
2021-09-28 01:14:12 -07:00
ch <- c . descs [ i ] . mustNewConstMetric ( val , dev )
2014-06-04 04:12:34 -07:00
}
}
2016-12-28 06:21:31 -08:00
return nil
2014-06-04 04:12:34 -07:00
}