diff --git a/pkg/collector/logical_disk/logical_disk.go b/pkg/collector/logical_disk/logical_disk.go index 0b05c378..89316fa0 100644 --- a/pkg/collector/logical_disk/logical_disk.go +++ b/pkg/collector/logical_disk/logical_disk.go @@ -3,6 +3,7 @@ package logical_disk import ( + "errors" "fmt" "regexp" @@ -11,6 +12,7 @@ import ( "github.com/go-kit/log/level" "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" + "github.com/prometheus-community/windows_exporter/pkg/wmi" "github.com/prometheus/client_golang/prometheus" ) @@ -19,8 +21,15 @@ const ( FlagLogicalDiskVolumeExclude = "collector.logical_disk.volume-exclude" FlagLogicalDiskVolumeInclude = "collector.logical_disk.volume-include" + + win32DiskQuery = "SELECT VolumeName,DeviceID FROM WIN32_LogicalDisk" ) +type Win32_LogicalDisk struct { + VolumeName string + DeviceID string +} + type Config struct { VolumeInclude string `yaml:"volume_include"` VolumeExclude string `yaml:"volume_exclude"` @@ -103,112 +112,112 @@ func (c *collector) Build() error { c.RequestsQueued = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "requests_queued"), "The number of requests queued to the disk (LogicalDisk.CurrentDiskQueueLength)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.AvgReadQueue = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "avg_read_requests_queued"), "Average number of read requests that were queued for the selected disk during the sample interval (LogicalDisk.AvgDiskReadQueueLength)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.AvgWriteQueue = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "avg_write_requests_queued"), "Average number of write requests that were queued for the selected disk during the sample interval (LogicalDisk.AvgDiskWriteQueueLength)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.ReadBytesTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "read_bytes_total"), "The number of bytes transferred from the disk during read operations (LogicalDisk.DiskReadBytesPerSec)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.ReadsTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "reads_total"), "The number of read operations on the disk (LogicalDisk.DiskReadsPerSec)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.WriteBytesTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "write_bytes_total"), "The number of bytes transferred to the disk during write operations (LogicalDisk.DiskWriteBytesPerSec)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.WritesTotal = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "writes_total"), "The number of write operations on the disk (LogicalDisk.DiskWritesPerSec)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.ReadTime = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "read_seconds_total"), "Seconds that the disk was busy servicing read requests (LogicalDisk.PercentDiskReadTime)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.WriteTime = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "write_seconds_total"), "Seconds that the disk was busy servicing write requests (LogicalDisk.PercentDiskWriteTime)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.FreeSpace = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "free_bytes"), "Free space in bytes, updates every 10-15 min (LogicalDisk.PercentFreeSpace)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.TotalSpace = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "size_bytes"), "Total space in bytes, updates every 10-15 min (LogicalDisk.PercentFreeSpace_Base)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.IdleTime = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "idle_seconds_total"), "Seconds that the disk was idle (LogicalDisk.PercentIdleTime)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.SplitIOs = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "split_ios_total"), "The number of I/Os to the disk were split into multiple I/Os (LogicalDisk.SplitIOPerSec)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.ReadLatency = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "read_latency_seconds_total"), "Shows the average time, in seconds, of a read operation from the disk (LogicalDisk.AvgDiskSecPerRead)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.WriteLatency = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "write_latency_seconds_total"), "Shows the average time, in seconds, of a write operation to the disk (LogicalDisk.AvgDiskSecPerWrite)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) c.ReadWriteLatency = prometheus.NewDesc( prometheus.BuildFQName(types.Namespace, Name, "read_write_latency_seconds_total"), "Shows the time, in seconds, of the average disk transfer (LogicalDisk.AvgDiskSecPerTransfer)", - []string{"volume"}, + []string{"volume", "volume_name"}, nil, ) @@ -241,6 +250,7 @@ func (c *collector) Collect(ctx *types.ScrapeContext, ch chan<- prometheus.Metri // - https://msdn.microsoft.com/en-us/library/ms803973.aspx - LogicalDisk object reference type logicalDisk struct { Name string + VolumeName string CurrentDiskQueueLength float64 `perflib:"Current Disk Queue Length"` AvgDiskReadQueueLength float64 `perflib:"Avg. Disk Read Queue Length"` AvgDiskWriteQueueLength float64 `perflib:"Avg. Disk Write Queue Length"` @@ -260,6 +270,15 @@ type logicalDisk struct { } func (c *collector) collect(ctx *types.ScrapeContext, ch chan<- prometheus.Metric) (*prometheus.Desc, error) { + var dst_Win32_LogicalDisk []Win32_LogicalDisk + + if err := wmi.Query(win32DiskQuery, &dst_Win32_LogicalDisk); err != nil { + return nil, err + } + if len(dst_Win32_LogicalDisk) == 0 { + return nil, errors.New("WMI query returned empty result set") + } + var dst []logicalDisk if err := perflib.UnmarshalObject(ctx.PerfObjects["LogicalDisk"], &dst, c.logger); err != nil { return nil, err @@ -271,118 +290,144 @@ func (c *collector) collect(ctx *types.ScrapeContext, ch chan<- prometheus.Metri !c.volumeIncludePattern.MatchString(volume.Name) { continue } + for _, logicalDisk := range dst_Win32_LogicalDisk { + if logicalDisk.VolumeName == "" { + logicalDisk.VolumeName = "Local Disk" + } + if logicalDisk.DeviceID == volume.Name { + ch <- prometheus.MustNewConstMetric( + c.RequestsQueued, + prometheus.GaugeValue, + volume.CurrentDiskQueueLength, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.RequestsQueued, - prometheus.GaugeValue, - volume.CurrentDiskQueueLength, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.AvgReadQueue, + prometheus.GaugeValue, + volume.AvgDiskReadQueueLength*perflib.TicksToSecondScaleFactor, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.AvgReadQueue, - prometheus.GaugeValue, - volume.AvgDiskReadQueueLength*perflib.TicksToSecondScaleFactor, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.AvgWriteQueue, + prometheus.GaugeValue, + volume.AvgDiskWriteQueueLength*perflib.TicksToSecondScaleFactor, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.AvgWriteQueue, - prometheus.GaugeValue, - volume.AvgDiskWriteQueueLength*perflib.TicksToSecondScaleFactor, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.ReadBytesTotal, + prometheus.CounterValue, + volume.DiskReadBytesPerSec, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.ReadBytesTotal, - prometheus.CounterValue, - volume.DiskReadBytesPerSec, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.ReadsTotal, + prometheus.CounterValue, + volume.DiskReadsPerSec, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.ReadsTotal, - prometheus.CounterValue, - volume.DiskReadsPerSec, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.WriteBytesTotal, + prometheus.CounterValue, + volume.DiskWriteBytesPerSec, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.WriteBytesTotal, - prometheus.CounterValue, - volume.DiskWriteBytesPerSec, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.WritesTotal, + prometheus.CounterValue, + volume.DiskWritesPerSec, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.WritesTotal, - prometheus.CounterValue, - volume.DiskWritesPerSec, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.ReadTime, + prometheus.CounterValue, + volume.PercentDiskReadTime, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.ReadTime, - prometheus.CounterValue, - volume.PercentDiskReadTime, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.WriteTime, + prometheus.CounterValue, + volume.PercentDiskWriteTime, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.WriteTime, - prometheus.CounterValue, - volume.PercentDiskWriteTime, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.FreeSpace, + prometheus.GaugeValue, + volume.PercentFreeSpace_Base*1024*1024, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.FreeSpace, - prometheus.GaugeValue, - volume.PercentFreeSpace_Base*1024*1024, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.TotalSpace, + prometheus.GaugeValue, + volume.PercentFreeSpace*1024*1024, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.TotalSpace, - prometheus.GaugeValue, - volume.PercentFreeSpace*1024*1024, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.IdleTime, + prometheus.CounterValue, + volume.PercentIdleTime, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.IdleTime, - prometheus.CounterValue, - volume.PercentIdleTime, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.SplitIOs, + prometheus.CounterValue, + volume.SplitIOPerSec, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.SplitIOs, - prometheus.CounterValue, - volume.SplitIOPerSec, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.ReadLatency, + prometheus.CounterValue, + volume.AvgDiskSecPerRead*perflib.TicksToSecondScaleFactor, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.ReadLatency, - prometheus.CounterValue, - volume.AvgDiskSecPerRead*perflib.TicksToSecondScaleFactor, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.WriteLatency, + prometheus.CounterValue, + volume.AvgDiskSecPerWrite*perflib.TicksToSecondScaleFactor, + volume.Name, + logicalDisk.VolumeName, + ) - ch <- prometheus.MustNewConstMetric( - c.WriteLatency, - prometheus.CounterValue, - volume.AvgDiskSecPerWrite*perflib.TicksToSecondScaleFactor, - volume.Name, - ) + ch <- prometheus.MustNewConstMetric( + c.ReadWriteLatency, + prometheus.CounterValue, + volume.AvgDiskSecPerTransfer*perflib.TicksToSecondScaleFactor, + volume.Name, + logicalDisk.VolumeName, + ) + + break + + } + } - ch <- prometheus.MustNewConstMetric( - c.ReadWriteLatency, - prometheus.CounterValue, - volume.AvgDiskSecPerTransfer*perflib.TicksToSecondScaleFactor, - volume.Name, - ) } return nil, nil