2022-11-16 17:11:10 +00:00
//go:build windows
// +build windows
package collector
import (
"errors"
"strings"
"github.com/prometheus-community/windows_exporter/log"
"github.com/prometheus/client_golang/prometheus"
2023-03-12 00:27:31 +00:00
"github.com/yusufpapurcu/wmi"
2022-11-16 17:11:10 +00:00
)
const (
2022-11-16 17:50:42 +00:00
win32DiskQuery = "SELECT DeviceID, Model, Caption, Name, Partitions, Size, Status, Availability FROM WIN32_DiskDrive"
2022-11-16 17:11:10 +00:00
)
// A DiskDriveInfoCollector is a Prometheus collector for a few WMI metrics in Win32_DiskDrive
type DiskDriveInfoCollector struct {
DiskInfo * prometheus . Desc
Status * prometheus . Desc
Size * prometheus . Desc
Partitions * prometheus . Desc
Availability * prometheus . Desc
}
func newDiskDriveInfoCollector ( ) ( Collector , error ) {
2023-04-02 20:16:31 +00:00
const subsystem = "diskdrive"
2022-11-16 17:11:10 +00:00
return & DiskDriveInfoCollector {
DiskInfo : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "info" ) ,
"General drive information" ,
[ ] string {
"device_id" ,
"model" ,
"caption" ,
2022-11-16 17:50:42 +00:00
"name" ,
2022-11-16 17:11:10 +00:00
} ,
nil ,
) ,
Status : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "status" ) ,
"Status of the drive" ,
[ ] string {
"name" , "status" } ,
nil ,
) ,
Size : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "size" ) ,
"Size of the disk drive. It is calculated by multiplying the total number of cylinders, tracks in each cylinder, sectors in each track, and bytes in each sector." ,
2022-11-18 19:57:21 +00:00
[ ] string { "name" } ,
2022-11-16 17:11:10 +00:00
nil ,
) ,
Partitions : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "partitions" ) ,
"Number of partitions" ,
2022-11-18 19:57:21 +00:00
[ ] string { "name" } ,
2022-11-16 17:11:10 +00:00
nil ,
) ,
Availability : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "availability" ) ,
"Availability Status" ,
[ ] string {
"name" , "availability" } ,
nil ,
) ,
} , nil
}
type Win32_DiskDrive struct {
DeviceID string
Model string
Size uint64
2022-11-16 17:50:42 +00:00
Name string
2022-11-16 17:11:10 +00:00
Caption string
Partitions uint32
Status string
Availability uint16
}
var (
allDiskStatus = [ ] string {
"OK" ,
"Error" ,
"Degraded" ,
"Unknown" ,
"Pred fail" ,
"Starting" ,
"Stopping" ,
"Service" ,
"Stressed" ,
"Nonrecover" ,
"No Contact" ,
"Lost Comm" ,
}
availMap = map [ int ] string {
1 : "Other" ,
2 : "Unknown" ,
3 : "Running / Full Power" ,
4 : "Warning" ,
5 : "In Test" ,
6 : "Not Applicable" ,
7 : "Power Off" ,
8 : "Off line" ,
9 : "Off Duty" ,
10 : "Degraded" ,
11 : "Not Installed" ,
12 : "Install Error" ,
13 : "Power Save - Unknown" ,
14 : "Power Save - Low Power Mode" ,
15 : "Power Save - Standby" ,
16 : "Power Cycle" ,
17 : "Power Save - Warning" ,
18 : "Paused" ,
19 : "Not Ready" ,
20 : "Not Configured" ,
21 : "Quiesced" ,
}
)
// Collect sends the metric values for each metric to the provided prometheus Metric channel.
func ( c * DiskDriveInfoCollector ) Collect ( ctx * ScrapeContext , ch chan <- prometheus . Metric ) error {
if desc , err := c . collect ( ch ) ; err != nil {
log . Error ( "failed collecting disk_drive_info metrics:" , desc , err )
return err
}
return nil
}
func ( c * DiskDriveInfoCollector ) collect ( ch chan <- prometheus . Metric ) ( * prometheus . Desc , error ) {
var dst [ ] Win32_DiskDrive
if err := wmi . Query ( win32DiskQuery , & dst ) ; err != nil {
return nil , err
}
if len ( dst ) == 0 {
return nil , errors . New ( "WMI query returned empty result set" )
}
2022-11-18 20:01:46 +00:00
for _ , disk := range dst {
2022-11-16 17:11:10 +00:00
ch <- prometheus . MustNewConstMetric (
c . DiskInfo ,
prometheus . GaugeValue ,
1.0 ,
2022-11-18 20:01:46 +00:00
strings . Trim ( disk . DeviceID , "\\.\\" ) ,
strings . TrimRight ( disk . Model , " " ) ,
strings . TrimRight ( disk . Caption , " " ) ,
strings . TrimRight ( disk . Name , "\\.\\" ) ,
2022-11-16 17:11:10 +00:00
)
for _ , status := range allDiskStatus {
isCurrentState := 0.0
2022-11-18 20:01:46 +00:00
if status == disk . Status {
2022-11-16 17:11:10 +00:00
isCurrentState = 1.0
}
ch <- prometheus . MustNewConstMetric (
c . Status ,
prometheus . GaugeValue ,
isCurrentState ,
2022-11-18 20:01:46 +00:00
strings . Trim ( disk . Name , "\\.\\" ) ,
2022-11-16 17:11:10 +00:00
status ,
)
}
ch <- prometheus . MustNewConstMetric (
c . Size ,
2022-11-18 20:01:46 +00:00
prometheus . GaugeValue ,
float64 ( disk . Size ) ,
strings . Trim ( disk . Name , "\\.\\" ) ,
2022-11-16 17:11:10 +00:00
)
ch <- prometheus . MustNewConstMetric (
c . Partitions ,
2022-11-18 20:01:46 +00:00
prometheus . GaugeValue ,
float64 ( disk . Partitions ) ,
strings . Trim ( disk . Name , "\\.\\" ) ,
2022-11-16 17:11:10 +00:00
)
for availNum , val := range availMap {
isCurrentState := 0.0
2022-11-18 20:01:46 +00:00
if availNum == int ( disk . Availability ) {
2022-11-16 17:11:10 +00:00
isCurrentState = 1.0
}
ch <- prometheus . MustNewConstMetric (
c . Availability ,
prometheus . GaugeValue ,
isCurrentState ,
2022-11-18 20:01:46 +00:00
strings . Trim ( disk . Name , "\\.\\" ) ,
2022-11-16 17:11:10 +00:00
val ,
)
}
}
return nil , nil
}