1// 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 { 36 // 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 41 _ uint32 42 PageFaultCount uint32 43 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 52} 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} 117