mirror of
https://github.com/prometheus-community/windows_exporter
synced 2025-02-15 19:48:16 +00:00
Replace the CS collector with native WinAPI calls to sysinfoapi
Signed-off-by: Ben Ridley <benridley29@gmail.com>
This commit is contained in:
parent
18495abb69
commit
71054ac429
@ -3,10 +3,8 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/StackExchange/wmi"
|
||||
"github.com/prometheus-community/windows_exporter/log"
|
||||
"github.com/prometheus-community/windows_exporter/sysinfoapi"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@ -60,51 +58,45 @@ func (c *CSCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// Win32_ComputerSystem docs:
|
||||
// - https://msdn.microsoft.com/en-us/library/aa394102
|
||||
type Win32_ComputerSystem struct {
|
||||
NumberOfLogicalProcessors uint32
|
||||
TotalPhysicalMemory uint64
|
||||
DNSHostname string
|
||||
Domain string
|
||||
Workgroup *string
|
||||
}
|
||||
|
||||
func (c *CSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
|
||||
var dst []Win32_ComputerSystem
|
||||
q := queryAll(&dst)
|
||||
if err := wmi.Query(q, &dst); err != nil {
|
||||
cs := sysinfoapi.GetNumLogicalProcessors()
|
||||
|
||||
pm, err := sysinfoapi.GetPhysicalMemory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(dst) == 0 {
|
||||
return nil, errors.New("WMI query returned empty result set")
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.LogicalProcessors,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].NumberOfLogicalProcessors),
|
||||
float64(cs),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.PhysicalMemoryBytes,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].TotalPhysicalMemory),
|
||||
float64(pm),
|
||||
)
|
||||
|
||||
var fqdn string
|
||||
if dst[0].Workgroup == nil || dst[0].Domain != *dst[0].Workgroup {
|
||||
fqdn = dst[0].DNSHostname + "." + dst[0].Domain
|
||||
} else {
|
||||
fqdn = dst[0].DNSHostname
|
||||
hostname, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSHostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domain, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fqdn, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSFullyQualified)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.Hostname,
|
||||
prometheus.GaugeValue,
|
||||
1.0,
|
||||
dst[0].DNSHostname,
|
||||
dst[0].Domain,
|
||||
hostname,
|
||||
domain,
|
||||
fqdn,
|
||||
)
|
||||
|
||||
|
23
collector/cs_test.go
Normal file
23
collector/cs_test.go
Normal file
@ -0,0 +1,23 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func BenchmarkCsCollect(b *testing.B) {
|
||||
c, err := NewCSCollector()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
metrics := make(chan prometheus.Metric)
|
||||
go func() {
|
||||
for {
|
||||
<-metrics
|
||||
}
|
||||
}()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Collect(&ScrapeContext{}, metrics)
|
||||
}
|
||||
}
|
112
sysinfoapi/sysinfoapi.go
Normal file
112
sysinfoapi/sysinfoapi.go
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2020 Prometheus Team
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package sysinfoapi wraps some WinAPI sysinfoapi functions used by the exporter to produce metrics.
|
||||
// It is fairly opinionated for the exporter's internal use, and is not intended to be a
|
||||
// generic wrapper for the WinAPI's sysinfoapi.
|
||||
package sysinfoapi
|
||||
|
||||
import (
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// WinProcInfo is a wrapper for
|
||||
type WinProcInfo struct {
|
||||
WReserved uint16
|
||||
WProcessorArchitecture uint16
|
||||
}
|
||||
|
||||
// WinSystemInfo is a wrapper for LPSYSTEM_INFO
|
||||
type WinSystemInfo struct {
|
||||
Arch WinProcInfo
|
||||
DwPageSize uint32
|
||||
LpMinimumApplicationAddress *byte
|
||||
LpMaximumApplicationAddress *byte
|
||||
DwActiveProcessorMask *uint32
|
||||
DwNumberOfProcessors uint32
|
||||
DwProcessorType uint32
|
||||
DwAllocationGranularity uint32
|
||||
WProcessorLevel uint16
|
||||
WProcessorRevision uint16
|
||||
}
|
||||
|
||||
// WinComputerNameFormat is a wrapper for COMPUTER_NAME_FORMAT
|
||||
type WinComputerNameFormat int
|
||||
|
||||
// Definitions for WinComputerNameFormat constants
|
||||
const (
|
||||
ComputerNameNetBIOS WinComputerNameFormat = iota
|
||||
ComputerNameDNSHostname
|
||||
ComputerNameDNSDomain
|
||||
ComputerNameDNSFullyQualified
|
||||
ComputerNamePhysicalNetBIOS
|
||||
ComputerNamePhysicalDNSHostname
|
||||
ComputerNamePhysicalDNSDomain
|
||||
ComputerNamePhysicalDNSFullyQualified
|
||||
ComputerNameMax
|
||||
)
|
||||
|
||||
// WinMemoryStatus is a wrapper for LPMEMORYSTATUSEX
|
||||
type WinMemoryStatus 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")
|
||||
procGetComputerNameExW = kernel32.NewProc("GetComputerNameExW")
|
||||
)
|
||||
|
||||
// GetNumLogicalProcessors returns the number of logical processes provided by sysinfoapi's GetSystemInfo function.
|
||||
func GetNumLogicalProcessors() int {
|
||||
var sysInfo WinSystemInfo
|
||||
pInfo := uintptr(unsafe.Pointer(&sysInfo))
|
||||
procGetSystemInfo.Call(pInfo)
|
||||
return int(sysInfo.DwNumberOfProcessors)
|
||||
}
|
||||
|
||||
// GetPhysicalMemory returns the system's installed physical memory provided by sysinfoapi's GlobalMemoryStatusEx function.
|
||||
func GetPhysicalMemory() (int, error) {
|
||||
var wm WinMemoryStatus
|
||||
wm.dwLength = (uint32)(unsafe.Sizeof(wm))
|
||||
r1, _, err := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&wm)))
|
||||
if r1 != 1 {
|
||||
return 0, err
|
||||
}
|
||||
return int(wm.ullTotalPhys), nil
|
||||
}
|
||||
|
||||
// GetComputerName provides the requested computer name provided by sysinfoapi's GetComputerNameEx function.
|
||||
func GetComputerName(f WinComputerNameFormat) (string, error) {
|
||||
size := 4096
|
||||
var buffer [4096]uint16
|
||||
r1, _, err := procGetComputerNameExW.Call(uintptr(f), uintptr(unsafe.Pointer(&buffer)), uintptr(unsafe.Pointer(&size)))
|
||||
if r1 == 0 {
|
||||
return "", err
|
||||
}
|
||||
bytes := buffer[0:size]
|
||||
out := utf16.Decode(bytes)
|
||||
return string(out), nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user