2021-12-18 18:01:29 +00:00
//go:build windows
2018-11-30 00:51:12 +00:00
// +build windows
2016-09-01 12:55:35 +00:00
package collector
2016-08-26 06:59:27 +00:00
import (
2021-01-13 00:23:40 +00:00
"fmt"
2021-01-15 05:38:52 +00:00
"os"
2021-01-15 04:08:33 +00:00
"strings"
2017-03-31 05:56:42 +00:00
"time"
2018-04-05 05:11:36 +00:00
2023-04-22 10:17:51 +00:00
"github.com/go-kit/log"
"github.com/go-kit/log/level"
2021-01-13 00:23:40 +00:00
"github.com/prometheus-community/windows_exporter/headers/netapi32"
"github.com/prometheus-community/windows_exporter/headers/psapi"
"github.com/prometheus-community/windows_exporter/headers/sysinfoapi"
2016-08-26 06:59:27 +00:00
"github.com/prometheus/client_golang/prometheus"
2021-01-15 05:38:52 +00:00
"golang.org/x/sys/windows/registry"
2016-08-26 06:59:27 +00:00
)
2016-09-19 07:02:05 +00:00
// A OSCollector is a Prometheus collector for WMI metrics
2016-08-26 06:59:27 +00:00
type OSCollector struct {
2023-04-22 10:17:51 +00:00
logger log . Logger
2019-10-01 16:54:50 +00:00
OSInformation * prometheus . Desc
2016-08-26 12:19:08 +00:00
PhysicalMemoryFreeBytes * prometheus . Desc
PagingFreeBytes * prometheus . Desc
VirtualMemoryFreeBytes * prometheus . Desc
2016-09-19 07:02:05 +00:00
ProcessesLimit * prometheus . Desc
ProcessMemoryLimitBytes * prometheus . Desc
2016-08-26 12:19:08 +00:00
Processes * prometheus . Desc
Users * prometheus . Desc
2016-09-19 07:02:05 +00:00
PagingLimitBytes * prometheus . Desc
2016-08-26 12:19:08 +00:00
VirtualMemoryBytes * prometheus . Desc
VisibleMemoryBytes * prometheus . Desc
2018-04-05 05:11:36 +00:00
Time * prometheus . Desc
Timezone * prometheus . Desc
2016-08-26 06:59:27 +00:00
}
2021-01-15 04:08:33 +00:00
type pagingFileCounter struct {
Name string
Usage float64 ` perflib:"% Usage" `
UsagePeak float64 ` perflib:"% Usage Peak" `
}
2022-12-21 05:44:29 +00:00
// newOSCollector ...
2023-04-22 10:17:51 +00:00
func newOSCollector ( logger log . Logger ) ( Collector , error ) {
2016-09-01 14:04:43 +00:00
const subsystem = "os"
2016-08-26 06:59:27 +00:00
return & OSCollector {
2023-04-22 10:17:51 +00:00
logger : log . With ( logger , "collector" , subsystem ) ,
2019-10-01 16:54:50 +00:00
OSInformation : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "info" ) ,
"OperatingSystem.Caption, OperatingSystem.Version" ,
2022-08-30 05:01:06 +00:00
[ ] string { "product" , "version" , "major_version" , "minor_version" , "build_number" } ,
2019-10-01 16:54:50 +00:00
nil ,
) ,
2016-09-19 07:02:05 +00:00
PagingLimitBytes : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "paging_limit_bytes" ) ,
"OperatingSystem.SizeStoredInPagingFiles" ,
2016-08-26 06:59:27 +00:00
nil ,
nil ,
) ,
2016-08-26 12:19:08 +00:00
PagingFreeBytes : prometheus . NewDesc (
2016-09-01 14:04:43 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "paging_free_bytes" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.FreeSpaceInPagingFiles" ,
2016-08-26 06:59:27 +00:00
nil ,
nil ,
) ,
2016-08-26 12:19:08 +00:00
PhysicalMemoryFreeBytes : prometheus . NewDesc (
2016-09-01 14:04:43 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "physical_memory_free_bytes" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.FreePhysicalMemory" ,
2016-08-26 06:59:27 +00:00
nil ,
nil ,
) ,
2017-03-31 05:56:42 +00:00
Time : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "time" ) ,
"OperatingSystem.LocalDateTime" ,
nil ,
nil ,
) ,
Timezone : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "timezone" ) ,
"OperatingSystem.LocalDateTime" ,
[ ] string { "timezone" } ,
nil ,
) ,
2016-08-26 12:19:08 +00:00
Processes : prometheus . NewDesc (
2016-09-01 14:04:43 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "processes" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.NumberOfProcesses" ,
2016-08-26 08:23:41 +00:00
nil ,
nil ,
) ,
2016-09-19 07:02:05 +00:00
ProcessesLimit : prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "processes_limit" ) ,
"OperatingSystem.MaxNumberOfProcesses" ,
2016-08-26 08:23:41 +00:00
nil ,
nil ,
) ,
2016-09-19 07:02:05 +00:00
ProcessMemoryLimitBytes : prometheus . NewDesc (
2021-06-15 10:38:23 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "process_memory_limit_bytes" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.MaxProcessMemorySize" ,
2016-08-26 06:59:27 +00:00
nil ,
nil ,
) ,
2016-08-26 09:35:31 +00:00
Users : prometheus . NewDesc (
2016-09-01 14:04:43 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "users" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.NumberOfUsers" ,
2016-08-26 07:29:03 +00:00
nil ,
nil ,
) ,
2016-08-26 12:19:08 +00:00
VirtualMemoryBytes : prometheus . NewDesc (
2016-09-01 14:04:43 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "virtual_memory_bytes" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.TotalVirtualMemorySize" ,
2016-08-26 07:29:03 +00:00
nil ,
nil ,
) ,
2016-08-26 12:19:08 +00:00
VisibleMemoryBytes : prometheus . NewDesc (
2016-09-01 14:04:43 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "visible_memory_bytes" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.TotalVisibleMemorySize" ,
2016-08-26 07:29:03 +00:00
nil ,
nil ,
) ,
2016-08-26 12:19:08 +00:00
VirtualMemoryFreeBytes : prometheus . NewDesc (
2016-09-01 14:04:43 +00:00
prometheus . BuildFQName ( Namespace , subsystem , "virtual_memory_free_bytes" ) ,
2016-09-19 07:02:05 +00:00
"OperatingSystem.FreeVirtualMemory" ,
2016-08-26 06:59:27 +00:00
nil ,
nil ,
) ,
2016-09-01 14:04:43 +00:00
} , nil
2016-08-26 06:59:27 +00:00
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
2019-04-05 13:59:40 +00:00
func ( c * OSCollector ) Collect ( ctx * ScrapeContext , ch chan <- prometheus . Metric ) error {
2021-01-15 04:08:33 +00:00
if desc , err := c . collect ( ctx , ch ) ; err != nil {
2023-06-08 00:29:50 +00:00
_ = level . Error ( c . logger ) . Log ( "failed collecting os metrics" , "desc" , desc , "err" , err )
2016-09-01 14:04:43 +00:00
return err
2016-08-26 06:59:27 +00:00
}
2016-09-01 14:04:43 +00:00
return nil
2016-08-26 06:59:27 +00:00
}
2018-10-04 19:35:33 +00:00
// Win32_OperatingSystem docs:
// - https://msdn.microsoft.com/en-us/library/aa394239 - Win32_OperatingSystem class
2016-08-26 06:59:27 +00:00
type Win32_OperatingSystem struct {
2019-10-01 16:54:50 +00:00
Caption string
2016-08-26 07:29:03 +00:00
FreePhysicalMemory uint64
FreeSpaceInPagingFiles uint64
FreeVirtualMemory uint64
2019-10-01 16:54:50 +00:00
LocalDateTime time . Time
2016-08-26 08:23:41 +00:00
MaxNumberOfProcesses uint32
MaxProcessMemorySize uint64
2016-08-26 07:29:03 +00:00
NumberOfProcesses uint32
NumberOfUsers uint32
SizeStoredInPagingFiles uint64
TotalVirtualMemorySize uint64
TotalVisibleMemorySize uint64
2019-10-01 16:54:50 +00:00
Version string
2016-08-26 06:59:27 +00:00
}
2021-01-15 04:08:33 +00:00
func ( c * OSCollector ) collect ( ctx * ScrapeContext , ch chan <- prometheus . Metric ) ( * prometheus . Desc , error ) {
2021-03-03 04:35:04 +00:00
nwgi , err := netapi32 . GetWorkstationInfo ( )
2021-01-15 05:38:52 +00:00
if err != nil {
2016-08-26 06:59:27 +00:00
return nil , err
}
2021-01-15 05:38:52 +00:00
gmse , err := sysinfoapi . GlobalMemoryStatusEx ( )
if err != nil {
return nil , err
}
2018-08-07 19:42:16 +00:00
2021-01-15 05:38:52 +00:00
currentTime := time . Now ( )
timezoneName , _ := currentTime . Zone ( )
2021-01-13 00:23:40 +00:00
2021-01-15 05:38:52 +00:00
// Get total allocation of paging files across all disks.
memManKey , err := registry . OpenKey ( registry . LOCAL_MACHINE , ` SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management ` , registry . QUERY_VALUE )
2021-03-29 17:12:20 +00:00
defer memManKey . Close ( )
2021-01-15 05:38:52 +00:00
if err != nil {
return nil , err
}
2022-03-16 03:20:19 +00:00
pagingFiles , _ , pagingErr := memManKey . GetStringsValue ( "ExistingPageFiles" )
2021-01-15 05:38:52 +00:00
// Get build number and product name from registry
ntKey , err := registry . OpenKey ( registry . LOCAL_MACHINE , ` SOFTWARE\Microsoft\Windows NT\CurrentVersion ` , registry . QUERY_VALUE )
2021-03-29 17:12:20 +00:00
defer ntKey . Close ( )
2021-01-15 05:38:52 +00:00
if err != nil {
return nil , err
}
2021-03-29 17:12:20 +00:00
2021-01-15 05:38:52 +00:00
pn , _ , err := ntKey . GetStringValue ( "ProductName" )
if err != nil {
return nil , err
}
bn , _ , err := ntKey . GetStringValue ( "CurrentBuildNumber" )
if err != nil {
return nil , err
}
2021-12-18 18:30:47 +00:00
var fsipf float64
2021-01-15 05:38:52 +00:00
for _ , pagingFile := range pagingFiles {
fileString := strings . ReplaceAll ( pagingFile , ` \??\ ` , "" )
file , err := os . Stat ( fileString )
2022-12-16 11:57:44 +00:00
// For unknown reasons, Windows doesn't always create a page file. Continue collection rather than aborting.
2021-01-15 05:38:52 +00:00
if err != nil {
2023-06-08 00:29:50 +00:00
_ = level . Debug ( c . logger ) . Log ( "msg" , fmt . Sprintf ( "Failed to read page file (reason: %s): %s\n" , err , fileString ) )
2022-12-16 11:57:44 +00:00
} else {
fsipf += float64 ( file . Size ( ) )
2021-01-15 05:38:52 +00:00
}
}
gpi , err := psapi . GetPerformanceInfo ( )
if err != nil {
return nil , err
}
var pfc = make ( [ ] pagingFileCounter , 0 )
2023-04-22 10:17:51 +00:00
if err := unmarshalObject ( ctx . perfObjects [ "Paging File" ] , & pfc , c . logger ) ; err != nil {
2021-01-15 05:38:52 +00:00
return nil , err
}
// Get current page file usage.
2021-12-18 18:30:47 +00:00
var pfbRaw float64
2021-01-15 05:38:52 +00:00
for _ , pageFile := range pfc {
if strings . Contains ( strings . ToLower ( pageFile . Name ) , "_total" ) {
continue
}
pfbRaw += pageFile . Usage
}
// Subtract from total page file allocation on disk.
pfb := fsipf - ( pfbRaw * float64 ( gpi . PageSize ) )
2019-10-01 16:54:50 +00:00
ch <- prometheus . MustNewConstMetric (
c . OSInformation ,
prometheus . GaugeValue ,
1.0 ,
2021-01-15 05:38:52 +00:00
fmt . Sprintf ( "Microsoft %s" , pn ) , // Caption
2021-03-03 04:35:04 +00:00
fmt . Sprintf ( "%d.%d.%s" , nwgi . VersionMajor , nwgi . VersionMinor , bn ) , // Version
2022-08-30 05:01:06 +00:00
fmt . Sprintf ( "%d" , nwgi . VersionMajor ) , // Major Version
fmt . Sprintf ( "%d" , nwgi . VersionMinor ) , // Minor Version
bn , // Build number
2019-10-01 16:54:50 +00:00
)
2016-08-26 06:59:27 +00:00
ch <- prometheus . MustNewConstMetric (
2016-08-26 12:19:08 +00:00
c . PhysicalMemoryFreeBytes ,
2016-08-26 06:59:27 +00:00
prometheus . GaugeValue ,
2021-03-03 04:35:04 +00:00
float64 ( gmse . AvailPhys ) ,
2016-08-26 06:59:27 +00:00
)
2017-03-31 05:56:42 +00:00
ch <- prometheus . MustNewConstMetric (
c . Time ,
prometheus . GaugeValue ,
2020-12-21 06:11:11 +00:00
float64 ( currentTime . Unix ( ) ) ,
2017-03-31 05:56:42 +00:00
)
ch <- prometheus . MustNewConstMetric (
c . Timezone ,
prometheus . GaugeValue ,
1.0 ,
timezoneName ,
)
2022-03-16 03:20:19 +00:00
if pagingErr == nil {
ch <- prometheus . MustNewConstMetric (
c . PagingFreeBytes ,
prometheus . GaugeValue ,
pfb ,
)
ch <- prometheus . MustNewConstMetric (
c . PagingLimitBytes ,
prometheus . GaugeValue ,
fsipf ,
)
} else {
2023-06-08 00:29:50 +00:00
_ = level . Debug ( c . logger ) . Log ( "Could not find HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management key. windows_os_paging_free_bytes and windows_os_paging_limit_bytes will be omitted." )
2022-03-16 03:20:19 +00:00
}
2016-08-26 06:59:27 +00:00
ch <- prometheus . MustNewConstMetric (
2016-08-26 12:19:08 +00:00
c . VirtualMemoryFreeBytes ,
2016-08-26 06:59:27 +00:00
prometheus . GaugeValue ,
2021-03-03 04:35:04 +00:00
float64 ( gmse . AvailPageFile ) ,
2016-08-26 06:59:27 +00:00
)
2021-01-13 00:23:40 +00:00
// Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value.
// https://techcommunity.microsoft.com/t5/windows-blog-archive/pushing-the-limits-of-windows-processes-and-threads/ba-p/723824
// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-operatingsystem
2016-08-26 08:23:41 +00:00
ch <- prometheus . MustNewConstMetric (
2016-09-19 07:02:05 +00:00
c . ProcessesLimit ,
2016-08-26 08:23:41 +00:00
prometheus . GaugeValue ,
2021-01-13 00:23:40 +00:00
float64 ( 4294967295 ) ,
2016-08-26 08:23:41 +00:00
)
ch <- prometheus . MustNewConstMetric (
2016-09-19 07:02:05 +00:00
c . ProcessMemoryLimitBytes ,
2016-08-26 08:23:41 +00:00
prometheus . GaugeValue ,
2021-03-03 04:35:04 +00:00
float64 ( gmse . TotalVirtual ) ,
2016-08-26 08:23:41 +00:00
)
2016-08-26 06:59:27 +00:00
ch <- prometheus . MustNewConstMetric (
2016-08-26 09:35:31 +00:00
c . Processes ,
2016-08-26 06:59:27 +00:00
prometheus . GaugeValue ,
2021-01-13 00:23:40 +00:00
float64 ( gpi . ProcessCount ) ,
2016-08-26 06:59:27 +00:00
)
ch <- prometheus . MustNewConstMetric (
2016-08-26 09:35:31 +00:00
c . Users ,
2016-08-26 06:59:27 +00:00
prometheus . GaugeValue ,
2021-03-03 04:35:04 +00:00
float64 ( nwgi . LoggedOnUsers ) ,
2016-08-26 06:59:27 +00:00
)
2016-08-26 07:29:03 +00:00
ch <- prometheus . MustNewConstMetric (
2016-08-26 12:19:08 +00:00
c . VirtualMemoryBytes ,
2016-08-26 07:29:03 +00:00
prometheus . GaugeValue ,
2021-03-03 04:35:04 +00:00
float64 ( gmse . TotalPageFile ) ,
2016-08-26 07:29:03 +00:00
)
ch <- prometheus . MustNewConstMetric (
2016-08-26 12:19:08 +00:00
c . VisibleMemoryBytes ,
2016-08-26 07:29:03 +00:00
prometheus . GaugeValue ,
2021-03-03 04:35:04 +00:00
float64 ( gmse . TotalPhys ) ,
2016-08-26 07:29:03 +00:00
)
2016-08-26 06:59:27 +00:00
return nil , nil
}