diff --git a/go.mod b/go.mod index 71ab655d..17cf32ee 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus-community/windows_exporter -go 1.21 +go 1.22 require ( github.com/Microsoft/hcsshim v0.12.4 diff --git a/pkg/collector/os/os.go b/pkg/collector/os/os.go index b6407de9..4d44f107 100644 --- a/pkg/collector/os/os.go +++ b/pkg/collector/os/os.go @@ -8,16 +8,19 @@ import ( "os" "strconv" "strings" + "syscall" "time" - "github.com/alecthomas/kingpin/v2" - "github.com/go-kit/log" - "github.com/go-kit/log/level" + "github.com/prometheus-community/windows_exporter/pkg/headers/kernel32" "github.com/prometheus-community/windows_exporter/pkg/headers/netapi32" "github.com/prometheus-community/windows_exporter/pkg/headers/psapi" "github.com/prometheus-community/windows_exporter/pkg/headers/sysinfoapi" "github.com/prometheus-community/windows_exporter/pkg/perflib" "github.com/prometheus-community/windows_exporter/pkg/types" + + "github.com/alecthomas/kingpin/v2" + "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "golang.org/x/sys/windows/registry" ) @@ -197,16 +200,36 @@ func (c *collector) collect(ctx *types.ScrapeContext, ch chan<- prometheus.Metri } currentTime := time.Now() - timezoneName, _ := currentTime.Zone() + + timeZoneInfo, err := kernel32.GetDynamicTimeZoneInformation() + if err != nil { + return err + } + + // timeZoneKeyName contains the english name of the timezone. + timezoneName := syscall.UTF16ToString(timeZoneInfo.TimeZoneKeyName[:]) // 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) defer memManKey.Close() - if err != nil { return err } + pagingFiles, _, pagingErr := memManKey.GetStringsValue("ExistingPageFiles") + + var fsipf float64 + for _, pagingFile := range pagingFiles { + fileString := strings.ReplaceAll(pagingFile, `\??\`, "") + file, err := os.Stat(fileString) + // For unknown reasons, Windows doesn't always create a page file. Continue collection rather than aborting. + if err != nil { + _ = level.Debug(c.logger).Log("msg", fmt.Sprintf("Failed to read page file (reason: %s): %s\n", err, fileString)) + } else { + fsipf += float64(file.Size()) + } + } + // Get build number and product name from registry ntKey, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) defer ntKey.Close() @@ -232,18 +255,6 @@ func (c *collector) collect(ctx *types.ScrapeContext, ch chan<- prometheus.Metri return err } - var fsipf float64 - for _, pagingFile := range pagingFiles { - fileString := strings.ReplaceAll(pagingFile, `\??\`, "") - file, err := os.Stat(fileString) - // For unknown reasons, Windows doesn't always create a page file. Continue collection rather than aborting. - if err != nil { - _ = level.Debug(c.logger).Log("msg", fmt.Sprintf("Failed to read page file (reason: %s): %s\n", err, fileString)) - } else { - fsipf += float64(file.Size()) - } - } - gpi, err := psapi.GetPerformanceInfo() if err != nil { return err diff --git a/pkg/headers/kernel32/kernel32.go b/pkg/headers/kernel32/kernel32.go new file mode 100644 index 00000000..cee36766 --- /dev/null +++ b/pkg/headers/kernel32/kernel32.go @@ -0,0 +1,52 @@ +package kernel32 + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + + procGetDynamicTimeZoneInformationSys = kernel32.NewProc("GetDynamicTimeZoneInformation") +) + +// SYSTEMTIME contains a date and time. +// 📑 https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime +type SYSTEMTIME struct { + WYear uint16 + WMonth uint16 + WDayOfWeek uint16 + WDay uint16 + WHour uint16 + WMinute uint16 + WSecond uint16 + WMilliseconds uint16 +} + +// DynamicTimezoneInformation contains the current dynamic daylight time settings. +// 📑 https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information +type DynamicTimezoneInformation struct { + Bias int32 + standardName [32]uint16 + StandardDate SYSTEMTIME + StandardBias int32 + DaylightName [32]uint16 + DaylightDate SYSTEMTIME + DaylightBias int32 + TimeZoneKeyName [128]uint16 + DynamicDaylightTimeDisabled uint8 // BOOLEAN +} + +// GetDynamicTimeZoneInformation retrieves the current dynamic daylight time settings. +// 📑 https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-getdynamictimezoneinformation +func GetDynamicTimeZoneInformation() (DynamicTimezoneInformation, error) { + var tzi DynamicTimezoneInformation + + r0, _, err := syscall.SyscallN(procGetDynamicTimeZoneInformationSys.Addr(), uintptr(unsafe.Pointer(&tzi))) + if uint32(r0) == 0xffffffff { + return tzi, err + } + + return tzi, nil +}