|
|
@ -4,6 +4,7 @@ package common
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"fmt"
|
|
|
|
"path/filepath"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
"syscall"
|
|
|
@ -69,13 +70,13 @@ var (
|
|
|
|
ProcNtWow64QueryInformationProcess64 = ModNt.NewProc("NtWow64QueryInformationProcess64")
|
|
|
|
ProcNtWow64QueryInformationProcess64 = ModNt.NewProc("NtWow64QueryInformationProcess64")
|
|
|
|
ProcNtWow64ReadVirtualMemory64 = ModNt.NewProc("NtWow64ReadVirtualMemory64")
|
|
|
|
ProcNtWow64ReadVirtualMemory64 = ModNt.NewProc("NtWow64ReadVirtualMemory64")
|
|
|
|
|
|
|
|
|
|
|
|
PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
|
|
|
|
PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
|
|
|
|
PdhAddCounter = ModPdh.NewProc("PdhAddCounterW")
|
|
|
|
PdhAddCounter = ModPdh.NewProc("PdhAddCounterW")
|
|
|
|
PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData")
|
|
|
|
PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData")
|
|
|
|
PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
|
|
|
|
PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
|
|
|
|
PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery")
|
|
|
|
PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery")
|
|
|
|
|
|
|
|
|
|
|
|
procQueryDosDeviceW = Modkernel32.NewProc("QueryDosDeviceW")
|
|
|
|
procQueryDosDeviceW = Modkernel32.NewProc("QueryDosDeviceW")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type FILETIME struct {
|
|
|
|
type FILETIME struct {
|
|
|
@ -93,7 +94,7 @@ func BytePtrToString(p *uint8) string {
|
|
|
|
return string(a[:i])
|
|
|
|
return string(a[:i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CounterInfo
|
|
|
|
// CounterInfo struct is used to track a windows performance counter
|
|
|
|
// copied from https://github.com/mackerelio/mackerel-agent/
|
|
|
|
// copied from https://github.com/mackerelio/mackerel-agent/
|
|
|
|
type CounterInfo struct {
|
|
|
|
type CounterInfo struct {
|
|
|
|
PostName string
|
|
|
|
PostName string
|
|
|
@ -101,7 +102,7 @@ type CounterInfo struct {
|
|
|
|
Counter windows.Handle
|
|
|
|
Counter windows.Handle
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CreateQuery XXX
|
|
|
|
// CreateQuery with a PdhOpenQuery call
|
|
|
|
// copied from https://github.com/mackerelio/mackerel-agent/
|
|
|
|
// copied from https://github.com/mackerelio/mackerel-agent/
|
|
|
|
func CreateQuery() (windows.Handle, error) {
|
|
|
|
func CreateQuery() (windows.Handle, error) {
|
|
|
|
var query windows.Handle
|
|
|
|
var query windows.Handle
|
|
|
@ -112,7 +113,7 @@ func CreateQuery() (windows.Handle, error) {
|
|
|
|
return query, nil
|
|
|
|
return query, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CreateCounter XXX
|
|
|
|
// CreateCounter with a PdhAddCounter call
|
|
|
|
func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) {
|
|
|
|
func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) {
|
|
|
|
var counter windows.Handle
|
|
|
|
var counter windows.Handle
|
|
|
|
r, _, err := PdhAddCounter.Call(
|
|
|
|
r, _, err := PdhAddCounter.Call(
|
|
|
@ -130,6 +131,62 @@ func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, err
|
|
|
|
}, nil
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GetCounterValue get counter value from handle
|
|
|
|
|
|
|
|
// adapted from https://github.com/mackerelio/mackerel-agent/
|
|
|
|
|
|
|
|
func GetCounterValue(counter windows.Handle) (float64, error) {
|
|
|
|
|
|
|
|
var value PDH_FMT_COUNTERVALUE_DOUBLE
|
|
|
|
|
|
|
|
r, _, err := PdhGetFormattedCounterValue.Call(uintptr(counter), PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&value)))
|
|
|
|
|
|
|
|
if r != 0 && r != PDH_INVALID_DATA {
|
|
|
|
|
|
|
|
return 0.0, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return value.DoubleValue, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type Win32PerformanceCounter struct {
|
|
|
|
|
|
|
|
PostName string
|
|
|
|
|
|
|
|
CounterName string
|
|
|
|
|
|
|
|
Query windows.Handle
|
|
|
|
|
|
|
|
Counter windows.Handle
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func NewWin32PerformanceCounter(postName, counterName string) (*Win32PerformanceCounter, error) {
|
|
|
|
|
|
|
|
query, err := CreateQuery()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
var counter = Win32PerformanceCounter{
|
|
|
|
|
|
|
|
Query: query,
|
|
|
|
|
|
|
|
PostName: postName,
|
|
|
|
|
|
|
|
CounterName: counterName,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
r, _, err := PdhAddCounter.Call(
|
|
|
|
|
|
|
|
uintptr(counter.Query),
|
|
|
|
|
|
|
|
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(counter.CounterName))),
|
|
|
|
|
|
|
|
0,
|
|
|
|
|
|
|
|
uintptr(unsafe.Pointer(&counter.Counter)),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if r != 0 {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return &counter, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (w *Win32PerformanceCounter) GetValue() (float64, error) {
|
|
|
|
|
|
|
|
r, _, err := PdhCollectQueryData.Call(uintptr(w.Query))
|
|
|
|
|
|
|
|
if r != 0 && err != nil {
|
|
|
|
|
|
|
|
if r == PDH_NO_DATA {
|
|
|
|
|
|
|
|
return 0.0, fmt.Errorf("%w: this counter has not data", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0.0, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return GetCounterValue(w.Counter)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func ProcessorQueueLengthCounter() (*Win32PerformanceCounter, error) {
|
|
|
|
|
|
|
|
return NewWin32PerformanceCounter("processor_queue_length", `\System\Processor Queue Length`)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
|
|
|
|
// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
|
|
|
|
func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
|
|
|
|
func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
|
|
|
|
if _, ok := ctx.Deadline(); !ok {
|
|
|
|
if _, ok := ctx.Deadline(); !ok {
|
|
|
|