feat: Implemented support for reading raw values, added tests and doc (#6501)

This commit is contained in:
Vlasta Hajek 2022-02-10 23:03:52 +01:00 committed by GitHub
parent 437d3b0773
commit 3ef1c73582
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 542 additions and 111 deletions

View File

@ -179,7 +179,19 @@ So for ordering your data in a good manner,
this is a good key to set with a value when you want your IIS and Disk results stored
separately from Processor results.
Example: `Measurement = "win_disk"``
Example: `Measurement = "win_disk"`
#### UseRawValues
(Optional)
This key is optional. It is a simple bool.
If set to `true`, counter values will be provided in the raw, integer, form. This is in contrast with the default behavior, where values are returned in a formatted, displayable, form
as seen in the Windows Performance Monitor.
A field representing raw counter value has the `_Raw` suffix. Raw values should be further used in a calculation, e.g. `100-(non_negative_derivative("Percent_Processor_Time_Raw",1s)/100000`
Note: Time based counters (i.e. _% Processor Time_) are reported in hundredths of nanoseconds.
Example: `UseRawValues = true`
#### IncludeTotal

View File

@ -272,6 +272,8 @@ var (
pdh_ValidatePathW *syscall.Proc
pdh_ExpandWildCardPathW *syscall.Proc
pdh_GetCounterInfoW *syscall.Proc
pdh_GetRawCounterValue *syscall.Proc
pdh_GetRawCounterArrayW *syscall.Proc
)
func init() {
@ -290,6 +292,8 @@ func init() {
pdh_ValidatePathW = libpdhDll.MustFindProc("PdhValidatePathW")
pdh_ExpandWildCardPathW = libpdhDll.MustFindProc("PdhExpandWildCardPathW")
pdh_GetCounterInfoW = libpdhDll.MustFindProc("PdhGetCounterInfoW")
pdh_GetRawCounterValue = libpdhDll.MustFindProc("PdhGetRawCounterValue")
pdh_GetRawCounterArrayW = libpdhDll.MustFindProc("PdhGetRawCounterArrayW")
}
// PdhAddCounter adds the specified counter to the query. This is the internationalized version. Preferably, use the
@ -591,3 +595,50 @@ func PdhGetCounterInfo(hCounter PDH_HCOUNTER, bRetrieveExplainText int, pdwBuffe
return uint32(ret)
}
// Returns the current raw value of the counter.
// If the specified counter instance does not exist, this function will return ERROR_SUCCESS
// and the CStatus member of the PDH_RAW_COUNTER structure will contain PDH_CSTATUS_NO_INSTANCE.
//
// hCounter [in]
// Handle of the counter from which to retrieve the current raw value. The PdhAddCounter function returns this handle.
//
// lpdwType [out]
// Receives the counter type. For a list of counter types, see the Counter Types section of the Windows Server 2003 Deployment Kit.
// This parameter is optional.
//
// pValue [out]
// A PDH_RAW_COUNTER structure that receives the counter value.
func PdhGetRawCounterValue(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_RAW_COUNTER) uint32 {
ret, _, _ := pdh_GetRawCounterValue.Call(
uintptr(hCounter),
uintptr(unsafe.Pointer(lpdwType)),
uintptr(unsafe.Pointer(pValue)))
return uint32(ret)
}
// Returns an array of raw values from the specified counter. Use this function when you want to retrieve the raw counter values
// of a counter that contains a wildcard character for the instance name.
// hCounter
// Handle of the counter for whose current raw instance values you want to retrieve. The PdhAddCounter function returns this handle.
//
// lpdwBufferSize
// Size of the ItemBuffer buffer, in bytes. If zero on input, the function returns PDH_MORE_DATA and sets this parameter to the required buffer size.
// If the buffer is larger than the required size, the function sets this parameter to the actual size of the buffer that was used.
// If the specified size on input is greater than zero but less than the required size, you should not rely on the returned size to reallocate the buffer.
//
// lpdwItemCount
// Number of raw counter values in the ItemBuffer buffer.
//
// ItemBuffer
// Caller-allocated buffer that receives the array of PDH_RAW_COUNTER_ITEM structures; the structures contain the raw instance counter values.
// Set to NULL if lpdwBufferSize is zero.
func PdhGetRawCounterArray(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *byte) uint32 {
ret, _, _ := pdh_GetRawCounterArrayW.Call(
uintptr(hCounter),
uintptr(unsafe.Pointer(lpdwBufferSize)),
uintptr(unsafe.Pointer(lpdwBufferCount)),
uintptr(unsafe.Pointer(itemBuffer)))
return uint32(ret)
}

View File

@ -120,3 +120,26 @@ type PDH_COUNTER_INFO struct {
//Start of the string data that is appended to the structure.
DataBuffer [1]uint32 // pointer to an extra space
}
// The PDH_RAW_COUNTER structure returns the data as it was collected from the counter provider. No translation, formatting, or other interpretation is performed on the data
type PDH_RAW_COUNTER struct {
// Counter status that indicates if the counter value is valid. Check this member before using the data in a calculation or displaying its value. For a list of possible values,
// see https://docs.microsoft.com/windows/desktop/PerfCtrs/checking-pdh-interface-return-values
CStatus uint32
// Local time for when the data was collected
TimeStamp FILETIME
// First raw counter value.
FirstValue int64
// Second raw counter value. Rate counters require two values in order to compute a displayable value.
SecondValue int64
// If the counter type contains the PERF_MULTI_COUNTER flag, this member contains the additional counter data used in the calculation.
// For example, the PERF_100NSEC_MULTI_TIMER counter type contains the PERF_MULTI_COUNTER flag.
MultiCount uint32
}
type PDH_RAW_COUNTER_ITEM struct {
// Pointer to a null-terminated string that specifies the instance name of the counter. The string is appended to the end of this structure.
SzName *uint16
//A PDH_RAW_COUNTER structure that contains the raw counter value of the instance
RawValue PDH_RAW_COUNTER
}

View File

@ -113,3 +113,26 @@ type PDH_COUNTER_INFO struct {
//Start of the string data that is appended to the structure.
DataBuffer [1]uint32 // pointer to an extra space
}
// The PDH_RAW_COUNTER structure returns the data as it was collected from the counter provider. No translation, formatting, or other interpretation is performed on the data
type PDH_RAW_COUNTER struct {
// Counter status that indicates if the counter value is valid. Check this member before using the data in a calculation or displaying its value. For a list of possible values,
// see https://docs.microsoft.com/windows/desktop/PerfCtrs/checking-pdh-interface-return-values
CStatus uint32
// Local time for when the data was collected
TimeStamp FILETIME
// First raw counter value.
FirstValue int64
// Second raw counter value. Rate counters require two values in order to compute a displayable value.
SecondValue int64
// If the counter type contains the PERF_MULTI_COUNTER flag, this member contains the additional counter data used in the calculation.
// For example, the PERF_100NSEC_MULTI_TIMER counter type contains the PERF_MULTI_COUNTER flag.
MultiCount uint32
}
type PDH_RAW_COUNTER_ITEM struct {
// Pointer to a null-terminated string that specifies the instance name of the counter. The string is appended to the end of this structure.
SzName *uint16
//A PDH_RAW_COUNTER structure that contains the raw counter value of the instance
RawValue PDH_RAW_COUNTER
}

View File

@ -14,7 +14,7 @@ import (
//PerformanceQuery is abstraction for PDH_FMT_COUNTERVALUE_ITEM_DOUBLE
type CounterValue struct {
InstanceName string
Value float64
Value interface{}
}
//PerformanceQuery provides wrappers around Windows performance counters API for easy usage in GO
@ -26,7 +26,9 @@ type PerformanceQuery interface {
GetCounterPath(counterHandle PDH_HCOUNTER) (string, error)
ExpandWildCardPath(counterPath string) ([]string, error)
GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error)
GetRawCounterValue(hCounter PDH_HCOUNTER) (int64, error)
GetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER) ([]CounterValue, error)
GetRawCounterArray(hCounter PDH_HCOUNTER) ([]CounterValue, error)
CollectData() error
CollectDataWithTime() (time.Time, error)
IsVistaOrNewer() bool
@ -182,6 +184,29 @@ func (m *PerformanceQueryImpl) GetFormattedCounterArrayDouble(hCounter PDH_HCOUN
return nil, NewPdhError(ret)
}
func (m *PerformanceQueryImpl) GetRawCounterArray(hCounter PDH_HCOUNTER) ([]CounterValue, error) {
var buffSize uint32
var itemCount uint32
var ret uint32
if ret = PdhGetRawCounterArray(hCounter, &buffSize, &itemCount, nil); ret == PDH_MORE_DATA {
buff := make([]byte, buffSize)
if ret = PdhGetRawCounterArray(hCounter, &buffSize, &itemCount, &buff[0]); ret == ERROR_SUCCESS {
items := (*[1 << 20]PDH_RAW_COUNTER_ITEM)(unsafe.Pointer(&buff[0]))[:itemCount]
values := make([]CounterValue, 0, itemCount)
for _, item := range items {
if item.RawValue.CStatus == PDH_CSTATUS_VALID_DATA || item.RawValue.CStatus == PDH_CSTATUS_NEW_DATA {
val := CounterValue{UTF16PtrToString(item.SzName), item.RawValue.FirstValue}
values = append(values, val)
}
}
return values, nil
}
}
return nil, NewPdhError(ret)
}
func (m *PerformanceQueryImpl) CollectData() error {
var ret uint32
if m.query == 0 {
@ -209,6 +234,27 @@ func (m *PerformanceQueryImpl) IsVistaOrNewer() bool {
return PdhAddEnglishCounterSupported()
}
func (m *PerformanceQueryImpl) GetRawCounterValue(hCounter PDH_HCOUNTER) (int64, error) {
if m.query == 0 {
return 0, errors.New("uninitialised query")
}
var counterType uint32
var value PDH_RAW_COUNTER
var ret uint32
if ret = PdhGetRawCounterValue(hCounter, &counterType, &value); ret == ERROR_SUCCESS {
if value.CStatus == PDH_CSTATUS_VALID_DATA || value.CStatus == PDH_CSTATUS_NEW_DATA {
return value.FirstValue, nil
} else {
return 0, NewPdhError(value.CStatus)
}
} else {
return 0, NewPdhError(ret)
}
}
// UTF16PtrToString converts Windows API LPTSTR (pointer to string) to go string
func UTF16PtrToString(s *uint16) string {
if s == nil {

View File

@ -59,6 +59,8 @@ var sampleConfig = `
# IncludeTotal=false
# Print out when the performance counter is missing from object, counter or instance.
# WarnOnMissing = false
# Gather raw values instead of formatted. Raw value is stored in the field name with the "_Raw" suffix, e.g. "Disk_Read_Bytes_sec_Raw".
# UseRawValues = true
[[inputs.win_perf_counters.object]]
# Disk times and queues
@ -174,6 +176,7 @@ type perfobject struct {
WarnOnMissing bool
FailOnMissing bool
IncludeTotal bool
UseRawValues bool
}
type counter struct {
@ -183,6 +186,7 @@ type counter struct {
instance string
measurement string
includeTotal bool
useRawValue bool
counterHandle PDH_HCOUNTER
}
@ -257,8 +261,20 @@ func (m *Win_PerfCounters) SampleConfig() string {
return sampleConfig
}
//objectName string, counter string, instance string, measurement string, include_total bool
func (m *Win_PerfCounters) AddItem(counterPath string, objectName string, instance string, counterName string, measurement string, includeTotal bool) error {
func newCounter(counterHandle PDH_HCOUNTER, counterPath string, objectName string, instance string, counterName string, measurement string, includeTotal bool, useRawValue bool) *counter {
measurementName := sanitizedChars.Replace(measurement)
if measurementName == "" {
measurementName = "win_perf_counters"
}
newCounterName := sanitizedChars.Replace(counterName)
if useRawValue {
newCounterName += "_Raw"
}
return &counter{counterPath, objectName, newCounterName, instance, measurementName,
includeTotal, useRawValue, counterHandle}
}
func (m *Win_PerfCounters) AddItem(counterPath string, objectName string, instance string, counterName string, measurement string, includeTotal bool, useRawValue bool) error {
origCounterPath := counterPath
var err error
var counterHandle PDH_HCOUNTER
@ -315,20 +331,27 @@ func (m *Win_PerfCounters) AddItem(counterPath string, objectName string, instan
}
counterPath = formatPath(origObjectName, newInstance, origCounterName)
counterHandle, err = m.query.AddEnglishCounterToQuery(counterPath)
newItem = &counter{
newItem = newCounter(
counterHandle,
counterPath,
origObjectName, origCounterName,
instance, measurement,
includeTotal, counterHandle,
}
origObjectName, instance,
origCounterName,
measurement,
includeTotal,
useRawValue,
)
} else {
counterHandle, err = m.query.AddCounterToQuery(counterPath)
newItem = &counter{
newItem = newCounter(
counterHandle,
counterPath,
objectName, counterName,
instance, measurement,
includeTotal, counterHandle,
}
objectName,
instance,
counterName,
measurement,
includeTotal,
useRawValue,
)
}
if instance == "_Total" && origInstance == "*" && !includeTotal {
@ -342,8 +365,16 @@ func (m *Win_PerfCounters) AddItem(counterPath string, objectName string, instan
}
}
} else {
newItem := &counter{counterPath, objectName, counterName, instance, measurement,
includeTotal, counterHandle}
newItem := newCounter(
counterHandle,
counterPath,
objectName,
instance,
counterName,
measurement,
includeTotal,
useRawValue,
)
m.counters = append(m.counters, newItem)
if m.PrintValid {
m.Log.Infof("Valid: %s", counterPath)
@ -369,12 +400,15 @@ func (m *Win_PerfCounters) ParseConfig() error {
if len(m.Object) > 0 {
for _, PerfObject := range m.Object {
for _, counter := range PerfObject.Counters {
if len(PerfObject.Instances) == 0 {
m.Log.Warnf("Missing 'Instances' param for object '%s'\n", PerfObject.ObjectName)
}
for _, instance := range PerfObject.Instances {
objectname := PerfObject.ObjectName
counterPath = formatPath(objectname, instance, counter)
err := m.AddItem(counterPath, objectname, instance, counter, PerfObject.Measurement, PerfObject.IncludeTotal)
err := m.AddItem(counterPath, objectname, instance, counter, PerfObject.Measurement, PerfObject.IncludeTotal, PerfObject.UseRawValues)
if err != nil {
if PerfObject.FailOnMissing || PerfObject.WarnOnMissing {
@ -447,12 +481,16 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
return err
}
}
var value interface{}
// For iterate over the known metrics and get the samples.
for _, metric := range m.counters {
// collect
if m.UseWildcardsExpansion {
value, err := m.query.GetFormattedCounterValueDouble(metric.counterHandle)
if metric.useRawValue {
value, err = m.query.GetRawCounterValue(metric.counterHandle)
} else {
value, err = m.query.GetFormattedCounterValueDouble(metric.counterHandle)
}
if err != nil {
//ignore invalid data as some counters from process instances returns this sometimes
if !isKnownCounterDataError(err) {
@ -463,7 +501,12 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
}
addCounterMeasurement(metric, metric.instance, value, collectFields)
} else {
counterValues, err := m.query.GetFormattedCounterArrayDouble(metric.counterHandle)
var counterValues []CounterValue
if metric.useRawValue {
counterValues, err = m.query.GetRawCounterArray(metric.counterHandle)
} else {
counterValues, err = m.query.GetFormattedCounterArrayDouble(metric.counterHandle)
}
if err != nil {
//ignore invalid data as some counters from process instances returns this sometimes
if !isKnownCounterDataError(err) {
@ -519,16 +562,12 @@ func shouldIncludeMetric(metric *counter, cValue CounterValue) bool {
return false
}
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}
func addCounterMeasurement(metric *counter, instanceName string, value interface{}, collectFields map[instanceGrouping]map[string]interface{}) {
var instance = instanceGrouping{metric.measurement, instanceName, metric.objectName}
if collectFields[instance] == nil {
collectFields[instance] = make(map[string]interface{})
}
collectFields[instance][sanitizedChars.Replace(metric.counter)] = float32(value)
collectFields[instance][sanitizedChars.Replace(metric.counter)] = value
}
func isKnownCounterDataError(err error) bool {

View File

@ -69,8 +69,13 @@ func TestWinPerformanceQueryImplIntegration(t *testing.T) {
err = query.CollectData()
require.NoError(t, err)
_, err = query.GetFormattedCounterValueDouble(hCounter)
fcounter, err := query.GetFormattedCounterValueDouble(hCounter)
require.NoError(t, err)
require.True(t, fcounter > 0)
rcounter, err := query.GetRawCounterValue(hCounter)
require.NoError(t, err)
require.True(t, rcounter > 10000000)
now := time.Now()
mtime, err := query.CollectDataWithTime()
@ -104,13 +109,17 @@ func TestWinPerformanceQueryImplIntegration(t *testing.T) {
err = query.CollectData()
require.NoError(t, err)
arr, err := query.GetFormattedCounterArrayDouble(hCounter)
farr, 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)
farr, err = query.GetFormattedCounterArrayDouble(hCounter)
}
require.NoError(t, err)
require.True(t, len(arr) > 0, "Too")
require.True(t, len(farr) > 0)
rarr, err := query.GetRawCounterArray(hCounter)
require.NoError(t, err)
require.True(t, len(rarr) > 0, "Too")
err = query.Close()
require.NoError(t, err)
@ -144,8 +153,13 @@ func TestWinPerfcountersConfigGet1Integration(t *testing.T) {
perfobjects[0] = PerfObject
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
m.query.Open()
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
_ = m.query.Open()
err := m.ParseConfig()
require.NoError(t, err)
@ -178,8 +192,13 @@ func TestWinPerfcountersConfigGet2Integration(t *testing.T) {
perfobjects[0] = PerfObject
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
m.query.Open()
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
_ = m.query.Open()
err := m.ParseConfig()
require.NoError(t, err)
@ -225,8 +244,13 @@ func TestWinPerfcountersConfigGet3Integration(t *testing.T) {
perfobjects[0] = PerfObject
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
m.query.Open()
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
_ = m.query.Open()
err := m.ParseConfig()
require.NoError(t, err)
@ -274,8 +298,13 @@ func TestWinPerfcountersConfigGet4Integration(t *testing.T) {
perfobjects[0] = PerfObject
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
m.query.Open()
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
_ = m.query.Open()
err := m.ParseConfig()
require.NoError(t, err)
@ -324,8 +353,13 @@ func TestWinPerfcountersConfigGet5Integration(t *testing.T) {
perfobjects[0] = PerfObject
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
m.query.Open()
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
_ = m.query.Open()
err := m.ParseConfig()
require.NoError(t, err)
@ -370,8 +404,13 @@ func TestWinPerfcountersConfigGet6Integration(t *testing.T) {
perfobjects[0] = PerfObject
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
m.query.Open()
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
_ = m.query.Open()
err := m.ParseConfig()
require.NoError(t, err)
@ -402,12 +441,18 @@ func TestWinPerfcountersConfigGet7Integration(t *testing.T) {
false,
false,
false,
false,
}
perfobjects[0] = PerfObject
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
m.query.Open()
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
_ = m.query.Open()
err := m.ParseConfig()
require.NoError(t, err)
@ -458,7 +503,7 @@ func TestWinPerfcountersConfigError1Integration(t *testing.T) {
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
m.query.Open()
_ = m.query.Open()
err := m.ParseConfig()
require.Error(t, err)
@ -497,7 +542,7 @@ func TestWinPerfcountersConfigError2Integration(t *testing.T) {
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
m.query.Open()
_ = m.query.Open()
err := m.ParseConfig()
var acc testutil.Accumulator
@ -538,7 +583,7 @@ func TestWinPerfcountersConfigError3Integration(t *testing.T) {
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
m.query.Open()
_ = m.query.Open()
err := m.ParseConfig()
require.Error(t, err)
@ -647,3 +692,77 @@ func TestWinPerfcountersCollect2Integration(t *testing.T) {
}
}
func TestWinPerfcountersCollectRawIntegration(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test in short mode")
}
var instances = make([]string, 1)
var counters = make([]string, 1)
var perfobjects = make([]perfobject, 1)
objectname := "Processor"
instances[0] = "*"
counters[0] = "% Idle Time"
var expectedCounter = "Percent_Idle_Time_Raw"
var measurement = "test"
PerfObject := perfobject{
ObjectName: objectname,
Instances: instances,
Counters: counters,
Measurement: measurement,
WarnOnMissing: false,
FailOnMissing: true,
IncludeTotal: false,
UseRawValues: true,
}
perfobjects[0] = PerfObject
m := Win_PerfCounters{
PrintValid: false,
Object: perfobjects,
UseWildcardsExpansion: true,
query: &PerformanceQueryImpl{},
Log: testutil.Logger{},
}
var acc testutil.Accumulator
err := m.Gather(&acc)
require.NoError(t, err)
time.Sleep(2000 * time.Millisecond)
err = m.Gather(&acc)
require.NoError(t, err)
require.True(t, len(acc.Metrics) > 1)
for _, metric := range acc.Metrics {
val, ok := metric.Fields[expectedCounter]
require.True(t, ok, "Expected presence of %s field", expectedCounter)
valInt64, ok := val.(int64)
require.True(t, ok, fmt.Sprintf("Expected int64, got %T", val))
require.True(t, valInt64 > 0, fmt.Sprintf("Expected > 0, got %d, for %#v", valInt64, metric))
}
// Test *Array way
m = Win_PerfCounters{PrintValid: false, Object: perfobjects, UseWildcardsExpansion: false, query: &PerformanceQueryImpl{}, Log: testutil.Logger{}}
var acc2 testutil.Accumulator
err = m.Gather(&acc)
require.NoError(t, err)
time.Sleep(2000 * time.Millisecond)
err = m.Gather(&acc2)
require.NoError(t, err)
require.True(t, len(acc2.Metrics) > 1)
for _, metric := range acc2.Metrics {
val, ok := metric.Fields[expectedCounter]
require.True(t, ok, "Expected presence of %s field", expectedCounter)
valInt64, ok := val.(int64)
require.True(t, ok, fmt.Sprintf("Expected int64, got %T", val))
require.True(t, valInt64 > 0, fmt.Sprintf("Expected > 0, got %d, for %#v", valInt64, metric))
}
}

View File

@ -6,6 +6,7 @@ package win_perf_counters
import (
"errors"
"fmt"
"github.com/stretchr/testify/assert"
"testing"
"time"
@ -30,12 +31,19 @@ type FakePerformanceQuery struct {
var MetricTime = time.Date(2018, 5, 28, 12, 0, 0, 0, time.UTC)
func (m *testCounter) ToCounterValue() *CounterValue {
func (m *testCounter) ToCounterValue(raw bool) *CounterValue {
_, inst, _, _ := extractCounterInfoFromCounterPath(m.path)
if inst == "" {
inst = "--"
}
return &CounterValue{inst, m.value}
var val interface{}
if raw {
val = int64(m.value)
} else {
val = m.value
}
return &CounterValue{inst, val}
}
func (m *FakePerformanceQuery) Open() error {
@ -110,6 +118,22 @@ func (m *FakePerformanceQuery) GetFormattedCounterValueDouble(counterHandle PDH_
}
return 0, fmt.Errorf("GetFormattedCounterValueDouble: invalid handle: %d", counterHandle)
}
func (m *FakePerformanceQuery) GetRawCounterValue(counterHandle PDH_HCOUNTER) (int64, error) {
if !m.openCalled {
return 0, errors.New("GetRawCounterValue: uninitialised query")
}
for _, counter := range m.counters {
if counter.handle == counterHandle {
if counter.status > 0 {
return 0, NewPdhError(counter.status)
}
return int64(counter.value), nil
}
}
return 0, fmt.Errorf("GetRawCounterValue: invalid handle: %d", counterHandle)
}
func (m *FakePerformanceQuery) findCounterByPath(counterPath string) *testCounter {
for _, c := range m.counters {
if c.path == counterPath {
@ -142,7 +166,7 @@ func (m *FakePerformanceQuery) GetFormattedCounterArrayDouble(hCounter PDH_HCOUN
if counter.status > 0 {
return nil, NewPdhError(counter.status)
}
counters = append(counters, *counter.ToCounterValue())
counters = append(counters, *counter.ToCounterValue(false))
} else {
return nil, fmt.Errorf("GetFormattedCounterArrayDouble: invalid counter : %s", p)
}
@ -156,6 +180,34 @@ func (m *FakePerformanceQuery) GetFormattedCounterArrayDouble(hCounter PDH_HCOUN
return nil, fmt.Errorf("GetFormattedCounterArrayDouble: invalid counter : %d, no paths found", hCounter)
}
func (m *FakePerformanceQuery) GetRawCounterArray(hCounter PDH_HCOUNTER) ([]CounterValue, error) {
if !m.openCalled {
return nil, errors.New("GetRawCounterArray: uninitialised query")
}
for _, c := range m.counters {
if c.handle == hCounter {
if e, ok := m.expandPaths[c.path]; ok {
counters := make([]CounterValue, 0, len(e))
for _, p := range e {
counter := m.findCounterByPath(p)
if counter != nil {
if counter.status > 0 {
return nil, NewPdhError(counter.status)
}
counters = append(counters, *counter.ToCounterValue(true))
} else {
return nil, fmt.Errorf("GetRawCounterArray: invalid counter : %s", p)
}
}
return counters, nil
} else {
return nil, fmt.Errorf("GetRawCounterArray: invalid counter : %d", hCounter)
}
}
}
return nil, fmt.Errorf("GetRawCounterArray: invalid counter : %d, no paths found", hCounter)
}
func (m *FakePerformanceQuery) CollectData() error {
if !m.openCalled {
return errors.New("CollectData: uninitialized query")
@ -174,7 +226,7 @@ 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, includeTotal, useRawValues bool) []perfobject {
PerfObject := perfobject{
ObjectName: object,
Instances: instances,
@ -183,6 +235,7 @@ func createPerfObject(measurement string, object string, instances []string, cou
WarnOnMissing: false,
FailOnMissing: failOnMissing,
IncludeTotal: includeTotal,
UseRawValues: useRawValues,
}
perfobjects := []perfobject{PerfObject}
return perfobjects
@ -261,7 +314,7 @@ func TestAddItemSimple(t *testing.T) {
}}
err = m.query.Open()
require.NoError(t, err)
err = m.AddItem(cps1[0], "O", "I", "c", "test", false)
err = m.AddItem(cps1[0], "O", "I", "c", "test", false, true)
require.NoError(t, err)
err = m.query.Close()
require.NoError(t, err)
@ -284,7 +337,7 @@ func TestAddItemInvalidCountPath(t *testing.T) {
}}
err = m.query.Open()
require.NoError(t, err)
err = m.AddItem("\\O\\C", "O", "------", "C", "test", false)
err = m.AddItem("\\O\\C", "O", "------", "C", "test", false, false)
require.Error(t, err)
err = m.query.Close()
require.NoError(t, err)
@ -292,7 +345,7 @@ func TestAddItemInvalidCountPath(t *testing.T) {
func TestParseConfigBasic(t *testing.T) {
var err error
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false)
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -330,7 +383,7 @@ func TestParseConfigBasic(t *testing.T) {
func TestParseConfigNoInstance(t *testing.T) {
var err error
perfObjects := createPerfObject("m", "O", []string{"------"}, []string{"C1", "C2"}, false, false)
perfObjects := createPerfObject("m", "O", []string{"------"}, []string{"C1", "C2"}, false, false, false)
cps1 := []string{"\\O\\C1", "\\O\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -367,7 +420,7 @@ func TestParseConfigNoInstance(t *testing.T) {
func TestParseConfigInvalidCounterError(t *testing.T) {
var err error
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, true, false)
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, true, false, false)
cps1 := []string{"\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -402,7 +455,7 @@ func TestParseConfigInvalidCounterError(t *testing.T) {
func TestParseConfigInvalidCounterNoError(t *testing.T) {
var err error
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false)
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)
cps1 := []string{"\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -438,7 +491,7 @@ func TestParseConfigInvalidCounterNoError(t *testing.T) {
func TestParseConfigTotalExpansion(t *testing.T) {
var err error
perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, true, true)
perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, true, true, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(_Total)\\C1", "\\O(_Total)\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -485,7 +538,7 @@ func TestParseConfigTotalExpansion(t *testing.T) {
func TestParseConfigExpand(t *testing.T) {
var err error
perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, false, false)
perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, false, false, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -514,7 +567,7 @@ func TestSimpleGather(t *testing.T) {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test"
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false)
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false, false)
cp1 := "\\O(I)\\C"
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -532,7 +585,7 @@ func TestSimpleGather(t *testing.T) {
require.NoError(t, err)
fields1 := map[string]interface{}{
"C": float32(1.2),
"C": 1.2,
}
tags1 := map[string]string{
"instance": "I",
@ -557,7 +610,7 @@ func TestSimpleGatherNoData(t *testing.T) {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test"
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false)
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false, false)
cp1 := "\\O(I)\\C"
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -577,7 +630,7 @@ func TestSimpleGatherNoData(t *testing.T) {
// fields would contain if the error was ignored, and we simply added garbage
fields1 := map[string]interface{}{
"C": float32(1.2),
"C": 1.2,
}
// tags would contain if the error was ignored, and we simply added garbage
tags1 := map[string]string{
@ -603,7 +656,7 @@ func TestSimpleGatherWithTimestamp(t *testing.T) {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test"
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false)
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false, false)
cp1 := "\\O(I)\\C"
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -622,7 +675,7 @@ func TestSimpleGatherWithTimestamp(t *testing.T) {
require.NoError(t, err)
fields1 := map[string]interface{}{
"C": float32(1.2),
"C": 1.2,
}
tags1 := map[string]string{
"instance": "I",
@ -634,12 +687,12 @@ func TestSimpleGatherWithTimestamp(t *testing.T) {
func TestGatherError(t *testing.T) {
var err error
expected_error := "error while getting value for counter \\O(I)\\C: The information passed is not valid.\r\n"
expectedError := "error while getting value for counter \\O(I)\\C: The information passed is not valid.\r\n"
if testing.Short() {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test"
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false)
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C"}, false, false, false)
cp1 := "\\O(I)\\C"
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -655,7 +708,7 @@ func TestGatherError(t *testing.T) {
var acc1 testutil.Accumulator
err = m.Gather(&acc1)
require.Error(t, err)
require.Equal(t, expected_error, err.Error())
require.Equal(t, expectedError, err.Error())
m.UseWildcardsExpansion = true
m.counters = nil
@ -665,7 +718,7 @@ func TestGatherError(t *testing.T) {
err = m.Gather(&acc2)
require.Error(t, err)
require.Equal(t, expected_error, err.Error())
require.Equal(t, expectedError, err.Error())
}
func TestGatherInvalidDataIgnore(t *testing.T) {
@ -674,7 +727,7 @@ func TestGatherInvalidDataIgnore(t *testing.T) {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test"
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C1", "C2", "C3"}, false, false)
perfObjects := createPerfObject(measurement, "O", []string{"I"}, []string{"C1", "C2", "C3"}, false, false, false)
cps1 := []string{"\\O(I)\\C1", "\\O(I)\\C2", "\\O(I)\\C3"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -694,8 +747,8 @@ func TestGatherInvalidDataIgnore(t *testing.T) {
require.NoError(t, err)
fields1 := map[string]interface{}{
"C1": float32(1.2),
"C3": float32(0),
"C1": 1.2,
"C3": float64(0),
}
tags1 := map[string]string{
"instance": "I",
@ -720,7 +773,7 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test"
perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"*"}, true, false)
perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"*"}, true, false, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
fpm := &FakePerformanceQuery{
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}),
@ -730,12 +783,13 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
vistaAndNewer: true,
}
m := Win_PerfCounters{
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
UseWildcardsExpansion: true,
query: fpm,
CountersRefreshInterval: config.Duration(time.Second * 10),
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
UseWildcardsExpansion: true,
query: fpm,
CountersRefreshInterval: config.Duration(time.Second * 10),
LocalizeWildcardsExpansion: true,
}
var acc1 testutil.Accumulator
err = m.Gather(&acc1)
@ -744,8 +798,8 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
require.Len(t, acc1.Metrics, 2)
fields1 := map[string]interface{}{
"C1": float32(1.1),
"C2": float32(1.2),
"C1": 1.1,
"C2": 1.2,
}
tags1 := map[string]string{
"instance": "I1",
@ -754,8 +808,8 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
fields2 := map[string]interface{}{
"C1": float32(1.3),
"C2": float32(1.4),
"C1": 1.3,
"C2": 1.4,
}
tags2 := map[string]string{
"instance": "I2",
@ -771,12 +825,12 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
vistaAndNewer: true,
}
m.query = fpm
fpm.Open()
_ = fpm.Open()
var acc2 testutil.Accumulator
fields3 := map[string]interface{}{
"C1": float32(1.5),
"C2": float32(1.6),
"C1": 1.5,
"C2": 1.6,
}
tags3 := map[string]string{
"instance": "I3",
@ -812,7 +866,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test"
perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, false)
perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, false, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
fpm := &FakePerformanceQuery{
counters: createCounterMap(append([]string{"\\O(*)\\C1", "\\O(*)\\C2"}, cps1...), []float64{0, 0, 1.1, 1.2, 1.3, 1.4}, []uint32{0, 0, 0, 0, 0, 0}),
@ -836,8 +890,8 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
require.Len(t, acc1.Metrics, 2)
fields1 := map[string]interface{}{
"C1": float32(1.1),
"C2": float32(1.2),
"C1": 1.1,
"C2": 1.2,
}
tags1 := map[string]string{
"instance": "I1",
@ -846,8 +900,8 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
fields2 := map[string]interface{}{
"C1": float32(1.3),
"C2": float32(1.4),
"C1": 1.3,
"C2": 1.4,
}
tags2 := map[string]string{
"instance": "I2",
@ -865,12 +919,12 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
vistaAndNewer: true,
}
m.query = fpm
fpm.Open()
_ = fpm.Open()
var acc2 testutil.Accumulator
fields3 := map[string]interface{}{
"C1": float32(1.5),
"C2": float32(1.6),
"C1": 1.5,
"C2": 1.6,
}
tags3 := map[string]string{
"instance": "I3",
@ -887,7 +941,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
acc2.AssertContainsTaggedFields(t, measurement, fields2, tags2)
acc2.AssertContainsTaggedFields(t, measurement, fields3, tags3)
//test changed configuration
perfObjects = createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2", "C3"}, true, false)
perfObjects = createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2", "C3"}, true, false, false)
cps3 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I1)\\C3", "\\O(I2)\\C1", "\\O(I2)\\C2", "\\O(I2)\\C3"}
fpm = &FakePerformanceQuery{
counters: createCounterMap(append([]string{"\\O(*)\\C1", "\\O(*)\\C2", "\\O(*)\\C3"}, cps3...), []float64{0, 0, 0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6}, []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0}),
@ -901,7 +955,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
m.query = fpm
m.Object = perfObjects
fpm.Open()
_ = fpm.Open()
time.Sleep(time.Duration(m.CountersRefreshInterval))
@ -910,18 +964,18 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
require.NoError(t, err)
require.Len(t, acc3.Metrics, 2)
fields4 := map[string]interface{}{
"C1": float32(1.1),
"C2": float32(1.2),
"C3": float32(1.3),
"C1": 1.1,
"C2": 1.2,
"C3": 1.3,
}
tags4 := map[string]string{
"instance": "I1",
"objectname": "O",
}
fields5 := map[string]interface{}{
"C1": float32(1.4),
"C2": float32(1.5),
"C3": float32(1.6),
"C1": 1.4,
"C2": 1.5,
"C3": 1.6,
}
tags5 := map[string]string{
"instance": "I2",
@ -934,9 +988,12 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
}
func TestGatherTotalNoExpansion(t *testing.T) {
if testing.Short() {
t.Skip("Skipping long taking test in short mode")
}
var err error
measurement := "m"
perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, true)
perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, true, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(_Total)\\C1", "\\O(_Total)\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
@ -957,8 +1014,8 @@ func TestGatherTotalNoExpansion(t *testing.T) {
require.Len(t, m.counters, 2)
require.Len(t, acc1.Metrics, 2)
fields1 := map[string]interface{}{
"C1": float32(1.1),
"C2": float32(1.2),
"C1": 1.1,
"C2": 1.2,
}
tags1 := map[string]string{
"instance": "I1",
@ -967,8 +1024,8 @@ func TestGatherTotalNoExpansion(t *testing.T) {
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
fields2 := map[string]interface{}{
"C1": float32(1.3),
"C2": float32(1.4),
"C1": 1.3,
"C2": 1.4,
}
tags2 := map[string]string{
"instance": "_Total",
@ -992,6 +1049,67 @@ func TestGatherTotalNoExpansion(t *testing.T) {
acc2.AssertDoesNotContainsTaggedFields(t, measurement, fields2, tags2)
}
func TestGatherRaw(t *testing.T) {
if testing.Short() {
t.Skip("Skipping long taking test in short mode")
}
var err error
measurement := "m"
perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, true, true)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(_Total)\\C1", "\\O(_Total)\\C2"}
m := Win_PerfCounters{
Log: testutil.Logger{},
PrintValid: false,
UseWildcardsExpansion: false,
Object: perfObjects,
query: &FakePerformanceQuery{
counters: createCounterMap(append([]string{"\\O(*)\\C1", "\\O(*)\\C2"}, cps1...), []float64{0, 0, 1.1, 2.2, 3.3, 4.4}, []uint32{0, 0, 0, 0, 0, 0}),
expandPaths: map[string][]string{
"\\O(*)\\C1": {cps1[0], cps1[2]},
"\\O(*)\\C2": {cps1[1], cps1[3]},
},
vistaAndNewer: true,
}}
var acc1 testutil.Accumulator
err = m.Gather(&acc1)
require.NoError(t, err)
assert.Len(t, m.counters, 2)
assert.Len(t, acc1.Metrics, 2)
fields1 := map[string]interface{}{
"C1_Raw": int64(1),
"C2_Raw": int64(2),
}
tags1 := map[string]string{
"instance": "I1",
"objectname": "O",
}
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
fields2 := map[string]interface{}{
"C1_Raw": int64(3),
"C2_Raw": int64(4),
}
tags2 := map[string]string{
"instance": "_Total",
"objectname": "O",
}
acc1.AssertContainsTaggedFields(t, measurement, fields2, tags2)
m.UseWildcardsExpansion = true
m.counters = nil
m.lastRefreshed = time.Time{}
var acc2 testutil.Accumulator
err = m.Gather(&acc2)
require.NoError(t, err)
assert.Len(t, m.counters, 4) //expanded counters
assert.Len(t, acc2.Metrics, 2)
acc2.AssertContainsTaggedFields(t, measurement, fields1, tags1)
acc2.AssertContainsTaggedFields(t, measurement, fields2, tags2)
}
// list of nul terminated strings from WinAPI
var unicodeStringListWithEnglishChars = []uint16{0x5c, 0x5c, 0x54, 0x34, 0x38, 0x30, 0x5c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x6b, 0x28, 0x30, 0x20, 0x43, 0x3a, 0x29, 0x5c, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x44, 0x69, 0x73, 0x6b, 0x20, 0x51, 0x75, 0x65, 0x75, 0x65, 0x20, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0, 0x5c, 0x5c, 0x54, 0x34, 0x38, 0x30, 0x5c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x6b, 0x28, 0x5f, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x29, 0x5c, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x44, 0x69, 0x73, 0x6b, 0x20, 0x51, 0x75, 0x65, 0x75, 0x65, 0x20, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0, 0x0}
var unicodeStringListWithCzechChars = []uint16{0x5c, 0x5c, 0x54, 0x34, 0x38, 0x30, 0x5c, 0x46, 0x79, 0x7a, 0x69, 0x63, 0x6b, 0xfd, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x28, 0x30, 0x20, 0x43, 0x3a, 0x29, 0x5c, 0x41, 0x6b, 0x74, 0x75, 0xe1, 0x6c, 0x6e, 0xed, 0x20, 0x64, 0xe9, 0x6c, 0x6b, 0x61, 0x20, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x79, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x75, 0x0, 0x5c, 0x5c, 0x54, 0x34, 0x38, 0x30, 0x5c, 0x46, 0x79, 0x7a, 0x69, 0x63, 0x6b, 0xfd, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x28, 0x5f, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x29, 0x5c, 0x41, 0x6b, 0x74, 0x75, 0xe1, 0x6c, 0x6e, 0xed, 0x20, 0x64, 0xe9, 0x6c, 0x6b, 0x61, 0x20, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x79, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x75, 0x0, 0x0}
@ -1027,14 +1145,14 @@ func TestUTF16ToStringArray(t *testing.T) {
func TestNoWildcards(t *testing.T) {
m := Win_PerfCounters{
Object: createPerfObject("measurement", "object", []string{"instance"}, []string{"counter*"}, false, false),
Object: createPerfObject("measurement", "object", []string{"instance"}, []string{"counter*"}, false, false, false),
UseWildcardsExpansion: true,
LocalizeWildcardsExpansion: false,
Log: testutil.Logger{},
}
require.Error(t, m.Init())
m = Win_PerfCounters{
Object: createPerfObject("measurement", "object?", []string{"instance"}, []string{"counter"}, false, false),
Object: createPerfObject("measurement", "object?", []string{"instance"}, []string{"counter"}, false, false, false),
UseWildcardsExpansion: true,
LocalizeWildcardsExpansion: false,
Log: testutil.Logger{},
@ -1053,7 +1171,7 @@ func TestLocalizeWildcardsExpansion(t *testing.T) {
query: &PerformanceQueryImpl{},
CountersRefreshInterval: config.Duration(time.Second * 60),
Object: createPerfObject("measurement", "Processor Information",
[]string{"_Total"}, []string{counter}, false, false),
[]string{"_Total"}, []string{counter}, false, false, false),
LocalizeWildcardsExpansion: false,
UseWildcardsExpansion: true,
Log: testutil.Logger{},