Converted most metrics to non-wmi
Signed-off-by: Ben Ridley <benridley29@gmail.com>
This commit is contained in:
parent
f76334213d
commit
048bff919e
|
@ -4,9 +4,14 @@ package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/StackExchange/wmi"
|
"github.com/StackExchange/wmi"
|
||||||
|
"github.com/prometheus-community/windows_exporter/headers/custom"
|
||||||
|
"github.com/prometheus-community/windows_exporter/headers/netapi32"
|
||||||
|
"github.com/prometheus-community/windows_exporter/headers/psapi"
|
||||||
|
"github.com/prometheus-community/windows_exporter/headers/sysinfoapi"
|
||||||
"github.com/prometheus-community/windows_exporter/log"
|
"github.com/prometheus-community/windows_exporter/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
@ -157,18 +162,30 @@ func (c *OSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, er
|
||||||
return nil, errors.New("WMI query returned empty result set")
|
return nil, errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
product, buildNum := custom.GetProductDetails()
|
||||||
|
|
||||||
|
nwgi, _, err := netapi32.NetWkstaGetInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.OSInformation,
|
c.OSInformation,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
1.0,
|
1.0,
|
||||||
dst[0].Caption,
|
fmt.Sprintf("Microsoft %v", product), // Caption
|
||||||
dst[0].Version,
|
fmt.Sprintf("%v.%v.%v", nwgi.Wki102_ver_major, nwgi.Wki102_ver_minor, buildNum), // Version
|
||||||
)
|
)
|
||||||
|
|
||||||
|
gmse, err := sysinfoapi.GlobalMemoryStatusEx()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.PhysicalMemoryFreeBytes,
|
c.PhysicalMemoryFreeBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].FreePhysicalMemory*1024), // KiB -> bytes
|
float64(gmse.UllAvailPhys),
|
||||||
)
|
)
|
||||||
|
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
|
@ -191,55 +208,71 @@ func (c *OSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, er
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.PagingFreeBytes,
|
c.PagingFreeBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].FreeSpaceInPagingFiles*1024), // KiB -> bytes
|
float64(dst[0].FreeSpaceInPagingFiles*1024),
|
||||||
|
// Cannot find a way to get this without WMI.
|
||||||
|
// Can get from CIM_OperatingSystem which is where WMI gets it from, but I can't figure out how to access this from cimwin32.dll
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/cim-operatingsystem#properties
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.VirtualMemoryFreeBytes,
|
c.VirtualMemoryFreeBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].FreeVirtualMemory*1024), // KiB -> bytes
|
float64(gmse.UllAvailPageFile),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ProcessesLimit,
|
c.ProcessesLimit,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].MaxNumberOfProcesses),
|
float64(4294967295),
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ProcessMemoryLimitBytes,
|
c.ProcessMemoryLimitBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].MaxProcessMemorySize*1024), // KiB -> bytes
|
float64(gmse.UllTotalVirtual),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
gpi, err := psapi.GetLPPerformanceInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.Processes,
|
c.Processes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].NumberOfProcesses),
|
float64(gpi.ProcessCount),
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.Users,
|
c.Users,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].NumberOfUsers),
|
float64(nwgi.Wki102_logged_on_users),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fsipf, err := custom.GetSizeStoredInPagingFiles()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.PagingLimitBytes,
|
c.PagingLimitBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].SizeStoredInPagingFiles*1024), // KiB -> bytes
|
float64(fsipf),
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.VirtualMemoryBytes,
|
c.VirtualMemoryBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].TotalVirtualMemorySize*1024), // KiB -> bytes
|
float64(gmse.UllTotalPageFile),
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.VisibleMemoryBytes,
|
c.VisibleMemoryBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(dst[0].TotalVisibleMemorySize*1024), // KiB -> bytes
|
float64(gmse.UllTotalPhys),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package custom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetSizeStoredInPagingFiles returns the total size of paging files across all discs.
|
||||||
|
func GetSizeStoredInPagingFiles() (int64, error) {
|
||||||
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management`, registry.QUERY_VALUE)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
pagingFiles, _, err := k.GetStringsValue("ExistingPageFiles")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var size int64 = 0
|
||||||
|
for _, pagingFile := range pagingFiles {
|
||||||
|
fileString := strings.ReplaceAll(pagingFile, `\??\`, "")
|
||||||
|
file, err := os.Stat(fileString)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
size += file.Size()
|
||||||
|
}
|
||||||
|
return size, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProductDetails returns the ProductName and CurrentBuildNumber values from the registry.
|
||||||
|
func GetProductDetails() (string, string) {
|
||||||
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
pn, _, err := k.GetStringValue("ProductName")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bn, _, err := k.GetStringValue("CurrentBuildNumber")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := k.Close(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return pn, bn
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
package netapi32
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WKSTAInfo102 is a wrapper of WKSTA_Info_102
|
||||||
|
//https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/ns-lmwksta-wksta_info_102
|
||||||
|
type WKSTAInfo102 struct {
|
||||||
|
Wki102_platform_id uint32
|
||||||
|
wki102_computername *uint16
|
||||||
|
wki102_langroup *uint16
|
||||||
|
Wki102_ver_major uint32
|
||||||
|
Wki102_ver_minor uint32
|
||||||
|
wki102_lanroot *uint16
|
||||||
|
Wki102_logged_on_users uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
netapi32 = windows.NewLazySystemDLL("netapi32")
|
||||||
|
procNetWkstaGetInfo = netapi32.NewProc("NetWkstaGetInfo")
|
||||||
|
procNetApiBufferFree = netapi32.NewProc("NetApiBufferFree")
|
||||||
|
)
|
||||||
|
|
||||||
|
// NetApiStatus is a map of Network Management Error Codes.
|
||||||
|
// https://docs.microsoft.com/en-gb/windows/win32/netmgmt/network-management-error-codes?redirectedfrom=MSDN
|
||||||
|
var NetApiStatus = map[uint32]string{
|
||||||
|
// Success
|
||||||
|
0: "NERR_Success",
|
||||||
|
// This computer name is invalid.
|
||||||
|
2351: "NERR_InvalidComputer",
|
||||||
|
// This operation is only allowed on the primary domain controller of the domain.
|
||||||
|
2226: "NERR_NotPrimary",
|
||||||
|
/// This operation is not allowed on this special group.
|
||||||
|
2234: "NERR_SpeGroupOp",
|
||||||
|
/// This operation is not allowed on the last administrative account.
|
||||||
|
2452: "NERR_LastAdmin",
|
||||||
|
/// The password parameter is invalid.
|
||||||
|
2203: "NERR_BadPassword",
|
||||||
|
/// The password does not meet the password policy requirements.
|
||||||
|
/// Check the minimum password length, password complexity and password history requirements.
|
||||||
|
2245: "NERR_PasswordTooShort",
|
||||||
|
/// The user name could not be found.
|
||||||
|
2221: "NERR_UserNotFound",
|
||||||
|
// Errors
|
||||||
|
5: "ERROR_ACCESS_DENIED",
|
||||||
|
8: "ERROR_NOT_ENOUGH_MEMORY",
|
||||||
|
87: "ERROR_INVALID_PARAMETER",
|
||||||
|
123: "ERROR_INVALID_NAME",
|
||||||
|
124: "ERROR_INVALID_LEVEL",
|
||||||
|
234: "ERROR_MORE_DATA",
|
||||||
|
1219: "ERROR_SESSION_CREDENTIAL_CONFLICT",
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetApiBufferFree frees the memory other network management functions use internally to return information.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/lmapibuf/nf-lmapibuf-netapibufferfree
|
||||||
|
func NetApiBufferFree(buffer *WKSTAInfo102) {
|
||||||
|
procNetApiBufferFree.Call(uintptr(unsafe.Pointer(buffer)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetWkstaGetInfo returns information about the configuration of a workstation.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo
|
||||||
|
func NetWkstaGetInfo() (WKSTAInfo102, uint32, error) {
|
||||||
|
// Struct
|
||||||
|
var lpwi *WKSTAInfo102
|
||||||
|
pLpwi := uintptr(unsafe.Pointer(&lpwi))
|
||||||
|
|
||||||
|
// Null value
|
||||||
|
var nullptr = uintptr(0)
|
||||||
|
|
||||||
|
// Level
|
||||||
|
pLevel := uintptr(102)
|
||||||
|
|
||||||
|
// Func call
|
||||||
|
r1, _, _ := procNetWkstaGetInfo.Call(nullptr, pLevel, pLpwi)
|
||||||
|
|
||||||
|
if ret := *(*uint32)(unsafe.Pointer(&r1)); ret != 0 {
|
||||||
|
return WKSTAInfo102{}, ret, errors.New(NetApiStatus[ret])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derence the pointer and return the object so we can safely clear the buffer.
|
||||||
|
var deref WKSTAInfo102 = *lpwi
|
||||||
|
defer NetApiBufferFree(lpwi)
|
||||||
|
|
||||||
|
return deref, 0, nil
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package psapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LPPerformanceInformation is a wrapper of the PERFORMANCE_INFORMATION struct.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-performance_information
|
||||||
|
type LPPerformanceInformation struct {
|
||||||
|
cb uint32
|
||||||
|
CommitTotal *uint32
|
||||||
|
CommitLimit *uint32
|
||||||
|
CommitPeak *uint32
|
||||||
|
PhysicalTotal *uint32
|
||||||
|
PhysicalAvailable *uint32
|
||||||
|
SystemCache *uint32
|
||||||
|
KernelTotal *uint32
|
||||||
|
KernelPaged *uint32
|
||||||
|
KernelNonpaged *uint32
|
||||||
|
PageSize *uint32
|
||||||
|
HandleCount uint32
|
||||||
|
ProcessCount uint32
|
||||||
|
ThreadCount uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// PerformanceInformation is a dereferenced version of LPPerformanceInformation
|
||||||
|
type PerformanceInformation struct {
|
||||||
|
cb uint32
|
||||||
|
CommitTotal uint32
|
||||||
|
CommitLimit uint32
|
||||||
|
CommitPeak uint32
|
||||||
|
PhysicalTotal uint32
|
||||||
|
PhysicalAvailable uint32
|
||||||
|
SystemCache uint32
|
||||||
|
KernelTotal uint32
|
||||||
|
KernelPaged uint32
|
||||||
|
KernelNonpaged uint32
|
||||||
|
PageSize uint32
|
||||||
|
HandleCount uint32
|
||||||
|
ProcessCount uint32
|
||||||
|
ThreadCount uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
psapi = windows.NewLazySystemDLL("psapi.dll")
|
||||||
|
procGetPerformanceInfo = psapi.NewProc("GetPerformanceInfo")
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetLPPerformanceInfo retrieves the performance values contained in the LPPerformanceInformation structure.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getperformanceinfo
|
||||||
|
func GetLPPerformanceInfo() (LPPerformanceInformation, error) {
|
||||||
|
var pi LPPerformanceInformation
|
||||||
|
size := (uint32)(unsafe.Sizeof(pi))
|
||||||
|
pi.cb = size
|
||||||
|
pPi := uintptr(unsafe.Pointer(&pi))
|
||||||
|
r1, _, err := procGetPerformanceInfo.Call(pPi, uintptr(size))
|
||||||
|
|
||||||
|
if ret := *(*bool)(unsafe.Pointer(&r1)); ret == false {
|
||||||
|
// returned false
|
||||||
|
return LPPerformanceInformation{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pi, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPerformanceInfo returns the dereferenced version of GetLPPerformanceInfo.
|
||||||
|
func GetPerformanceInfo() (PerformanceInformation, error) {
|
||||||
|
var lppi LPPerformanceInformation
|
||||||
|
size := (uint32)(unsafe.Sizeof(lppi))
|
||||||
|
lppi.cb = size
|
||||||
|
pLppi := uintptr(unsafe.Pointer(&lppi))
|
||||||
|
r1, _, err := procGetPerformanceInfo.Call(pLppi, uintptr(size))
|
||||||
|
|
||||||
|
if ret := *(*bool)(unsafe.Pointer(&r1)); ret == false {
|
||||||
|
// returned false
|
||||||
|
return PerformanceInformation{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pi PerformanceInformation
|
||||||
|
pi.cb = lppi.cb
|
||||||
|
pi.CommitTotal = *(*uint32)(unsafe.Pointer(&lppi.CommitTotal))
|
||||||
|
pi.CommitLimit = *(*uint32)(unsafe.Pointer(&lppi.CommitLimit))
|
||||||
|
pi.CommitPeak = *(*uint32)(unsafe.Pointer(&lppi.CommitPeak))
|
||||||
|
pi.PhysicalTotal = *(*uint32)(unsafe.Pointer(&lppi.PhysicalTotal))
|
||||||
|
pi.PhysicalAvailable = *(*uint32)(unsafe.Pointer(&lppi.PhysicalAvailable))
|
||||||
|
pi.SystemCache = *(*uint32)(unsafe.Pointer(&lppi.SystemCache))
|
||||||
|
pi.KernelTotal = *(*uint32)(unsafe.Pointer(&lppi.KernelTotal))
|
||||||
|
pi.KernelPaged = *(*uint32)(unsafe.Pointer(&lppi.KernelPaged))
|
||||||
|
pi.KernelNonpaged = *(*uint32)(unsafe.Pointer(&lppi.KernelNonpaged))
|
||||||
|
pi.PageSize = *(*uint32)(unsafe.Pointer(&lppi.PageSize))
|
||||||
|
pi.HandleCount = lppi.HandleCount
|
||||||
|
pi.ProcessCount = lppi.ProcessCount
|
||||||
|
pi.ThreadCount = lppi.ThreadCount
|
||||||
|
|
||||||
|
return pi, nil
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package sysinfoapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MemoryStatusEx is a wrapper for MEMORYSTATUSEX
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
|
||||||
|
type MemoryStatusEx struct {
|
||||||
|
dwLength uint32
|
||||||
|
DwMemoryLoad uint32
|
||||||
|
UllTotalPhys uint64
|
||||||
|
UllAvailPhys uint64
|
||||||
|
UllTotalPageFile uint64
|
||||||
|
UllAvailPageFile uint64
|
||||||
|
UllTotalVirtual uint64
|
||||||
|
UllAvailVirtual uint64
|
||||||
|
UllAvailExtendedVirtual uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
procGetSystemInfo = kernel32.NewProc("GetSystemInfo")
|
||||||
|
procGlobalMemoryStatusEx = kernel32.NewProc("GlobalMemoryStatusEx")
|
||||||
|
)
|
||||||
|
|
||||||
|
// GlobalMemoryStatusEx retrieves information about the system's current usage of both physical and virtual memory.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex
|
||||||
|
func GlobalMemoryStatusEx() (MemoryStatusEx, error) {
|
||||||
|
var mse MemoryStatusEx
|
||||||
|
mse.dwLength = (uint32)(unsafe.Sizeof(mse))
|
||||||
|
pMse := uintptr(unsafe.Pointer(&mse))
|
||||||
|
r1, _, err := procGlobalMemoryStatusEx.Call(pMse)
|
||||||
|
|
||||||
|
if ret := *(*bool)(unsafe.Pointer(&r1)); ret == false {
|
||||||
|
// returned false
|
||||||
|
return MemoryStatusEx{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mse, nil
|
||||||
|
}
|
Loading…
Reference in New Issue