113 lines
3.2 KiB
Go
113 lines
3.2 KiB
Go
![]() |
// Copyright 2019 The Prometheus Authors
|
||
|
// 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 prometheus
|
||
|
|
||
|
import (
|
||
|
"syscall"
|
||
|
"unsafe"
|
||
|
|
||
|
"golang.org/x/sys/windows"
|
||
|
)
|
||
|
|
||
|
func canCollectProcess() bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
modpsapi = syscall.NewLazyDLL("psapi.dll")
|
||
|
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||
|
|
||
|
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
|
||
|
procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount")
|
||
|
)
|
||
|
|
||
|
type processMemoryCounters struct {
|
||
|
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/ns-psapi-_process_memory_counters_ex
|
||
|
_ uint32
|
||
|
PageFaultCount uint32
|
||
|
PeakWorkingSetSize uint64
|
||
|
WorkingSetSize uint64
|
||
|
QuotaPeakPagedPoolUsage uint64
|
||
|
QuotaPagedPoolUsage uint64
|
||
|
QuotaPeakNonPagedPoolUsage uint64
|
||
|
QuotaNonPagedPoolUsage uint64
|
||
|
PagefileUsage uint64
|
||
|
PeakPagefileUsage uint64
|
||
|
PrivateUsage uint64
|
||
|
}
|
||
|
|
||
|
func getProcessMemoryInfo(handle windows.Handle) (processMemoryCounters, error) {
|
||
|
mem := processMemoryCounters{}
|
||
|
r1, _, err := procGetProcessMemoryInfo.Call(
|
||
|
uintptr(handle),
|
||
|
uintptr(unsafe.Pointer(&mem)),
|
||
|
uintptr(unsafe.Sizeof(mem)),
|
||
|
)
|
||
|
if r1 != 1 {
|
||
|
return mem, err
|
||
|
} else {
|
||
|
return mem, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func getProcessHandleCount(handle windows.Handle) (uint32, error) {
|
||
|
var count uint32
|
||
|
r1, _, err := procGetProcessHandleCount.Call(
|
||
|
uintptr(handle),
|
||
|
uintptr(unsafe.Pointer(&count)),
|
||
|
)
|
||
|
if r1 != 1 {
|
||
|
return 0, err
|
||
|
} else {
|
||
|
return count, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *processCollector) processCollect(ch chan<- Metric) {
|
||
|
h, err := windows.GetCurrentProcess()
|
||
|
if err != nil {
|
||
|
c.reportError(ch, nil, err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var startTime, exitTime, kernelTime, userTime windows.Filetime
|
||
|
err = windows.GetProcessTimes(h, &startTime, &exitTime, &kernelTime, &userTime)
|
||
|
if err != nil {
|
||
|
c.reportError(ch, nil, err)
|
||
|
return
|
||
|
}
|
||
|
ch <- MustNewConstMetric(c.startTime, GaugeValue, float64(startTime.Nanoseconds()/1e9))
|
||
|
ch <- MustNewConstMetric(c.cpuTotal, CounterValue, fileTimeToSeconds(kernelTime)+fileTimeToSeconds(userTime))
|
||
|
|
||
|
mem, err := getProcessMemoryInfo(h)
|
||
|
if err != nil {
|
||
|
c.reportError(ch, nil, err)
|
||
|
return
|
||
|
}
|
||
|
ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(mem.PrivateUsage))
|
||
|
ch <- MustNewConstMetric(c.rss, GaugeValue, float64(mem.WorkingSetSize))
|
||
|
|
||
|
handles, err := getProcessHandleCount(h)
|
||
|
if err != nil {
|
||
|
c.reportError(ch, nil, err)
|
||
|
return
|
||
|
}
|
||
|
ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(handles))
|
||
|
ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(16*1024*1024)) // Windows has a hard-coded max limit, not per-process.
|
||
|
}
|
||
|
|
||
|
func fileTimeToSeconds(ft windows.Filetime) float64 {
|
||
|
return float64(uint64(ft.HighDateTime)<<32+uint64(ft.LowDateTime)) / 1e7
|
||
|
}
|