2019-06-14 13:26:55 +03:00
|
|
|
// 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 {
|
2020-04-13 05:43:29 +03:00
|
|
|
// System interface description
|
|
|
|
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/ns-psapi-process_memory_counters_ex
|
|
|
|
|
|
|
|
// Refer to the Golang internal implementation
|
|
|
|
// https://golang.org/src/internal/syscall/windows/psapi_windows.go
|
2019-06-14 13:26:55 +03:00
|
|
|
_ uint32
|
|
|
|
PageFaultCount uint32
|
2020-04-13 05:43:29 +03:00
|
|
|
PeakWorkingSetSize uintptr
|
|
|
|
WorkingSetSize uintptr
|
|
|
|
QuotaPeakPagedPoolUsage uintptr
|
|
|
|
QuotaPagedPoolUsage uintptr
|
|
|
|
QuotaPeakNonPagedPoolUsage uintptr
|
|
|
|
QuotaNonPagedPoolUsage uintptr
|
|
|
|
PagefileUsage uintptr
|
|
|
|
PeakPagefileUsage uintptr
|
|
|
|
PrivateUsage uintptr
|
2019-06-14 13:26:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|