Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
333
plugins/inputs/win_perf_counters/performance_query.go
Normal file
333
plugins/inputs/win_perf_counters/performance_query.go
Normal file
|
@ -0,0 +1,333 @@
|
|||
// Go API over pdh syscalls
|
||||
//go:build windows
|
||||
|
||||
package win_perf_counters
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Initial buffer size for return buffers
|
||||
const initialBufferSize = uint32(1024) // 1kB
|
||||
|
||||
var errBufferLimitReached = errors.New("buffer limit reached")
|
||||
|
||||
// counterValue is abstraction for pdhFmtCountervalueItemDouble
|
||||
type counterValue struct {
|
||||
instanceName string
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// performanceQuery provides wrappers around Windows performance counters API for easy usage in GO
|
||||
//
|
||||
//nolint:interfacebloat // conditionally allow to contain more methods
|
||||
type performanceQuery interface {
|
||||
open() error
|
||||
close() error
|
||||
addCounterToQuery(counterPath string) (pdhCounterHandle, error)
|
||||
addEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error)
|
||||
getCounterPath(counterHandle pdhCounterHandle) (string, error)
|
||||
expandWildCardPath(counterPath string) ([]string, error)
|
||||
getFormattedCounterValueDouble(hCounter pdhCounterHandle) (float64, error)
|
||||
getRawCounterValue(hCounter pdhCounterHandle) (int64, error)
|
||||
getFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error)
|
||||
getRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error)
|
||||
collectData() error
|
||||
collectDataWithTime() (time.Time, error)
|
||||
isVistaOrNewer() bool
|
||||
}
|
||||
|
||||
type performanceQueryCreator interface {
|
||||
newPerformanceQuery(string, uint32) performanceQuery
|
||||
}
|
||||
|
||||
// pdhError represents error returned from Performance Counters API
|
||||
type pdhError struct {
|
||||
errorCode uint32
|
||||
errorText string
|
||||
}
|
||||
|
||||
func (m *pdhError) Error() string {
|
||||
return m.errorText
|
||||
}
|
||||
|
||||
func newPdhError(code uint32) error {
|
||||
return &pdhError{
|
||||
errorCode: code,
|
||||
errorText: pdhFormatError(code),
|
||||
}
|
||||
}
|
||||
|
||||
// performanceQueryImpl is implementation of performanceQuery interface, which calls phd.dll functions
|
||||
type performanceQueryImpl struct {
|
||||
maxBufferSize uint32
|
||||
query pdhQueryHandle
|
||||
}
|
||||
|
||||
type performanceQueryCreatorImpl struct{}
|
||||
|
||||
func (performanceQueryCreatorImpl) newPerformanceQuery(_ string, maxBufferSize uint32) performanceQuery {
|
||||
return &performanceQueryImpl{maxBufferSize: maxBufferSize}
|
||||
}
|
||||
|
||||
// open creates a new counterPath that is used to manage the collection of performance data.
|
||||
// It returns counterPath handle used for subsequent calls for adding counters and querying data
|
||||
func (m *performanceQueryImpl) open() error {
|
||||
if m.query != 0 {
|
||||
err := m.close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var handle pdhQueryHandle
|
||||
|
||||
if ret := pdhOpenQuery(0, 0, &handle); ret != errorSuccess {
|
||||
return newPdhError(ret)
|
||||
}
|
||||
m.query = handle
|
||||
return nil
|
||||
}
|
||||
|
||||
// close closes the counterPath, releases associated counter handles and frees resources
|
||||
func (m *performanceQueryImpl) close() error {
|
||||
if m.query == 0 {
|
||||
return errors.New("uninitialized query")
|
||||
}
|
||||
|
||||
if ret := pdhCloseQuery(m.query); ret != errorSuccess {
|
||||
return newPdhError(ret)
|
||||
}
|
||||
m.query = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *performanceQueryImpl) addCounterToQuery(counterPath string) (pdhCounterHandle, error) {
|
||||
var counterHandle pdhCounterHandle
|
||||
if m.query == 0 {
|
||||
return 0, errors.New("uninitialized query")
|
||||
}
|
||||
|
||||
if ret := pdhAddCounter(m.query, counterPath, 0, &counterHandle); ret != errorSuccess {
|
||||
return 0, newPdhError(ret)
|
||||
}
|
||||
return counterHandle, nil
|
||||
}
|
||||
|
||||
func (m *performanceQueryImpl) addEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error) {
|
||||
var counterHandle pdhCounterHandle
|
||||
if m.query == 0 {
|
||||
return 0, errors.New("uninitialized query")
|
||||
}
|
||||
if ret := pdhAddEnglishCounter(m.query, counterPath, 0, &counterHandle); ret != errorSuccess {
|
||||
return 0, newPdhError(ret)
|
||||
}
|
||||
return counterHandle, nil
|
||||
}
|
||||
|
||||
// getCounterPath returns counter information for given handle
|
||||
func (m *performanceQueryImpl) getCounterPath(counterHandle pdhCounterHandle) (string, error) {
|
||||
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
|
||||
buf := make([]byte, buflen)
|
||||
|
||||
// Get the info with the current buffer size
|
||||
size := buflen
|
||||
ret := pdhGetCounterInfo(counterHandle, 0, &size, &buf[0])
|
||||
if ret == errorSuccess {
|
||||
ci := (*pdhCounterInfo)(unsafe.Pointer(&buf[0])) //nolint:gosec // G103: Valid use of unsafe call to create PDH_COUNTER_INFO
|
||||
return utf16PtrToString(ci.SzFullPath), nil
|
||||
}
|
||||
|
||||
// Use the size as a hint if it exceeds the current buffer size
|
||||
if size > buflen {
|
||||
buflen = size
|
||||
}
|
||||
|
||||
// We got a non-recoverable error so exit here
|
||||
if ret != pdhMoreData {
|
||||
return "", newPdhError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
return "", errBufferLimitReached
|
||||
}
|
||||
|
||||
// expandWildCardPath examines local computer and returns those counter paths that match the given counter path which contains wildcard characters.
|
||||
func (m *performanceQueryImpl) expandWildCardPath(counterPath string) ([]string, error) {
|
||||
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
|
||||
buf := make([]uint16, buflen)
|
||||
|
||||
// Get the info with the current buffer size
|
||||
size := buflen
|
||||
ret := pdhExpandWildCardPath(counterPath, &buf[0], &size)
|
||||
if ret == errorSuccess {
|
||||
return utf16ToStringArray(buf), nil
|
||||
}
|
||||
|
||||
// Use the size as a hint if it exceeds the current buffer size
|
||||
if size > buflen {
|
||||
buflen = size
|
||||
}
|
||||
|
||||
// We got a non-recoverable error so exit here
|
||||
if ret != pdhMoreData {
|
||||
return nil, newPdhError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errBufferLimitReached
|
||||
}
|
||||
|
||||
// getFormattedCounterValueDouble computes a displayable value for the specified counter
|
||||
func (*performanceQueryImpl) getFormattedCounterValueDouble(hCounter pdhCounterHandle) (float64, error) {
|
||||
var counterType uint32
|
||||
var value pdhFmtCountervalueDouble
|
||||
|
||||
if ret := pdhGetFormattedCounterValueDouble(hCounter, &counterType, &value); ret != errorSuccess {
|
||||
return 0, newPdhError(ret)
|
||||
}
|
||||
if value.CStatus == pdhCstatusValidData || value.CStatus == pdhCstatusNewData {
|
||||
return value.DoubleValue, nil
|
||||
}
|
||||
return 0, newPdhError(value.CStatus)
|
||||
}
|
||||
|
||||
func (m *performanceQueryImpl) getFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error) {
|
||||
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
|
||||
buf := make([]byte, buflen)
|
||||
|
||||
// Get the info with the current buffer size
|
||||
var itemCount uint32
|
||||
size := buflen
|
||||
ret := pdhGetFormattedCounterArrayDouble(hCounter, &size, &itemCount, &buf[0])
|
||||
if ret == errorSuccess {
|
||||
//nolint:gosec // G103: Valid use of unsafe call to create PDH_FMT_COUNTERVALUE_ITEM_DOUBLE
|
||||
items := (*[1 << 20]pdhFmtCountervalueItemDouble)(unsafe.Pointer(&buf[0]))[:itemCount]
|
||||
values := make([]counterValue, 0, itemCount)
|
||||
for _, item := range items {
|
||||
if item.FmtValue.CStatus == pdhCstatusValidData || item.FmtValue.CStatus == pdhCstatusNewData {
|
||||
val := counterValue{utf16PtrToString(item.SzName), item.FmtValue.DoubleValue}
|
||||
values = append(values, val)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// Use the size as a hint if it exceeds the current buffer size
|
||||
if size > buflen {
|
||||
buflen = size
|
||||
}
|
||||
|
||||
// We got a non-recoverable error so exit here
|
||||
if ret != pdhMoreData {
|
||||
return nil, newPdhError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errBufferLimitReached
|
||||
}
|
||||
|
||||
func (m *performanceQueryImpl) getRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error) {
|
||||
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
|
||||
buf := make([]byte, buflen)
|
||||
|
||||
// Get the info with the current buffer size
|
||||
var itemCount uint32
|
||||
size := buflen
|
||||
ret := pdhGetRawCounterArray(hCounter, &size, &itemCount, &buf[0])
|
||||
if ret == errorSuccess {
|
||||
//nolint:gosec // G103: Valid use of unsafe call to create PDH_RAW_COUNTER_ITEM
|
||||
items := (*[1 << 20]pdhRawCounterItem)(unsafe.Pointer(&buf[0]))[:itemCount]
|
||||
values := make([]counterValue, 0, itemCount)
|
||||
for _, item := range items {
|
||||
if item.RawValue.CStatus == pdhCstatusValidData || item.RawValue.CStatus == pdhCstatusNewData {
|
||||
val := counterValue{utf16PtrToString(item.SzName), item.RawValue.FirstValue}
|
||||
values = append(values, val)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// Use the size as a hint if it exceeds the current buffer size
|
||||
if size > buflen {
|
||||
buflen = size
|
||||
}
|
||||
|
||||
// We got a non-recoverable error so exit here
|
||||
if ret != pdhMoreData {
|
||||
return nil, newPdhError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errBufferLimitReached
|
||||
}
|
||||
|
||||
func (m *performanceQueryImpl) collectData() error {
|
||||
var ret uint32
|
||||
if m.query == 0 {
|
||||
return errors.New("uninitialized query")
|
||||
}
|
||||
|
||||
if ret = pdhCollectQueryData(m.query); ret != errorSuccess {
|
||||
return newPdhError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *performanceQueryImpl) collectDataWithTime() (time.Time, error) {
|
||||
if m.query == 0 {
|
||||
return time.Now(), errors.New("uninitialized query")
|
||||
}
|
||||
ret, mtime := pdhCollectQueryDataWithTime(m.query)
|
||||
if ret != errorSuccess {
|
||||
return time.Now(), newPdhError(ret)
|
||||
}
|
||||
return mtime, nil
|
||||
}
|
||||
|
||||
func (*performanceQueryImpl) isVistaOrNewer() bool {
|
||||
return pdhAddEnglishCounterSupported()
|
||||
}
|
||||
|
||||
func (m *performanceQueryImpl) getRawCounterValue(hCounter pdhCounterHandle) (int64, error) {
|
||||
if m.query == 0 {
|
||||
return 0, errors.New("uninitialised query")
|
||||
}
|
||||
|
||||
var counterType uint32
|
||||
var value pdhRawCounter
|
||||
var ret uint32
|
||||
|
||||
if ret = pdhGetRawCounterValue(hCounter, &counterType, &value); ret == errorSuccess {
|
||||
if value.CStatus == pdhCstatusValidData || value.CStatus == pdhCstatusNewData {
|
||||
return value.FirstValue, nil
|
||||
}
|
||||
return 0, newPdhError(value.CStatus)
|
||||
}
|
||||
return 0, newPdhError(ret)
|
||||
}
|
||||
|
||||
// utf16PtrToString converts Windows API LPTSTR (pointer to string) to go string
|
||||
func utf16PtrToString(s *uint16) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
//nolint:gosec // G103: Valid use of unsafe call to create string from Windows API LPTSTR (pointer to string)
|
||||
return syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(s))[0:])
|
||||
}
|
||||
|
||||
// utf16ToStringArray converts list of Windows API NULL terminated strings to go string array
|
||||
func utf16ToStringArray(buf []uint16) []string {
|
||||
var strings []string
|
||||
nextLineStart := 0
|
||||
stringLine := utf16PtrToString(&buf[0])
|
||||
for stringLine != "" {
|
||||
strings = append(strings, stringLine)
|
||||
nextLineStart += len([]rune(stringLine)) + 1
|
||||
remainingBuf := buf[nextLineStart:]
|
||||
stringLine = utf16PtrToString(&remainingBuf[0])
|
||||
}
|
||||
return strings
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue