metrics/process_metrics_windows.go

85 lines
2.9 KiB
Go
Raw Permalink Normal View History

//go:build windows
// +build windows
package metrics
import (
"io"
"log"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var (
modpsapi = syscall.NewLazyDLL("psapi.dll")
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount")
)
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-process_memory_counters_ex
type processMemoryCounters struct {
_ uint32
PageFaultCount uint32
PeakWorkingSetSize uintptr
WorkingSetSize uintptr
QuotaPeakPagedPoolUsage uintptr
QuotaPagedPoolUsage uintptr
QuotaPeakNonPagedPoolUsage uintptr
QuotaNonPagedPoolUsage uintptr
PagefileUsage uintptr
PeakPagefileUsage uintptr
PrivateUsage uintptr
}
func writeProcessMetrics(w io.Writer) {
h := windows.CurrentProcess()
var startTime, exitTime, stime, utime windows.Filetime
err := windows.GetProcessTimes(h, &startTime, &exitTime, &stime, &utime)
if err != nil {
log.Printf("ERROR: metrics: cannot read process times: %s", err)
return
}
var mc processMemoryCounters
r1, _, err := procGetProcessMemoryInfo.Call(
uintptr(h),
uintptr(unsafe.Pointer(&mc)),
unsafe.Sizeof(mc),
)
if r1 != 1 {
log.Printf("ERROR: metrics: cannot read process memory information: %s", err)
return
}
stimeSeconds := float64(uint64(stime.HighDateTime)<<32+uint64(stime.LowDateTime)) / 1e7
utimeSeconds := float64(uint64(utime.HighDateTime)<<32+uint64(utime.LowDateTime)) / 1e7
WriteCounterFloat64(w, "process_cpu_seconds_system_total", stimeSeconds)
WriteCounterFloat64(w, "process_cpu_seconds_total", stimeSeconds+utimeSeconds)
WriteCounterFloat64(w, "process_cpu_seconds_user_total", stimeSeconds)
WriteCounterUint64(w, "process_pagefaults_total", uint64(mc.PageFaultCount))
WriteGaugeUint64(w, "process_start_time_seconds", uint64(startTime.Nanoseconds())/1e9)
WriteGaugeUint64(w, "process_virtual_memory_bytes", uint64(mc.PrivateUsage))
WriteGaugeUint64(w, "process_resident_memory_peak_bytes", uint64(mc.PeakWorkingSetSize))
WriteGaugeUint64(w, "process_resident_memory_bytes", uint64(mc.WorkingSetSize))
}
func writeFDMetrics(w io.Writer) {
h := windows.CurrentProcess()
var count uint32
r1, _, err := procGetProcessHandleCount.Call(
uintptr(h),
uintptr(unsafe.Pointer(&count)),
)
if r1 != 1 {
log.Printf("ERROR: metrics: cannot determine open file descriptors count: %s", err)
return
}
// it seems to be hard-coded limit for 64-bit systems
// https://learn.microsoft.com/en-us/archive/blogs/markrussinovich/pushing-the-limits-of-windows-handles#maximum-number-of-handles
WriteGaugeUint64(w, "process_max_fds", 16777216)
WriteGaugeUint64(w, "process_open_fds", uint64(count))
}