Add idiomatic wrappers to be exposed publically, and hide low-level

WinAPI operations

Signed-off-by: Ben Ridley <benridley29@gmail.com>
This commit is contained in:
Ben Ridley 2021-03-03 15:35:04 +11:00
parent d947d0f6db
commit 05f0f6f688
4 changed files with 126 additions and 46 deletions

View File

@ -72,13 +72,13 @@ func (c *CSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, er
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.LogicalProcessors, c.LogicalProcessors,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(systemInfo.DwNumberOfProcessors), float64(systemInfo.NumberOfProcessors),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.PhysicalMemoryBytes, c.PhysicalMemoryBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(mem.UllTotalPhys), float64(mem.TotalPhys),
) )
hostname, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSHostname) hostname, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSHostname)

View File

@ -158,7 +158,7 @@ type Win32_OperatingSystem struct {
} }
func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (*prometheus.Desc, error) { func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
nwgi, _, err := netapi32.NetWkstaGetInfo() nwgi, err := netapi32.GetWorkstationInfo()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -241,13 +241,13 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (
prometheus.GaugeValue, prometheus.GaugeValue,
1.0, 1.0,
fmt.Sprintf("Microsoft %s", pn), // Caption fmt.Sprintf("Microsoft %s", pn), // Caption
fmt.Sprintf("%d.%d.%s", nwgi.Wki102_ver_major, nwgi.Wki102_ver_minor, bn), // Version fmt.Sprintf("%d.%d.%s", nwgi.VersionMajor, nwgi.VersionMinor, bn), // Version
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.PhysicalMemoryFreeBytes, c.PhysicalMemoryFreeBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(gmse.UllAvailPhys), float64(gmse.AvailPhys),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
@ -272,7 +272,7 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.VirtualMemoryFreeBytes, c.VirtualMemoryFreeBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(gmse.UllAvailPageFile), float64(gmse.AvailPageFile),
) )
// Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value. // Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value.
@ -287,7 +287,7 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ProcessMemoryLimitBytes, c.ProcessMemoryLimitBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(gmse.UllTotalVirtual), float64(gmse.TotalVirtual),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
@ -299,7 +299,7 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.Users, c.Users,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(nwgi.Wki102_logged_on_users), float64(nwgi.LoggedOnUsers),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
@ -311,13 +311,13 @@ func (c *OSCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.VirtualMemoryBytes, c.VirtualMemoryBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(gmse.UllTotalPageFile), float64(gmse.TotalPageFile),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.VisibleMemoryBytes, c.VisibleMemoryBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(gmse.UllTotalPhys), float64(gmse.TotalPhys),
) )
return nil, nil return nil, nil

View File

@ -9,14 +9,25 @@ import (
// WKSTAInfo102 is a wrapper of WKSTA_Info_102 // WKSTAInfo102 is a wrapper of WKSTA_Info_102
//https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/ns-lmwksta-wksta_info_102 //https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/ns-lmwksta-wksta_info_102
type WKSTAInfo102 struct { type wKSTAInfo102 struct {
Wki102_platform_id uint32 wki102_platform_id uint32
wki102_computername *uint16 wki102_computername *uint16
wki102_langroup *uint16 wki102_langroup *uint16
Wki102_ver_major uint32 wki102_ver_major uint32
Wki102_ver_minor uint32 wki102_ver_minor uint32
wki102_lanroot *uint16 wki102_lanroot *uint16
Wki102_logged_on_users uint32 wki102_logged_on_users uint32
}
// WorkstationInfo is an idiomatic wrapper of WKSTAInfo102
type WorkstationInfo struct {
PlatformId uint32
ComputerName string
LanGroup string
VersionMajor uint32
VersionMinor uint32
LanRoot string
LoggedOnUsers uint32
} }
var ( var (
@ -57,33 +68,42 @@ var NetApiStatus = map[uint32]string{
// NetApiBufferFree frees the memory other network management functions use internally to return information. // 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 // https://docs.microsoft.com/en-us/windows/win32/api/lmapibuf/nf-lmapibuf-netapibufferfree
func NetApiBufferFree(buffer *WKSTAInfo102) { func netApiBufferFree(buffer *wKSTAInfo102) {
procNetApiBufferFree.Call(uintptr(unsafe.Pointer(buffer))) procNetApiBufferFree.Call(uintptr(unsafe.Pointer(buffer)))
} }
// NetWkstaGetInfo returns information about the configuration of a workstation. // NetWkstaGetInfo returns information about the configuration of a workstation.
// WARNING: The caller must call netApiBufferFree to free the memory allocated by this function.
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo // https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo
func NetWkstaGetInfo() (WKSTAInfo102, uint32, error) { func netWkstaGetInfo() (*wKSTAInfo102, uint32, error) {
// Struct var lpwi *wKSTAInfo102
var lpwi *WKSTAInfo102
pLpwi := uintptr(unsafe.Pointer(&lpwi))
// Null value
var nullptr = uintptr(0)
// Level
pLevel := uintptr(102) pLevel := uintptr(102)
// Func call r1, _, _ := procNetWkstaGetInfo.Call(0, pLevel, uintptr(unsafe.Pointer(&lpwi)))
r1, _, _ := procNetWkstaGetInfo.Call(nullptr, pLevel, pLpwi)
if ret := *(*uint32)(unsafe.Pointer(&r1)); ret != 0 { if ret := *(*uint32)(unsafe.Pointer(&r1)); ret != 0 {
return WKSTAInfo102{}, ret, errors.New(NetApiStatus[ret]) return nil, ret, errors.New(NetApiStatus[ret])
} }
// Derence the pointer and return the object so we can safely clear the buffer. return lpwi, 0, nil
var deref WKSTAInfo102 = *lpwi }
defer NetApiBufferFree(lpwi)
// GetWorkstationInfo is an idiomatic wrapper for netWkstaGetInfo
return deref, 0, nil func GetWorkstationInfo() (WorkstationInfo, error) {
info, _, err := netWkstaGetInfo()
if err != nil {
return WorkstationInfo{}, err
}
workstationInfo := WorkstationInfo{
PlatformId: info.wki102_platform_id,
ComputerName: windows.UTF16PtrToString(info.wki102_computername),
LanGroup: windows.UTF16PtrToString(info.wki102_langroup),
VersionMajor: info.wki102_ver_major,
VersionMinor: info.wki102_ver_minor,
LanRoot: windows.UTF16PtrToString(info.wki102_lanroot),
LoggedOnUsers: info.wki102_logged_on_users,
}
// Free the memory allocated by netapi
netApiBufferFree(info)
return workstationInfo, nil
} }

View File

@ -1,6 +1,7 @@
package sysinfoapi package sysinfoapi
import ( import (
"fmt"
"unicode/utf16" "unicode/utf16"
"unsafe" "unsafe"
@ -9,7 +10,7 @@ import (
// MemoryStatusEx is a wrapper for MEMORYSTATUSEX // MemoryStatusEx is a wrapper for MEMORYSTATUSEX
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
type MemoryStatusEx struct { type memoryStatusEx struct {
dwLength uint32 dwLength uint32
DwMemoryLoad uint32 DwMemoryLoad uint32
UllTotalPhys uint64 UllTotalPhys uint64
@ -21,6 +22,18 @@ type MemoryStatusEx struct {
UllAvailExtendedVirtual uint64 UllAvailExtendedVirtual uint64
} }
// MemoryStatus is an idiomatic wrapper for MemoryStatusEx
type MemoryStatus struct {
MemoryLoad uint32
TotalPhys uint64
AvailPhys uint64
TotalPageFile uint64
AvailPageFile uint64
TotalVirtual uint64
AvailVirtual uint64
AvailExtendedVirtual uint64
}
// wProcessorArchitecture is a wrapper for the union found in LP_SYSTEM_INFO // wProcessorArchitecture is a wrapper for the union found in LP_SYSTEM_INFO
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
type wProcessorArchitecture struct { type wProcessorArchitecture struct {
@ -28,14 +41,27 @@ type wProcessorArchitecture struct {
WProcessorArchitecture uint16 WProcessorArchitecture uint16
} }
// ProcessorArchitecture is an idiomatic wrapper for wProcessorArchitecture
type ProcessorArchitecture uint16
// Idiomatic values for wProcessorArchitecture
const (
AMD64 ProcessorArchitecture = 9
ARM = 5
ARM64 = 12
IA64 = 6
INTEL = 0
UNKNOWN = 0xffff
)
// LpSystemInfo is a wrapper for LPSYSTEM_INFO // LpSystemInfo is a wrapper for LPSYSTEM_INFO
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
type LpSystemInfo struct { type lpSystemInfo struct {
Arch wProcessorArchitecture Arch wProcessorArchitecture
DwPageSize uint32 DwPageSize uint32
LpMinimumApplicationAddress *byte LpMinimumApplicationAddress uintptr
LpMaximumApplicationAddress *byte LpMaximumApplicationAddress uintptr
DwActiveProcessorMask *uint32 DwActiveProcessorMask uint32
DwNumberOfProcessors uint32 DwNumberOfProcessors uint32
DwProcessorType uint32 DwProcessorType uint32
DwAllocationGranularity uint32 DwAllocationGranularity uint32
@ -43,6 +69,20 @@ type LpSystemInfo struct {
WProcessorRevision uint16 WProcessorRevision uint16
} }
// SystemInfo is an idiomatic wrapper for LpSystemInfo
type SystemInfo struct {
Arch ProcessorArchitecture
PageSize uint32
MinimumApplicationAddress uintptr
MaximumApplicationAddress uintptr
ActiveProcessorMask uint32
NumberOfProcessors uint32
ProcessorType uint32
AllocationGranularity uint32
ProcessorLevel uint16
ProcessorRevision uint16
}
// WinComputerNameFormat is a wrapper for COMPUTER_NAME_FORMAT // WinComputerNameFormat is a wrapper for COMPUTER_NAME_FORMAT
type WinComputerNameFormat int type WinComputerNameFormat int
@ -68,27 +108,47 @@ var (
// GlobalMemoryStatusEx retrieves information about the system's current usage of both physical and virtual memory. // 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 // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex
func GlobalMemoryStatusEx() (MemoryStatusEx, error) { func GlobalMemoryStatusEx() (MemoryStatus, error) {
var mse MemoryStatusEx var mse memoryStatusEx
mse.dwLength = (uint32)(unsafe.Sizeof(mse)) mse.dwLength = (uint32)(unsafe.Sizeof(mse))
pMse := uintptr(unsafe.Pointer(&mse)) pMse := uintptr(unsafe.Pointer(&mse))
r1, _, err := procGlobalMemoryStatusEx.Call(pMse) r1, _, err := procGlobalMemoryStatusEx.Call(pMse)
if ret := *(*bool)(unsafe.Pointer(&r1)); ret == false { if ret := *(*bool)(unsafe.Pointer(&r1)); ret == false {
// returned false return MemoryStatus{}, err
return MemoryStatusEx{}, err
} }
return mse, nil return MemoryStatus{
MemoryLoad: mse.DwMemoryLoad,
TotalPhys: mse.UllTotalPhys,
AvailPhys: mse.UllAvailPhys,
TotalPageFile: mse.UllTotalPageFile,
AvailPageFile: mse.UllAvailPageFile,
TotalVirtual: mse.UllTotalVirtual,
AvailVirtual: mse.UllAvailVirtual,
AvailExtendedVirtual: mse.UllAvailExtendedVirtual,
}, nil
} }
// GetSystemInfo wraps the GetSystemInfo function from sysinfoapi // GetSystemInfo wraps the GetSystemInfo function from sysinfoapi
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo
func GetSystemInfo() LpSystemInfo { func GetSystemInfo() SystemInfo {
var info LpSystemInfo var info lpSystemInfo
pInfo := uintptr(unsafe.Pointer(&info)) pInfo := uintptr(unsafe.Pointer(&info))
procGetSystemInfo.Call(pInfo) procGetSystemInfo.Call(pInfo)
return info fmt.Printf("%+v", info)
return SystemInfo{
Arch: ProcessorArchitecture(info.Arch.WProcessorArchitecture),
PageSize: info.DwPageSize,
MinimumApplicationAddress: info.LpMinimumApplicationAddress,
MaximumApplicationAddress: info.LpMinimumApplicationAddress,
ActiveProcessorMask: info.DwActiveProcessorMask,
NumberOfProcessors: info.DwNumberOfProcessors,
ProcessorType: info.DwProcessorType,
AllocationGranularity: info.DwAllocationGranularity,
ProcessorLevel: info.WProcessorLevel,
ProcessorRevision: info.WProcessorRevision,
}
} }
// GetComputerName wraps the GetComputerNameW function in a more Go-like way // GetComputerName wraps the GetComputerNameW function in a more Go-like way