blob: f973398df2d4a28e2609309a98c4c700d7b28425 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// Copyright 2019 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package prometheus
15
16import (
17 "syscall"
18 "unsafe"
19
20 "golang.org/x/sys/windows"
21)
22
23func canCollectProcess() bool {
24 return true
25}
26
27var (
28 modpsapi = syscall.NewLazyDLL("psapi.dll")
29 modkernel32 = syscall.NewLazyDLL("kernel32.dll")
30
31 procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
32 procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount")
33)
34
35type processMemoryCounters struct {
khenaidood948f772021-08-11 17:49:24 -040036 // System interface description
37 // https://docs.microsoft.com/en-us/windows/desktop/api/psapi/ns-psapi-process_memory_counters_ex
38
39 // Refer to the Golang internal implementation
40 // https://golang.org/src/internal/syscall/windows/psapi_windows.go
khenaidooab1f7bd2019-11-14 14:00:27 -050041 _ uint32
42 PageFaultCount uint32
khenaidood948f772021-08-11 17:49:24 -040043 PeakWorkingSetSize uintptr
44 WorkingSetSize uintptr
45 QuotaPeakPagedPoolUsage uintptr
46 QuotaPagedPoolUsage uintptr
47 QuotaPeakNonPagedPoolUsage uintptr
48 QuotaNonPagedPoolUsage uintptr
49 PagefileUsage uintptr
50 PeakPagefileUsage uintptr
51 PrivateUsage uintptr
khenaidooab1f7bd2019-11-14 14:00:27 -050052}
53
54func getProcessMemoryInfo(handle windows.Handle) (processMemoryCounters, error) {
55 mem := processMemoryCounters{}
56 r1, _, err := procGetProcessMemoryInfo.Call(
57 uintptr(handle),
58 uintptr(unsafe.Pointer(&mem)),
59 uintptr(unsafe.Sizeof(mem)),
60 )
61 if r1 != 1 {
62 return mem, err
63 } else {
64 return mem, nil
65 }
66}
67
68func getProcessHandleCount(handle windows.Handle) (uint32, error) {
69 var count uint32
70 r1, _, err := procGetProcessHandleCount.Call(
71 uintptr(handle),
72 uintptr(unsafe.Pointer(&count)),
73 )
74 if r1 != 1 {
75 return 0, err
76 } else {
77 return count, nil
78 }
79}
80
81func (c *processCollector) processCollect(ch chan<- Metric) {
82 h, err := windows.GetCurrentProcess()
83 if err != nil {
84 c.reportError(ch, nil, err)
85 return
86 }
87
88 var startTime, exitTime, kernelTime, userTime windows.Filetime
89 err = windows.GetProcessTimes(h, &startTime, &exitTime, &kernelTime, &userTime)
90 if err != nil {
91 c.reportError(ch, nil, err)
92 return
93 }
94 ch <- MustNewConstMetric(c.startTime, GaugeValue, float64(startTime.Nanoseconds()/1e9))
95 ch <- MustNewConstMetric(c.cpuTotal, CounterValue, fileTimeToSeconds(kernelTime)+fileTimeToSeconds(userTime))
96
97 mem, err := getProcessMemoryInfo(h)
98 if err != nil {
99 c.reportError(ch, nil, err)
100 return
101 }
102 ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(mem.PrivateUsage))
103 ch <- MustNewConstMetric(c.rss, GaugeValue, float64(mem.WorkingSetSize))
104
105 handles, err := getProcessHandleCount(h)
106 if err != nil {
107 c.reportError(ch, nil, err)
108 return
109 }
110 ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(handles))
111 ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(16*1024*1024)) // Windows has a hard-coded max limit, not per-process.
112}
113
114func fileTimeToSeconds(ft windows.Filetime) float64 {
115 return float64(uint64(ft.HighDateTime)<<32+uint64(ft.LowDateTime)) / 1e7
116}