Allow use of counter time in win perf counters (#4267)
This commit is contained in:
parent
b2e972cd81
commit
ed2bc1151b
|
@ -72,6 +72,15 @@ It is recommended NOT to use this on OSes starting with Vista and newer because
|
||||||
Example for Windows Server 2003, this would be set to true:
|
Example for Windows Server 2003, this would be set to true:
|
||||||
`PreVistaSupport=true`
|
`PreVistaSupport=true`
|
||||||
|
|
||||||
|
#### UsePerfCounterTime
|
||||||
|
|
||||||
|
Bool, if set to `true` will request a timestamp along with the PerfCounter data.
|
||||||
|
If se to `false`, current time will be used.
|
||||||
|
|
||||||
|
Supported on Windows Vista/Windows Server 2008 and newer
|
||||||
|
Example:
|
||||||
|
`UsePerfCounterTime=true`
|
||||||
|
|
||||||
### Object
|
### Object
|
||||||
|
|
||||||
See Entry below.
|
See Entry below.
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright (c) 2010 The win Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions
|
||||||
|
// are met:
|
||||||
|
// 1. Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// 3. The names of the authors may not be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// This is the official list of 'win' authors for copyright purposes.
|
||||||
|
//
|
||||||
|
// Alexander Neumann <an2048@googlemail.com>
|
||||||
|
// Joseph Watson <jtwatson@linux-consulting.us>
|
||||||
|
// Kevin Pors <krpors@gmail.com>
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package win_perf_counters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SYSTEMTIME struct {
|
||||||
|
wYear uint16
|
||||||
|
wMonth uint16
|
||||||
|
wDayOfWeek uint16
|
||||||
|
wDay uint16
|
||||||
|
wHour uint16
|
||||||
|
wMinute uint16
|
||||||
|
wSecond uint16
|
||||||
|
wMilliseconds uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type FILETIME struct {
|
||||||
|
dwLowDateTime uint32
|
||||||
|
dwHighDateTime uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Library
|
||||||
|
libkrnDll *syscall.DLL
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
krn_FileTimeToSystemTime *syscall.Proc
|
||||||
|
krn_FileTimeToLocalFileTime *syscall.Proc
|
||||||
|
krn_LocalFileTimeToFileTime *syscall.Proc
|
||||||
|
krn_WideCharToMultiByte *syscall.Proc
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
libkrnDll = syscall.MustLoadDLL("Kernel32.dll")
|
||||||
|
|
||||||
|
krn_FileTimeToSystemTime = libkrnDll.MustFindProc("FileTimeToSystemTime")
|
||||||
|
krn_FileTimeToLocalFileTime = libkrnDll.MustFindProc("FileTimeToLocalFileTime")
|
||||||
|
krn_LocalFileTimeToFileTime = libkrnDll.MustFindProc("LocalFileTimeToFileTime")
|
||||||
|
krn_WideCharToMultiByte = libkrnDll.MustFindProc("WideCharToMultiByte")
|
||||||
|
}
|
|
@ -38,12 +38,15 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error codes
|
// Error codes
|
||||||
const (
|
const (
|
||||||
ERROR_SUCCESS = 0
|
ERROR_SUCCESS = 0
|
||||||
|
ERROR_FAILURE = 1
|
||||||
ERROR_INVALID_FUNCTION = 1
|
ERROR_INVALID_FUNCTION = 1
|
||||||
|
EPOCH_DIFFERENCE_MICROS int64 = 11644473600000000
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -170,6 +173,7 @@ var (
|
||||||
pdh_AddEnglishCounterW *syscall.Proc
|
pdh_AddEnglishCounterW *syscall.Proc
|
||||||
pdh_CloseQuery *syscall.Proc
|
pdh_CloseQuery *syscall.Proc
|
||||||
pdh_CollectQueryData *syscall.Proc
|
pdh_CollectQueryData *syscall.Proc
|
||||||
|
pdh_CollectQueryDataWithTime *syscall.Proc
|
||||||
pdh_GetFormattedCounterValue *syscall.Proc
|
pdh_GetFormattedCounterValue *syscall.Proc
|
||||||
pdh_GetFormattedCounterArrayW *syscall.Proc
|
pdh_GetFormattedCounterArrayW *syscall.Proc
|
||||||
pdh_OpenQuery *syscall.Proc
|
pdh_OpenQuery *syscall.Proc
|
||||||
|
@ -187,6 +191,7 @@ func init() {
|
||||||
pdh_AddEnglishCounterW, _ = libpdhDll.FindProc("PdhAddEnglishCounterW") // XXX: only supported on versions > Vista.
|
pdh_AddEnglishCounterW, _ = libpdhDll.FindProc("PdhAddEnglishCounterW") // XXX: only supported on versions > Vista.
|
||||||
pdh_CloseQuery = libpdhDll.MustFindProc("PdhCloseQuery")
|
pdh_CloseQuery = libpdhDll.MustFindProc("PdhCloseQuery")
|
||||||
pdh_CollectQueryData = libpdhDll.MustFindProc("PdhCollectQueryData")
|
pdh_CollectQueryData = libpdhDll.MustFindProc("PdhCollectQueryData")
|
||||||
|
pdh_CollectQueryDataWithTime, _ = libpdhDll.FindProc("PdhCollectQueryDataWithTime")
|
||||||
pdh_GetFormattedCounterValue = libpdhDll.MustFindProc("PdhGetFormattedCounterValue")
|
pdh_GetFormattedCounterValue = libpdhDll.MustFindProc("PdhGetFormattedCounterValue")
|
||||||
pdh_GetFormattedCounterArrayW = libpdhDll.MustFindProc("PdhGetFormattedCounterArrayW")
|
pdh_GetFormattedCounterArrayW = libpdhDll.MustFindProc("PdhGetFormattedCounterArrayW")
|
||||||
pdh_OpenQuery = libpdhDll.MustFindProc("PdhOpenQuery")
|
pdh_OpenQuery = libpdhDll.MustFindProc("PdhOpenQuery")
|
||||||
|
@ -303,6 +308,37 @@ func PdhCollectQueryData(hQuery PDH_HQUERY) uint32 {
|
||||||
return uint32(ret)
|
return uint32(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PdhCollectQueryDataWithTime queries data from perfmon, retrieving the device/windows timestamp from the node it was collected on.
|
||||||
|
// Converts the filetime structure to a GO time class and returns the native time.
|
||||||
|
//
|
||||||
|
func PdhCollectQueryDataWithTime(hQuery PDH_HQUERY) (uint32, time.Time) {
|
||||||
|
var localFileTime FILETIME
|
||||||
|
ret, _, _ := pdh_CollectQueryDataWithTime.Call(uintptr(hQuery), uintptr(unsafe.Pointer(&localFileTime)))
|
||||||
|
|
||||||
|
if ret == ERROR_SUCCESS {
|
||||||
|
var utcFileTime FILETIME
|
||||||
|
ret, _, _ := krn_LocalFileTimeToFileTime.Call(
|
||||||
|
uintptr(unsafe.Pointer(&localFileTime)),
|
||||||
|
uintptr(unsafe.Pointer(&utcFileTime)))
|
||||||
|
|
||||||
|
if ret == 0 {
|
||||||
|
return uint32(ERROR_FAILURE), time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// First convert 100-ns intervals to microseconds, then adjust for the
|
||||||
|
// epoch difference
|
||||||
|
var totalMicroSeconds int64
|
||||||
|
totalMicroSeconds = ((int64(utcFileTime.dwHighDateTime) << 32) | int64(utcFileTime.dwLowDateTime)) / 10
|
||||||
|
totalMicroSeconds -= EPOCH_DIFFERENCE_MICROS
|
||||||
|
|
||||||
|
retTime := time.Unix(0, totalMicroSeconds*1000)
|
||||||
|
|
||||||
|
return uint32(ERROR_SUCCESS), retTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint32(ret), time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
// PdhGetFormattedCounterValueDouble formats the given hCounter using a 'double'. The result is set into the specialized union struct pValue.
|
// PdhGetFormattedCounterValueDouble formats the given hCounter using a 'double'. The result is set into the specialized union struct pValue.
|
||||||
// This function does not directly translate to a Windows counterpart due to union specialization tricks.
|
// This function does not directly translate to a Windows counterpart due to union specialization tricks.
|
||||||
func PdhGetFormattedCounterValueDouble(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_DOUBLE) uint32 {
|
func PdhGetFormattedCounterValueDouble(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_DOUBLE) uint32 {
|
||||||
|
|
|
@ -6,6 +6,7 @@ package win_perf_counters
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,7 +27,8 @@ type PerformanceQuery interface {
|
||||||
GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error)
|
GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error)
|
||||||
GetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER) ([]CounterValue, error)
|
GetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER) ([]CounterValue, error)
|
||||||
CollectData() error
|
CollectData() error
|
||||||
AddEnglishCounterSupported() bool
|
CollectDataWithTime() (time.Time, error)
|
||||||
|
IsVistaOrNewer() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//PdhError represents error returned from Performance Counters API
|
//PdhError represents error returned from Performance Counters API
|
||||||
|
@ -61,8 +63,8 @@ func (m *PerformanceQueryImpl) Open() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var handle PDH_HQUERY
|
var handle PDH_HQUERY
|
||||||
ret := PdhOpenQuery(0, 0, &handle)
|
|
||||||
if ret != ERROR_SUCCESS {
|
if ret := PdhOpenQuery(0, 0, &handle); ret != ERROR_SUCCESS {
|
||||||
return NewPdhError(ret)
|
return NewPdhError(ret)
|
||||||
}
|
}
|
||||||
m.query = handle
|
m.query = handle
|
||||||
|
@ -74,8 +76,8 @@ func (m *PerformanceQueryImpl) Close() error {
|
||||||
if m.query == 0 {
|
if m.query == 0 {
|
||||||
return errors.New("uninitialised query")
|
return errors.New("uninitialised query")
|
||||||
}
|
}
|
||||||
ret := PdhCloseQuery(m.query)
|
|
||||||
if ret != ERROR_SUCCESS {
|
if ret := PdhCloseQuery(m.query); ret != ERROR_SUCCESS {
|
||||||
return NewPdhError(ret)
|
return NewPdhError(ret)
|
||||||
}
|
}
|
||||||
m.query = 0
|
m.query = 0
|
||||||
|
@ -87,8 +89,8 @@ func (m *PerformanceQueryImpl) AddCounterToQuery(counterPath string) (PDH_HCOUNT
|
||||||
if m.query == 0 {
|
if m.query == 0 {
|
||||||
return 0, errors.New("uninitialised query")
|
return 0, errors.New("uninitialised query")
|
||||||
}
|
}
|
||||||
ret := PdhAddCounter(m.query, counterPath, 0, &counterHandle)
|
|
||||||
if ret != ERROR_SUCCESS {
|
if ret := PdhAddCounter(m.query, counterPath, 0, &counterHandle); ret != ERROR_SUCCESS {
|
||||||
return 0, NewPdhError(ret)
|
return 0, NewPdhError(ret)
|
||||||
}
|
}
|
||||||
return counterHandle, nil
|
return counterHandle, nil
|
||||||
|
@ -99,8 +101,7 @@ func (m *PerformanceQueryImpl) AddEnglishCounterToQuery(counterPath string) (PDH
|
||||||
if m.query == 0 {
|
if m.query == 0 {
|
||||||
return 0, errors.New("uninitialised query")
|
return 0, errors.New("uninitialised query")
|
||||||
}
|
}
|
||||||
ret := PdhAddEnglishCounter(m.query, counterPath, 0, &counterHandle)
|
if ret := PdhAddEnglishCounter(m.query, counterPath, 0, &counterHandle); ret != ERROR_SUCCESS {
|
||||||
if ret != ERROR_SUCCESS {
|
|
||||||
return 0, NewPdhError(ret)
|
return 0, NewPdhError(ret)
|
||||||
}
|
}
|
||||||
return counterHandle, nil
|
return counterHandle, nil
|
||||||
|
@ -110,13 +111,11 @@ func (m *PerformanceQueryImpl) AddEnglishCounterToQuery(counterPath string) (PDH
|
||||||
func (m *PerformanceQueryImpl) GetCounterPath(counterHandle PDH_HCOUNTER) (string, error) {
|
func (m *PerformanceQueryImpl) GetCounterPath(counterHandle PDH_HCOUNTER) (string, error) {
|
||||||
var bufSize uint32
|
var bufSize uint32
|
||||||
var buff []byte
|
var buff []byte
|
||||||
|
var ret uint32
|
||||||
ret := PdhGetCounterInfo(counterHandle, 0, &bufSize, nil)
|
if ret = PdhGetCounterInfo(counterHandle, 0, &bufSize, nil); ret == PDH_MORE_DATA {
|
||||||
if ret == PDH_MORE_DATA {
|
|
||||||
buff = make([]byte, bufSize)
|
buff = make([]byte, bufSize)
|
||||||
bufSize = uint32(len(buff))
|
bufSize = uint32(len(buff))
|
||||||
ret = PdhGetCounterInfo(counterHandle, 0, &bufSize, &buff[0])
|
if ret = PdhGetCounterInfo(counterHandle, 0, &bufSize, &buff[0]); ret == ERROR_SUCCESS {
|
||||||
if ret == ERROR_SUCCESS {
|
|
||||||
ci := (*PDH_COUNTER_INFO)(unsafe.Pointer(&buff[0]))
|
ci := (*PDH_COUNTER_INFO)(unsafe.Pointer(&buff[0]))
|
||||||
return UTF16PtrToString(ci.SzFullPath), nil
|
return UTF16PtrToString(ci.SzFullPath), nil
|
||||||
}
|
}
|
||||||
|
@ -128,9 +127,9 @@ func (m *PerformanceQueryImpl) GetCounterPath(counterHandle PDH_HCOUNTER) (strin
|
||||||
func (m *PerformanceQueryImpl) ExpandWildCardPath(counterPath string) ([]string, error) {
|
func (m *PerformanceQueryImpl) ExpandWildCardPath(counterPath string) ([]string, error) {
|
||||||
var bufSize uint32
|
var bufSize uint32
|
||||||
var buff []uint16
|
var buff []uint16
|
||||||
|
var ret uint32
|
||||||
|
|
||||||
ret := PdhExpandWildCardPath(counterPath, nil, &bufSize)
|
if ret = PdhExpandWildCardPath(counterPath, nil, &bufSize); ret == PDH_MORE_DATA {
|
||||||
if ret == PDH_MORE_DATA {
|
|
||||||
buff = make([]uint16, bufSize)
|
buff = make([]uint16, bufSize)
|
||||||
bufSize = uint32(len(buff))
|
bufSize = uint32(len(buff))
|
||||||
ret = PdhExpandWildCardPath(counterPath, &buff[0], &bufSize)
|
ret = PdhExpandWildCardPath(counterPath, &buff[0], &bufSize)
|
||||||
|
@ -146,8 +145,9 @@ func (m *PerformanceQueryImpl) ExpandWildCardPath(counterPath string) ([]string,
|
||||||
func (m *PerformanceQueryImpl) GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error) {
|
func (m *PerformanceQueryImpl) GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error) {
|
||||||
var counterType uint32
|
var counterType uint32
|
||||||
var value PDH_FMT_COUNTERVALUE_DOUBLE
|
var value PDH_FMT_COUNTERVALUE_DOUBLE
|
||||||
ret := PdhGetFormattedCounterValueDouble(hCounter, &counterType, &value)
|
var ret uint32
|
||||||
if ret == ERROR_SUCCESS {
|
|
||||||
|
if ret = PdhGetFormattedCounterValueDouble(hCounter, &counterType, &value); ret == ERROR_SUCCESS {
|
||||||
if value.CStatus == PDH_CSTATUS_VALID_DATA || value.CStatus == PDH_CSTATUS_NEW_DATA {
|
if value.CStatus == PDH_CSTATUS_VALID_DATA || value.CStatus == PDH_CSTATUS_NEW_DATA {
|
||||||
return value.DoubleValue, nil
|
return value.DoubleValue, nil
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,11 +161,12 @@ func (m *PerformanceQueryImpl) GetFormattedCounterValueDouble(hCounter PDH_HCOUN
|
||||||
func (m *PerformanceQueryImpl) GetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER) ([]CounterValue, error) {
|
func (m *PerformanceQueryImpl) GetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER) ([]CounterValue, error) {
|
||||||
var buffSize uint32
|
var buffSize uint32
|
||||||
var itemCount uint32
|
var itemCount uint32
|
||||||
ret := PdhGetFormattedCounterArrayDouble(hCounter, &buffSize, &itemCount, nil)
|
var ret uint32
|
||||||
if ret == PDH_MORE_DATA {
|
|
||||||
|
if ret = PdhGetFormattedCounterArrayDouble(hCounter, &buffSize, &itemCount, nil); ret == PDH_MORE_DATA {
|
||||||
buff := make([]byte, buffSize)
|
buff := make([]byte, buffSize)
|
||||||
ret = PdhGetFormattedCounterArrayDouble(hCounter, &buffSize, &itemCount, &buff[0])
|
|
||||||
if ret == ERROR_SUCCESS {
|
if ret = PdhGetFormattedCounterArrayDouble(hCounter, &buffSize, &itemCount, &buff[0]); ret == ERROR_SUCCESS {
|
||||||
items := (*[1 << 20]PDH_FMT_COUNTERVALUE_ITEM_DOUBLE)(unsafe.Pointer(&buff[0]))[:itemCount]
|
items := (*[1 << 20]PDH_FMT_COUNTERVALUE_ITEM_DOUBLE)(unsafe.Pointer(&buff[0]))[:itemCount]
|
||||||
values := make([]CounterValue, 0, itemCount)
|
values := make([]CounterValue, 0, itemCount)
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
|
@ -181,17 +182,29 @@ func (m *PerformanceQueryImpl) GetFormattedCounterArrayDouble(hCounter PDH_HCOUN
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PerformanceQueryImpl) CollectData() error {
|
func (m *PerformanceQueryImpl) CollectData() error {
|
||||||
|
var ret uint32
|
||||||
if m.query == 0 {
|
if m.query == 0 {
|
||||||
return errors.New("uninitialised query")
|
return errors.New("uninitialised query")
|
||||||
}
|
}
|
||||||
ret := PdhCollectQueryData(m.query)
|
|
||||||
if ret != ERROR_SUCCESS {
|
if ret = PdhCollectQueryData(m.query); ret != ERROR_SUCCESS {
|
||||||
return NewPdhError(ret)
|
return NewPdhError(ret)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PerformanceQueryImpl) AddEnglishCounterSupported() bool {
|
func (m *PerformanceQueryImpl) CollectDataWithTime() (time.Time, error) {
|
||||||
|
if m.query == 0 {
|
||||||
|
return time.Now(), errors.New("uninitialised query")
|
||||||
|
}
|
||||||
|
ret, mtime := PdhCollectQueryDataWithTime(m.query)
|
||||||
|
if ret != ERROR_SUCCESS {
|
||||||
|
return time.Now(), NewPdhError(ret)
|
||||||
|
}
|
||||||
|
return mtime, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PerformanceQueryImpl) IsVistaOrNewer() bool {
|
||||||
return PdhAddEnglishCounterSupported()
|
return PdhAddEnglishCounterSupported()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ var sampleConfig = `
|
||||||
## agent, it will not be gathered.
|
## agent, it will not be gathered.
|
||||||
## Settings:
|
## Settings:
|
||||||
# PrintValid = false # Print All matching performance counters
|
# PrintValid = false # Print All matching performance counters
|
||||||
|
# Whether request a timestamp along with the PerfCounter data or just use current time
|
||||||
|
# UsePerfCounterTime=true
|
||||||
# If UseWildcardsExpansion params is set to true, wildcards (partial wildcards in instance names and wildcards in counters names) in configured counter paths will be expanded
|
# If UseWildcardsExpansion params is set to true, wildcards (partial wildcards in instance names and wildcards in counters names) in configured counter paths will be expanded
|
||||||
# and in case of localized Windows, counter paths will be also localized. It also returns instance indexes in instance names.
|
# and in case of localized Windows, counter paths will be also localized. It also returns instance indexes in instance names.
|
||||||
# If false, wildcards (not partial) in instance names will still be expanded, but instance indexes will not be returned in instance names.
|
# If false, wildcards (not partial) in instance names will still be expanded, but instance indexes will not be returned in instance names.
|
||||||
|
@ -78,6 +80,7 @@ type Win_PerfCounters struct {
|
||||||
PrintValid bool
|
PrintValid bool
|
||||||
//deprecated: determined dynamically
|
//deprecated: determined dynamically
|
||||||
PreVistaSupport bool
|
PreVistaSupport bool
|
||||||
|
UsePerfCounterTime bool
|
||||||
Object []perfobject
|
Object []perfobject
|
||||||
CountersRefreshInterval internal.Duration
|
CountersRefreshInterval internal.Duration
|
||||||
UseWildcardsExpansion bool
|
UseWildcardsExpansion bool
|
||||||
|
@ -107,6 +110,12 @@ type counter struct {
|
||||||
counterHandle PDH_HCOUNTER
|
counterHandle PDH_HCOUNTER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type instanceGrouping struct {
|
||||||
|
name string
|
||||||
|
instance string
|
||||||
|
objectname string
|
||||||
|
}
|
||||||
|
|
||||||
var sanitizedChars = strings.NewReplacer("/sec", "_persec", "/Sec", "_persec",
|
var sanitizedChars = strings.NewReplacer("/sec", "_persec", "/Sec", "_persec",
|
||||||
" ", "_", "%", "Percent", `\`, "")
|
" ", "_", "%", "Percent", `\`, "")
|
||||||
|
|
||||||
|
@ -147,7 +156,7 @@ func (m *Win_PerfCounters) SampleConfig() string {
|
||||||
func (m *Win_PerfCounters) AddItem(counterPath string, objectName string, instance string, counterName string, measurement string, includeTotal bool) error {
|
func (m *Win_PerfCounters) AddItem(counterPath string, objectName string, instance string, counterName string, measurement string, includeTotal bool) error {
|
||||||
var err error
|
var err error
|
||||||
var counterHandle PDH_HCOUNTER
|
var counterHandle PDH_HCOUNTER
|
||||||
if !m.query.AddEnglishCounterSupported() {
|
if !m.query.IsVistaOrNewer() {
|
||||||
counterHandle, err = m.query.AddCounterToQuery(counterPath)
|
counterHandle, err = m.query.AddCounterToQuery(counterPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -249,18 +258,15 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
|
||||||
m.counters = m.counters[:0]
|
m.counters = m.counters[:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.query.Open()
|
if err = m.query.Open(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.ParseConfig()
|
if err = m.ParseConfig(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//some counters need two data samples before computing a value
|
//some counters need two data samples before computing a value
|
||||||
err = m.query.CollectData()
|
if err = m.query.CollectData(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m.lastRefreshed = time.Now()
|
m.lastRefreshed = time.Now()
|
||||||
|
@ -268,37 +274,31 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
type InstanceGrouping struct {
|
var collectFields = make(map[instanceGrouping]map[string]interface{})
|
||||||
name string
|
|
||||||
instance string
|
|
||||||
objectname string
|
|
||||||
}
|
|
||||||
|
|
||||||
var collectFields = make(map[InstanceGrouping]map[string]interface{})
|
var timestamp time.Time
|
||||||
|
if m.UsePerfCounterTime && m.query.IsVistaOrNewer() {
|
||||||
err = m.query.CollectData()
|
timestamp, err = m.query.CollectDataWithTime()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
timestamp = time.Now()
|
||||||
|
if err = m.query.CollectData(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For iterate over the known metrics and get the samples.
|
// For iterate over the known metrics and get the samples.
|
||||||
for _, metric := range m.counters {
|
for _, metric := range m.counters {
|
||||||
// collect
|
// collect
|
||||||
if m.UseWildcardsExpansion {
|
if m.UseWildcardsExpansion {
|
||||||
value, err := m.query.GetFormattedCounterValueDouble(metric.counterHandle)
|
value, err := m.query.GetFormattedCounterValueDouble(metric.counterHandle)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
measurement := sanitizedChars.Replace(metric.measurement)
|
addCounterMeasurement(metric, metric.instance, value, collectFields)
|
||||||
if measurement == "" {
|
|
||||||
measurement = "win_perf_counters"
|
|
||||||
}
|
|
||||||
|
|
||||||
var instance = InstanceGrouping{measurement, metric.instance, metric.objectName}
|
|
||||||
if collectFields[instance] == nil {
|
|
||||||
collectFields[instance] = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
collectFields[instance][sanitizedChars.Replace(metric.counter)] = float32(value)
|
|
||||||
} else {
|
} else {
|
||||||
//ignore invalid data from as some counters from process instances returns this sometimes
|
//ignore invalid data as some counters from process instances returns this sometimes
|
||||||
if phderr, ok := err.(*PdhError); ok && phderr.ErrorCode != PDH_INVALID_DATA && phderr.ErrorCode != PDH_CALC_NEGATIVE_VALUE {
|
if !isKnownCounterDataError(err) {
|
||||||
return fmt.Errorf("error while getting value for counter %s: %v", metric.counterPath, err)
|
return fmt.Errorf("error while getting value for counter %s: %v", metric.counterPath, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,17 +326,13 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if add {
|
if add {
|
||||||
measurement := sanitizedChars.Replace(metric.measurement)
|
addCounterMeasurement(metric, cValue.InstanceName, cValue.Value, collectFields)
|
||||||
if measurement == "" {
|
|
||||||
measurement = "win_perf_counters"
|
|
||||||
}
|
}
|
||||||
var instance = InstanceGrouping{measurement, cValue.InstanceName, metric.objectName}
|
|
||||||
|
|
||||||
if collectFields[instance] == nil {
|
|
||||||
collectFields[instance] = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
collectFields[instance][sanitizedChars.Replace(metric.counter)] = float32(cValue.Value)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
//ignore invalid data as some counters from process instances returns this sometimes
|
||||||
|
if !isKnownCounterDataError(err) {
|
||||||
|
return fmt.Errorf("error while getting value for counter %s: %v", metric.counterPath, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,12 +345,33 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
|
||||||
if len(instance.instance) > 0 {
|
if len(instance.instance) > 0 {
|
||||||
tags["instance"] = instance.instance
|
tags["instance"] = instance.instance
|
||||||
}
|
}
|
||||||
acc.AddFields(instance.name, fields, tags)
|
acc.AddFields(instance.name, fields, tags, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addCounterMeasurement(metric *counter, instanceName string, value float64, collectFields map[instanceGrouping]map[string]interface{}) {
|
||||||
|
measurement := sanitizedChars.Replace(metric.measurement)
|
||||||
|
if measurement == "" {
|
||||||
|
measurement = "win_perf_counters"
|
||||||
|
}
|
||||||
|
var instance = instanceGrouping{measurement, instanceName, metric.objectName}
|
||||||
|
if collectFields[instance] == nil {
|
||||||
|
collectFields[instance] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
collectFields[instance][sanitizedChars.Replace(metric.counter)] = float32(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isKnownCounterDataError(err error) bool {
|
||||||
|
if pdhErr, ok := err.(*PdhError); ok && (pdhErr.ErrorCode == PDH_INVALID_DATA ||
|
||||||
|
pdhErr.ErrorCode == PDH_CALC_NEGATIVE_VALUE ||
|
||||||
|
pdhErr.ErrorCode == PDH_CSTATUS_INVALID_DATA) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
inputs.Add("win_perf_counters", func() telegraf.Input {
|
inputs.Add("win_perf_counters", func() telegraf.Input {
|
||||||
return &Win_PerfCounters{query: &PerformanceQueryImpl{}, CountersRefreshInterval: internal.Duration{Duration: time.Second * 60}}
|
return &Win_PerfCounters{query: &PerformanceQueryImpl{}, CountersRefreshInterval: internal.Duration{Duration: time.Second * 60}}
|
||||||
|
|
|
@ -70,6 +70,11 @@ func TestWinPerformanceQueryImpl(t *testing.T) {
|
||||||
_, err = query.GetFormattedCounterValueDouble(hCounter)
|
_, err = query.GetFormattedCounterValueDouble(hCounter)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
mtime, err := query.CollectDataWithTime()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, mtime.Sub(now) < time.Second)
|
||||||
|
|
||||||
counterPath = "\\Process(*)\\% Processor Time"
|
counterPath = "\\Process(*)\\% Processor Time"
|
||||||
paths, err := query.ExpandWildCardPath(counterPath)
|
paths, err := query.ExpandWildCardPath(counterPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -98,6 +103,10 @@ func TestWinPerformanceQueryImpl(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
arr, err := query.GetFormattedCounterArrayDouble(hCounter)
|
arr, err := query.GetFormattedCounterArrayDouble(hCounter)
|
||||||
|
if phderr, ok := err.(*PdhError); ok && phderr.ErrorCode != PDH_INVALID_DATA && phderr.ErrorCode != PDH_CALC_NEGATIVE_VALUE {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
arr, err = query.GetFormattedCounterArrayDouble(hCounter)
|
||||||
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.True(t, len(arr) > 0, "Too")
|
assert.True(t, len(arr) > 0, "Too")
|
||||||
|
|
||||||
|
@ -596,7 +605,7 @@ func TestWinPerfcountersCollect2(t *testing.T) {
|
||||||
|
|
||||||
perfobjects[0] = PerfObject
|
perfobjects[0] = PerfObject
|
||||||
|
|
||||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}, UseWildcardsExpansion: true}
|
m := Win_PerfCounters{PrintValid: false, UsePerfCounterTime: true, Object: perfobjects, query: &PerformanceQueryImpl{}, UseWildcardsExpansion: true}
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
err := m.Gather(&acc)
|
err := m.Gather(&acc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -20,11 +20,13 @@ type testCounter struct {
|
||||||
}
|
}
|
||||||
type FakePerformanceQuery struct {
|
type FakePerformanceQuery struct {
|
||||||
counters map[string]testCounter
|
counters map[string]testCounter
|
||||||
addEnglishSupported bool
|
vistaAndNewer bool
|
||||||
expandPaths map[string][]string
|
expandPaths map[string][]string
|
||||||
openCalled bool
|
openCalled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var MetricTime = time.Date(2018, 5, 28, 12, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
func (m *testCounter) ToCounterValue() *CounterValue {
|
func (m *testCounter) ToCounterValue() *CounterValue {
|
||||||
_, inst, _, _ := extractObjectInstanceCounterFromQuery(m.path)
|
_, inst, _, _ := extractObjectInstanceCounterFromQuery(m.path)
|
||||||
if inst == "" {
|
if inst == "" {
|
||||||
|
@ -102,8 +104,10 @@ func (m *FakePerformanceQuery) GetFormattedCounterValueDouble(counterHandle PDH_
|
||||||
} else {
|
} else {
|
||||||
if counter.value == 0 {
|
if counter.value == 0 {
|
||||||
return 0, NewPdhError(PDH_INVALID_DATA)
|
return 0, NewPdhError(PDH_INVALID_DATA)
|
||||||
} else {
|
} else if counter.value == -1 {
|
||||||
return 0, NewPdhError(PDH_CALC_NEGATIVE_VALUE)
|
return 0, NewPdhError(PDH_CALC_NEGATIVE_VALUE)
|
||||||
|
} else {
|
||||||
|
return 0, NewPdhError(PDH_ACCESS_DENIED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,8 +142,18 @@ func (m *FakePerformanceQuery) GetFormattedCounterArrayDouble(hCounter PDH_HCOUN
|
||||||
counters := make([]CounterValue, 0, len(e))
|
counters := make([]CounterValue, 0, len(e))
|
||||||
for _, p := range e {
|
for _, p := range e {
|
||||||
counter := m.findCounterByPath(p)
|
counter := m.findCounterByPath(p)
|
||||||
if counter != nil && counter.value > 0 {
|
if counter != nil {
|
||||||
|
if counter.value > 0 {
|
||||||
counters = append(counters, *counter.ToCounterValue())
|
counters = append(counters, *counter.ToCounterValue())
|
||||||
|
} else {
|
||||||
|
if counter.value == 0 {
|
||||||
|
return nil, NewPdhError(PDH_INVALID_DATA)
|
||||||
|
} else if counter.value == -1 {
|
||||||
|
return nil, NewPdhError(PDH_CALC_NEGATIVE_VALUE)
|
||||||
|
} else {
|
||||||
|
return nil, NewPdhError(PDH_ACCESS_DENIED)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("GetFormattedCounterArrayDouble: invalid counter : %s", p)
|
return nil, fmt.Errorf("GetFormattedCounterArrayDouble: invalid counter : %s", p)
|
||||||
}
|
}
|
||||||
|
@ -160,8 +174,15 @@ func (m *FakePerformanceQuery) CollectData() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *FakePerformanceQuery) AddEnglishCounterSupported() bool {
|
func (m *FakePerformanceQuery) CollectDataWithTime() (time.Time, error) {
|
||||||
return m.addEnglishSupported
|
if !m.openCalled {
|
||||||
|
return time.Now(), errors.New("CollectData: uninitialised query")
|
||||||
|
}
|
||||||
|
return MetricTime, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FakePerformanceQuery) IsVistaOrNewer() bool {
|
||||||
|
return m.vistaAndNewer
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPerfObject(measurement string, object string, instances []string, counters []string, failOnMissing bool, includeTotal bool) []perfobject {
|
func createPerfObject(measurement string, object string, instances []string, counters []string, failOnMissing bool, includeTotal bool) []perfobject {
|
||||||
|
@ -198,7 +219,7 @@ func TestAddItemSimple(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
cps1[0]: cps1,
|
cps1[0]: cps1,
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -216,7 +237,7 @@ func TestAddItemInvalidCountPath(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
cps1[0]: {"\\O/C"},
|
cps1[0]: {"\\O/C"},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -238,7 +259,7 @@ func TestParseConfigBasic(t *testing.T) {
|
||||||
cps1[2]: {cps1[2]},
|
cps1[2]: {cps1[2]},
|
||||||
cps1[3]: {cps1[3]},
|
cps1[3]: {cps1[3]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -270,7 +291,7 @@ func TestParseConfigNoInstance(t *testing.T) {
|
||||||
cps1[0]: {cps1[0]},
|
cps1[0]: {cps1[0]},
|
||||||
cps1[1]: {cps1[1]},
|
cps1[1]: {cps1[1]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -303,7 +324,7 @@ func TestParseConfigInvalidCounterError(t *testing.T) {
|
||||||
cps1[1]: {cps1[1]},
|
cps1[1]: {cps1[1]},
|
||||||
cps1[2]: {cps1[2]},
|
cps1[2]: {cps1[2]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -334,7 +355,7 @@ func TestParseConfigInvalidCounterNoError(t *testing.T) {
|
||||||
cps1[1]: {cps1[1]},
|
cps1[1]: {cps1[1]},
|
||||||
cps1[2]: {cps1[2]},
|
cps1[2]: {cps1[2]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -364,7 +385,7 @@ func TestParseConfigTotalExpansion(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
"\\O(*)\\*": cps1,
|
"\\O(*)\\*": cps1,
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -381,7 +402,7 @@ func TestParseConfigTotalExpansion(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
"\\O(*)\\*": cps1,
|
"\\O(*)\\*": cps1,
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -401,7 +422,7 @@ func TestParseConfigExpand(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
"\\O(*)\\*": cps1,
|
"\\O(*)\\*": cps1,
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
err = m.query.Open()
|
err = m.query.Open()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -425,7 +446,7 @@ func TestSimpleGather(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
cp1: {cp1},
|
cp1: {cp1},
|
||||||
},
|
},
|
||||||
addEnglishSupported: false,
|
vistaAndNewer: false,
|
||||||
}}
|
}}
|
||||||
var acc1 testutil.Accumulator
|
var acc1 testutil.Accumulator
|
||||||
err = m.Gather(&acc1)
|
err = m.Gather(&acc1)
|
||||||
|
@ -449,7 +470,65 @@ func TestSimpleGather(t *testing.T) {
|
||||||
err = m.Gather(&acc2)
|
err = m.Gather(&acc2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimpleGatherWithTimestamp(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping long taking test in short mode")
|
||||||
|
}
|
||||||
|
measurement := "test"
|
||||||
|
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false)
|
||||||
|
cp1 := "\\O(I)\\C"
|
||||||
|
m := Win_PerfCounters{PrintValid: false, UsePerfCounterTime: true, Object: perfObjects, query: &FakePerformanceQuery{
|
||||||
|
counters: createCounterMap([]string{cp1}, []float64{1.2}),
|
||||||
|
expandPaths: map[string][]string{
|
||||||
|
cp1: {cp1},
|
||||||
|
},
|
||||||
|
vistaAndNewer: true,
|
||||||
|
}}
|
||||||
|
var acc1 testutil.Accumulator
|
||||||
|
err = m.Gather(&acc1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fields1 := map[string]interface{}{
|
||||||
|
"C": float32(1.2),
|
||||||
|
}
|
||||||
|
tags1 := map[string]string{
|
||||||
|
"instance": "I",
|
||||||
|
"objectname": "O",
|
||||||
|
}
|
||||||
|
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
||||||
|
assert.True(t, acc1.HasTimestamp(measurement, MetricTime))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGatherError(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping long taking test in short mode")
|
||||||
|
}
|
||||||
|
measurement := "test"
|
||||||
|
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false)
|
||||||
|
cp1 := "\\O(I)\\C"
|
||||||
|
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||||
|
counters: createCounterMap([]string{cp1}, []float64{-2}),
|
||||||
|
expandPaths: map[string][]string{
|
||||||
|
cp1: {cp1},
|
||||||
|
},
|
||||||
|
vistaAndNewer: false,
|
||||||
|
}}
|
||||||
|
var acc1 testutil.Accumulator
|
||||||
|
err = m.Gather(&acc1)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
m.UseWildcardsExpansion = true
|
||||||
|
m.counters = nil
|
||||||
|
m.lastRefreshed = time.Time{}
|
||||||
|
|
||||||
|
var acc2 testutil.Accumulator
|
||||||
|
|
||||||
|
err = m.Gather(&acc2)
|
||||||
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGatherInvalidDataIgnore(t *testing.T) {
|
func TestGatherInvalidDataIgnore(t *testing.T) {
|
||||||
|
@ -467,7 +546,7 @@ func TestGatherInvalidDataIgnore(t *testing.T) {
|
||||||
cps1[1]: {cps1[1]},
|
cps1[1]: {cps1[1]},
|
||||||
cps1[2]: {cps1[2]},
|
cps1[2]: {cps1[2]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: false,
|
vistaAndNewer: false,
|
||||||
}}
|
}}
|
||||||
var acc1 testutil.Accumulator
|
var acc1 testutil.Accumulator
|
||||||
err = m.Gather(&acc1)
|
err = m.Gather(&acc1)
|
||||||
|
@ -506,7 +585,7 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
"\\O(*)\\*": cps1,
|
"\\O(*)\\*": cps1,
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}
|
}
|
||||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, UseWildcardsExpansion: true, query: fpm, CountersRefreshInterval: internal.Duration{Duration: time.Second * 10}}
|
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, UseWildcardsExpansion: true, query: fpm, CountersRefreshInterval: internal.Duration{Duration: time.Second * 10}}
|
||||||
var acc1 testutil.Accumulator
|
var acc1 testutil.Accumulator
|
||||||
|
@ -540,7 +619,7 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
|
||||||
expandPaths: map[string][]string{
|
expandPaths: map[string][]string{
|
||||||
"\\O(*)\\*": cps2,
|
"\\O(*)\\*": cps2,
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}
|
}
|
||||||
m.query = fpm
|
m.query = fpm
|
||||||
fpm.Open()
|
fpm.Open()
|
||||||
|
@ -592,7 +671,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
|
||||||
"\\O(*)\\C1": {cps1[0], cps1[2]},
|
"\\O(*)\\C1": {cps1[0], cps1[2]},
|
||||||
"\\O(*)\\C2": {cps1[1], cps1[3]},
|
"\\O(*)\\C2": {cps1[1], cps1[3]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}
|
}
|
||||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, UseWildcardsExpansion: false, query: fpm, CountersRefreshInterval: internal.Duration{Duration: time.Second * 10}}
|
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, UseWildcardsExpansion: false, query: fpm, CountersRefreshInterval: internal.Duration{Duration: time.Second * 10}}
|
||||||
var acc1 testutil.Accumulator
|
var acc1 testutil.Accumulator
|
||||||
|
@ -628,7 +707,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
|
||||||
"\\O(*)\\C1": {cps2[0], cps2[2], cps2[4]},
|
"\\O(*)\\C1": {cps2[0], cps2[2], cps2[4]},
|
||||||
"\\O(*)\\C2": {cps2[1], cps2[3], cps2[5]},
|
"\\O(*)\\C2": {cps2[1], cps2[3], cps2[5]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}
|
}
|
||||||
m.query = fpm
|
m.query = fpm
|
||||||
fpm.Open()
|
fpm.Open()
|
||||||
|
@ -662,7 +741,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
|
||||||
"\\O(*)\\C2": {cps3[1], cps3[4]},
|
"\\O(*)\\C2": {cps3[1], cps3[4]},
|
||||||
"\\O(*)\\C3": {cps3[2], cps3[5]},
|
"\\O(*)\\C3": {cps3[2], cps3[5]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}
|
}
|
||||||
m.query = fpm
|
m.query = fpm
|
||||||
m.Object = perfObjects
|
m.Object = perfObjects
|
||||||
|
@ -710,7 +789,7 @@ func TestGatherTotalNoExpansion(t *testing.T) {
|
||||||
"\\O(*)\\C1": {cps1[0], cps1[2]},
|
"\\O(*)\\C1": {cps1[0], cps1[2]},
|
||||||
"\\O(*)\\C2": {cps1[1], cps1[3]},
|
"\\O(*)\\C2": {cps1[1], cps1[3]},
|
||||||
},
|
},
|
||||||
addEnglishSupported: true,
|
vistaAndNewer: true,
|
||||||
}}
|
}}
|
||||||
var acc1 testutil.Accumulator
|
var acc1 testutil.Accumulator
|
||||||
err = m.Gather(&acc1)
|
err = m.Gather(&acc1)
|
||||||
|
|
Loading…
Reference in New Issue