Fix wildcard and other issues with win_perf_counters (#4189)
This commit is contained in:
parent
ce3b367dac
commit
010e4f5b0b
|
@ -1,19 +1,24 @@
|
|||
# win_perf_counters readme
|
||||
|
||||
The way this plugin works is that on load of Telegraf,
|
||||
the plugin will be handed configuration from Telegraf.
|
||||
This configuration is parsed and then tested for validity such as
|
||||
if the Object, Instance and Counter existing.
|
||||
If it does not match at startup, it will not be fetched.
|
||||
Exceptions to this are in cases where you query for all instances "*".
|
||||
By default the plugin does not return _Total
|
||||
when it is querying for all (*) as this is redundant.
|
||||
Input plugin to read Performance Counters on Windows operating systems.
|
||||
|
||||
Configuration is parsed and then tested for validity such as
|
||||
whether the Object, Instance and Counter exist on Telegraf startup.
|
||||
|
||||
Counter paths are refreshed periodically, see [CountersRefreshInterval](#countersrefreshinterval)
|
||||
configuration parameter for more info.
|
||||
|
||||
Wildcards can be used in instance and counter names. Partial wildcards are supported only
|
||||
in instance names on Windows Vista and newer.
|
||||
|
||||
In case of query for all instances `["*"]`, the plugin does not return the instance `_Total`
|
||||
by default. See [IncludeTotal](#includetotal) for more info.
|
||||
|
||||
## Basics
|
||||
|
||||
The examples contained in this file have been found on the internet
|
||||
as counters used when performance monitoring
|
||||
Active Directory and IIS in perticular.
|
||||
Active Directory and IIS in particular.
|
||||
There are a lot other good objects to monitor, if you know what to look for.
|
||||
This file is likely to be updated in the future with more examples for
|
||||
useful configurations for separate scenarios.
|
||||
|
@ -29,9 +34,23 @@ Bool, if set to `true` will print out all matching performance objects.
|
|||
Example:
|
||||
`PrintValid=true`
|
||||
|
||||
#### CountersRefreshInterval
|
||||
|
||||
Configured counters are matched against available counters at the interval
|
||||
specified by the `CountersRefreshInterval` parameter. Default value is `1m` (1 minute).
|
||||
|
||||
If wildcards are used in instance or counter names, they are expanded at this point.
|
||||
|
||||
Setting `CountersRefreshInterval` too low (order of seconds) can cause Telegraf to create
|
||||
a high CPU load.
|
||||
|
||||
Set to `0s` to disable periodic refreshing.
|
||||
|
||||
#### PreVistaSupport
|
||||
|
||||
Bool, if set to `true` will use the localized PerfCounter interface that is present before Vista for backwards compatability.
|
||||
_Deprecated. Necessary features on Windows Vista and newer are checked dynamically_
|
||||
|
||||
Bool, if set to `true` will use the localized PerfCounter interface that has been present since before Vista for backwards compatability.
|
||||
|
||||
It is recommended NOT to use this on OSes starting with Vista and newer because it requires more configuration to use this than the newer interface present since Vista.
|
||||
|
||||
|
@ -45,10 +64,10 @@ See Entry below.
|
|||
### Entry
|
||||
A new configuration entry consists of the TOML header to start with,
|
||||
`[[inputs.win_perf_counters.object]]`.
|
||||
This must follow before other plugins configuration,
|
||||
This must follow before other plugin configurations,
|
||||
beneath the main win_perf_counters entry, `[[inputs.win_perf_counters]]`.
|
||||
|
||||
Following this is 3 required key/value pairs and the three optional parameters and their usage.
|
||||
Following this are 3 required key/value pairs and the three optional parameters and their usage.
|
||||
|
||||
#### ObjectName
|
||||
**Required**
|
||||
|
@ -60,37 +79,39 @@ Example: `ObjectName = "LogicalDisk"`
|
|||
#### Instances
|
||||
**Required**
|
||||
|
||||
Instances (this is an array) is the instances of a counter you would like returned,
|
||||
Instances key (this is an array) is the instances of a counter you would like returned,
|
||||
it can be one or more values.
|
||||
|
||||
Example, `Instances = ["C:","D:","E:"]` will return only for the instances
|
||||
C:, D: and E: where relevant. To get all instances of a Counter, use ["*"] only.
|
||||
By default any results containing _Total are stripped,
|
||||
C:, D: and E: where relevant. To get all instances of a Counter, use `["*"]` only.
|
||||
By default any results containing `_Total` are stripped,
|
||||
unless this is specified as the wanted instance.
|
||||
Alternatively see the option IncludeTotal below.
|
||||
Alternatively see the option `IncludeTotal` below.
|
||||
|
||||
Some Objects does not have instances to select from at all,
|
||||
here only one option is valid if you want data back,
|
||||
It is also possible to set partial wildcards, eg. `["chrome*"]`
|
||||
|
||||
Some Objects do not have instances to select from at all.
|
||||
Here only one option is valid if you want data back,
|
||||
and that is to specify `Instances = ["------"]`.
|
||||
|
||||
#### Counters
|
||||
**Required**
|
||||
|
||||
Counters (this is an array) is the counters of the ObjectName
|
||||
Counters key (this is an array) is the counters of the ObjectName
|
||||
you would like returned, it can also be one or more values.
|
||||
|
||||
Example: `Counters = ["% Idle Time", "% Disk Read Time", "% Disk Write Time"]`
|
||||
This must be specified for every counter you want the results of,
|
||||
it is not possible to ask for all counters in the ObjectName.
|
||||
or use `["*"]` for all the counters for object.
|
||||
|
||||
#### Measurement
|
||||
*Optional*
|
||||
|
||||
This key is optional, if it is not set it will be win_perf_counters.
|
||||
This key is optional, if it is not set it will be `win_perf_counters`.
|
||||
In InfluxDB this is the key by which the returned data is stored underneath,
|
||||
so for ordering your data in a good manner,
|
||||
this is a good key to set with where you want your IIS and Disk results stored,
|
||||
separate from Processor results.
|
||||
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"
|
||||
|
||||
|
@ -99,9 +120,9 @@ Example: `Measurement = "win_disk"
|
|||
|
||||
This key is optional, it is a simple bool.
|
||||
If it is not set to true or included it is treated as false.
|
||||
This key only has an effect if Instances is set to "*"
|
||||
and you would also like all instances containg _Total returned,
|
||||
like "_Total", "0,_Total" and so on where applicable
|
||||
This key only has an effect if the Instances key is set to `["*"]`
|
||||
and you would also like all instances containing `_Total` returned,
|
||||
like `_Total`, `0,_Total` and so on where applicable
|
||||
(Processor Information is one example).
|
||||
|
||||
#### WarnOnMissing
|
||||
|
@ -111,13 +132,13 @@ This key is optional, it is a simple bool.
|
|||
If it is not set to true or included it is treated as false.
|
||||
This only has an effect on the first execution of the plugin,
|
||||
it will print out any ObjectName/Instance/Counter combinations
|
||||
asked for that does not match. Useful when debugging new configurations.
|
||||
asked for that do not match. Useful when debugging new configurations.
|
||||
|
||||
#### FailOnMissing
|
||||
*Internal*
|
||||
|
||||
This key should not be used, it is for testing purposes only.
|
||||
It is a simple bool, if it is not set to true or included this is treaded as false.
|
||||
This key should not be used. It is for testing purposes only.
|
||||
It is a simple bool. If it is not set to true or included this is treated as false.
|
||||
If this is set to true, the plugin will abort and end prematurely
|
||||
if any of the combinations of ObjectName/Instances/Counters are invalid.
|
||||
|
||||
|
@ -337,10 +358,14 @@ if any of the combinations of ObjectName/Instances/Counters are invalid.
|
|||
|
||||
## Troubleshooting
|
||||
|
||||
If you are getting an error about an invalid counter, use the `typeperf` command to check the counter path
|
||||
on the command line.
|
||||
E.g. `typeperf "Process(chrome*)\% Processor Time"`
|
||||
|
||||
If no metrics are emitted even with the default config, you may need to repair
|
||||
your performance counters.
|
||||
|
||||
1. Launch Command Prompt as Administrator (right click Runs As Administrator).
|
||||
1. Launch the Command Prompt as Administrator (right click Runs As Administrator).
|
||||
1. Drop into the C:\WINDOWS\System32 directory by typing `C:` then `cd \Windows\System32`
|
||||
1. Rebuild your counter values, which may take a few moments so please be
|
||||
patient, by running:
|
||||
|
|
|
@ -198,6 +198,51 @@ type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
|
|||
FmtValue PDH_FMT_COUNTERVALUE_LONG
|
||||
}
|
||||
|
||||
//PDH_COUNTER_INFO structure contains information describing the properties of a counter. This information also includes the counter path.
|
||||
type PDH_COUNTER_INFO struct {
|
||||
//Size of the structure, including the appended strings, in bytes.
|
||||
DwLength uint32
|
||||
//Counter type. For a list of counter types, see the Counter Types section of the <a "href=http://go.microsoft.com/fwlink/p/?linkid=84422">Windows Server 2003 Deployment Kit</a>.
|
||||
//The counter type constants are defined in Winperf.h.
|
||||
DwType uint32
|
||||
//Counter version information. Not used.
|
||||
CVersion uint32
|
||||
//Counter status that indicates if the counter value is valid. For a list of possible values,
|
||||
//see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa371894(v=vs.85).aspx">Checking PDH Interface Return Values</a>.
|
||||
CStatus uint32
|
||||
//Scale factor to use when computing the displayable value of the counter. The scale factor is a power of ten.
|
||||
//The valid range of this parameter is PDH_MIN_SCALE (–7) (the returned value is the actual value times 10–⁷) to
|
||||
//PDH_MAX_SCALE (+7) (the returned value is the actual value times 10⁺⁷). A value of zero will set the scale to one, so that the actual value is returned
|
||||
LScale int32
|
||||
//Default scale factor as suggested by the counter's provider.
|
||||
LDefaultScale int32
|
||||
//The value passed in the dwUserData parameter when calling PdhAddCounter.
|
||||
DwUserData *uint32
|
||||
//The value passed in the dwUserData parameter when calling PdhOpenQuery.
|
||||
DwQueryUserData *uint32
|
||||
//Null-terminated string that specifies the full counter path. The string follows this structure in memory.
|
||||
SzFullPath *uint16 // pointer to a string
|
||||
//Null-terminated string that contains the name of the computer specified in the counter path. Is NULL, if the path does not specify a computer.
|
||||
//The string follows this structure in memory.
|
||||
SzMachineName *uint16 // pointer to a string
|
||||
//Null-terminated string that contains the name of the performance object specified in the counter path. The string follows this structure in memory.
|
||||
SzObjectName *uint16 // pointer to a string
|
||||
//Null-terminated string that contains the name of the object instance specified in the counter path. Is NULL, if the path does not specify an instance.
|
||||
//The string follows this structure in memory.
|
||||
SzInstanceName *uint16 // pointer to a string
|
||||
//Null-terminated string that contains the name of the parent instance specified in the counter path. Is NULL, if the path does not specify a parent instance.
|
||||
//The string follows this structure in memory.
|
||||
SzParentInstance *uint16 // pointer to a string
|
||||
//Instance index specified in the counter path. Is 0, if the path does not specify an instance index.
|
||||
DwInstanceIndex uint32 // pointer to a string
|
||||
//Null-terminated string that contains the counter name. The string follows this structure in memory.
|
||||
SzCounterName *uint16 // pointer to a string
|
||||
//Help text that describes the counter. Is NULL if the source is a log file.
|
||||
SzExplainText *uint16 // pointer to a string
|
||||
//Start of the string data that is appended to the structure.
|
||||
DataBuffer *uint32 // pointer to an extra space
|
||||
}
|
||||
|
||||
var (
|
||||
// Library
|
||||
libpdhDll *syscall.DLL
|
||||
|
@ -211,6 +256,8 @@ var (
|
|||
pdh_GetFormattedCounterArrayW *syscall.Proc
|
||||
pdh_OpenQuery *syscall.Proc
|
||||
pdh_ValidatePathW *syscall.Proc
|
||||
pdh_ExpandWildCardPathW *syscall.Proc
|
||||
pdh_GetCounterInfoW *syscall.Proc
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -226,9 +273,11 @@ func init() {
|
|||
pdh_GetFormattedCounterArrayW = libpdhDll.MustFindProc("PdhGetFormattedCounterArrayW")
|
||||
pdh_OpenQuery = libpdhDll.MustFindProc("PdhOpenQuery")
|
||||
pdh_ValidatePathW = libpdhDll.MustFindProc("PdhValidatePathW")
|
||||
pdh_ExpandWildCardPathW = libpdhDll.MustFindProc("PdhExpandWildCardPathW")
|
||||
pdh_GetCounterInfoW = libpdhDll.MustFindProc("PdhGetCounterInfoW")
|
||||
}
|
||||
|
||||
// Adds the specified counter to the query. This is the internationalized version. Preferably, use the
|
||||
// PdhAddCounter adds the specified counter to the query. This is the internationalized version. Preferably, use the
|
||||
// function PdhAddEnglishCounter instead. hQuery is the query handle, which has been fetched by PdhOpenQuery.
|
||||
// szFullCounterPath is a full, internationalized counter path (this will differ per Windows language version).
|
||||
// dwUserData is a 'user-defined value', which becomes part of the counter information. To retrieve this value
|
||||
|
@ -277,7 +326,14 @@ func PdhAddCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintp
|
|||
return uint32(ret)
|
||||
}
|
||||
|
||||
// Adds the specified language-neutral counter to the query. See the PdhAddCounter function. This function only exists on
|
||||
// PdhAddEnglishCounterSupported returns true if PdhAddEnglishCounterW Win API function was found in pdh.dll.
|
||||
// PdhAddEnglishCounterW function is not supported on pre-Windows Vista systems
|
||||
|
||||
func PdhAddEnglishCounterSupported() bool {
|
||||
return pdh_AddEnglishCounterW != nil
|
||||
}
|
||||
|
||||
// PdhAddEnglishCounter adds the specified language-neutral counter to the query. See the PdhAddCounter function. This function only exists on
|
||||
// Windows versions higher than Vista.
|
||||
func PdhAddEnglishCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32 {
|
||||
if pdh_AddEnglishCounterW == nil {
|
||||
|
@ -294,7 +350,7 @@ func PdhAddEnglishCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserDat
|
|||
return uint32(ret)
|
||||
}
|
||||
|
||||
// Closes all counters contained in the specified query, closes all handles related to the query,
|
||||
// PdhCloseQuery closes all counters contained in the specified query, closes all handles related to the query,
|
||||
// and frees all memory associated with the query.
|
||||
func PdhCloseQuery(hQuery PDH_HQUERY) uint32 {
|
||||
ret, _, _ := pdh_CloseQuery.Call(uintptr(hQuery))
|
||||
|
@ -329,7 +385,7 @@ func PdhCollectQueryData(hQuery PDH_HQUERY) uint32 {
|
|||
return uint32(ret)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func PdhGetFormattedCounterValueDouble(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_DOUBLE) uint32 {
|
||||
ret, _, _ := pdh_GetFormattedCounterValue.Call(
|
||||
|
@ -341,7 +397,7 @@ func PdhGetFormattedCounterValueDouble(hCounter PDH_HCOUNTER, lpdwType *uint32,
|
|||
return uint32(ret)
|
||||
}
|
||||
|
||||
// Returns an array of formatted counter values. Use this function when you want to format the counter values of a
|
||||
// PdhGetFormattedCounterArrayDouble returns an array of formatted counter values. Use this function when you want to format the counter values of a
|
||||
// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE.
|
||||
// An example of how this function can be used:
|
||||
//
|
||||
|
@ -389,7 +445,7 @@ func PdhGetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER, lpdwBufferSize *ui
|
|||
return uint32(ret)
|
||||
}
|
||||
|
||||
// Creates a new query that is used to manage the collection of performance data.
|
||||
// PdhOpenQuery creates a new query that is used to manage the collection of performance data.
|
||||
// szDataSource is a null terminated string that specifies the name of the log file from which to
|
||||
// retrieve the performance data. If 0, performance data is collected from a real-time data source.
|
||||
// dwUserData is a user-defined value to associate with this query. To retrieve the user data later,
|
||||
|
@ -405,7 +461,51 @@ func PdhOpenQuery(szDataSource uintptr, dwUserData uintptr, phQuery *PDH_HQUERY)
|
|||
return uint32(ret)
|
||||
}
|
||||
|
||||
// Validates a path. Will return ERROR_SUCCESS when ok, or PDH_CSTATUS_BAD_COUNTERNAME when the path is
|
||||
//PdhExpandWildCardPath examines the specified computer or log file and returns those counter paths that match the given counter path which contains wildcard characters.
|
||||
//The general counter path format is as follows:
|
||||
//
|
||||
//\\computer\object(parent/instance#index)\counter
|
||||
//
|
||||
//The parent, instance, index, and counter components of the counter path may contain either a valid name or a wildcard character. The computer, parent, instance,
|
||||
// and index components are not necessary for all counters.
|
||||
//
|
||||
//The following is a list of the possible formats:
|
||||
//
|
||||
//\\computer\object(parent/instance#index)\counter
|
||||
//\\computer\object(parent/instance)\counter
|
||||
//\\computer\object(instance#index)\counter
|
||||
//\\computer\object(instance)\counter
|
||||
//\\computer\object\counter
|
||||
//\object(parent/instance#index)\counter
|
||||
//\object(parent/instance)\counter
|
||||
//\object(instance#index)\counter
|
||||
//\object(instance)\counter
|
||||
//\object\counter
|
||||
//Use an asterisk (*) as the wildcard character, for example, \object(*)\counter.
|
||||
//
|
||||
//If a wildcard character is specified in the parent name, all instances of the specified object that match the specified instance and counter fields will be returned.
|
||||
// For example, \object(*/instance)\counter.
|
||||
//
|
||||
//If a wildcard character is specified in the instance name, all instances of the specified object and parent object will be returned if all instance names
|
||||
// corresponding to the specified index match the wildcard character. For example, \object(parent/*)\counter. If the object does not contain an instance, an error occurs.
|
||||
//
|
||||
//If a wildcard character is specified in the counter name, all counters of the specified object are returned.
|
||||
//
|
||||
//Partial counter path string matches (for example, "pro*") are supported.
|
||||
func PdhExpandWildCardPath(szWildCardPath string, mszExpandedPathList *uint16, pcchPathListLength *uint32) uint32 {
|
||||
ptxt, _ := syscall.UTF16PtrFromString(szWildCardPath)
|
||||
flags := uint32(0) // expand instances and counters
|
||||
ret, _, _ := pdh_ExpandWildCardPathW.Call(
|
||||
uintptr(unsafe.Pointer(nil)), // search counters on local computer
|
||||
uintptr(unsafe.Pointer(ptxt)),
|
||||
uintptr(unsafe.Pointer(mszExpandedPathList)),
|
||||
uintptr(unsafe.Pointer(pcchPathListLength)),
|
||||
uintptr(unsafe.Pointer(&flags)))
|
||||
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
// PdhValidatePath validates a path. Will return ERROR_SUCCESS when ok, or PDH_CSTATUS_BAD_COUNTERNAME when the path is
|
||||
// erroneous.
|
||||
func PdhValidatePath(path string) uint32 {
|
||||
ptxt, _ := syscall.UTF16PtrFromString(path)
|
||||
|
@ -414,13 +514,6 @@ func PdhValidatePath(path string) uint32 {
|
|||
return uint32(ret)
|
||||
}
|
||||
|
||||
func UTF16PtrToString(s *uint16) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(s))[0:])
|
||||
}
|
||||
|
||||
func PdhFormatError(msgId uint32) string {
|
||||
var flags uint32 = windows.FORMAT_MESSAGE_FROM_HMODULE | windows.FORMAT_MESSAGE_ARGUMENT_ARRAY | windows.FORMAT_MESSAGE_IGNORE_INSERTS
|
||||
buf := make([]uint16, 300)
|
||||
|
@ -430,3 +523,25 @@ func PdhFormatError(msgId uint32) string {
|
|||
}
|
||||
return fmt.Sprintf("(pdhErr=%d) %s", msgId, err.Error())
|
||||
}
|
||||
|
||||
//Retrieves information about a counter, such as data size, counter type, path, and user-supplied data values
|
||||
//hCounter [in]
|
||||
//Handle of the counter from which you want to retrieve information. The PdhAddCounter function returns this handle.
|
||||
//
|
||||
//bRetrieveExplainText [in]
|
||||
//Determines whether explain text is retrieved. If you set this parameter to TRUE, the explain text for the counter is retrieved. If you set this parameter to FALSE, the field in the returned buffer is NULL.
|
||||
//
|
||||
//pdwBufferSize [in, out]
|
||||
//Size of the lpBuffer 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.
|
||||
//
|
||||
//lpBuffer [out]
|
||||
//Caller-allocated buffer that receives a PDH_COUNTER_INFO structure. The structure is variable-length, because the string data is appended to the end of the fixed-format portion of the structure. This is done so that all data is returned in a single buffer allocated by the caller. Set to NULL if pdwBufferSize is zero.
|
||||
func PdhGetCounterInfo(hCounter PDH_HCOUNTER, bRetrieveExplainText int, pdwBufferSize *uint32, lpBuffer *byte) uint32 {
|
||||
ret, _, _ := pdh_GetCounterInfoW.Call(
|
||||
uintptr(hCounter),
|
||||
uintptr(bRetrieveExplainText),
|
||||
uintptr(unsafe.Pointer(pdwBufferSize)),
|
||||
uintptr(unsafe.Pointer(lpBuffer)))
|
||||
|
||||
return uint32(ret)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
// Go API over pdh syscalls
|
||||
// +build windows
|
||||
|
||||
package win_perf_counters
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//PerformanceQuery provides wrappers around Windows performance counters API for easy usage in GO
|
||||
type PerformanceQuery interface {
|
||||
Open() error
|
||||
Close() error
|
||||
AddCounterToQuery(counterPath string) (PDH_HCOUNTER, error)
|
||||
AddEnglishCounterToQuery(counterPath string) (PDH_HCOUNTER, error)
|
||||
GetCounterPath(counterHandle PDH_HCOUNTER) (string, error)
|
||||
ExpandWildCardPath(counterPath string) ([]string, error)
|
||||
GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error)
|
||||
CollectData() error
|
||||
AddEnglishCounterSupported() bool
|
||||
}
|
||||
|
||||
//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 {
|
||||
query PDH_HQUERY
|
||||
}
|
||||
|
||||
// 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 PDH_HQUERY
|
||||
ret := PdhOpenQuery(0, 0, &handle)
|
||||
if ret != ERROR_SUCCESS {
|
||||
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("uninitialised query")
|
||||
}
|
||||
ret := PdhCloseQuery(m.query)
|
||||
if ret != ERROR_SUCCESS {
|
||||
return NewPdhError(ret)
|
||||
}
|
||||
m.query = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PerformanceQueryImpl) AddCounterToQuery(counterPath string) (PDH_HCOUNTER, error) {
|
||||
var counterHandle PDH_HCOUNTER
|
||||
if m.query == 0 {
|
||||
return 0, errors.New("uninitialised query")
|
||||
}
|
||||
ret := PdhAddCounter(m.query, counterPath, 0, &counterHandle)
|
||||
if ret != ERROR_SUCCESS {
|
||||
return 0, NewPdhError(ret)
|
||||
}
|
||||
return counterHandle, nil
|
||||
}
|
||||
|
||||
func (m *PerformanceQueryImpl) AddEnglishCounterToQuery(counterPath string) (PDH_HCOUNTER, error) {
|
||||
var counterHandle PDH_HCOUNTER
|
||||
if m.query == 0 {
|
||||
return 0, errors.New("uninitialised query")
|
||||
}
|
||||
ret := PdhAddEnglishCounter(m.query, counterPath, 0, &counterHandle)
|
||||
if ret != ERROR_SUCCESS {
|
||||
return 0, NewPdhError(ret)
|
||||
}
|
||||
return counterHandle, nil
|
||||
}
|
||||
|
||||
//GetCounterPath return counter information for given handle
|
||||
func (m *PerformanceQueryImpl) GetCounterPath(counterHandle PDH_HCOUNTER) (string, error) {
|
||||
var bufSize uint32
|
||||
var buff []byte
|
||||
|
||||
ret := PdhGetCounterInfo(counterHandle, 0, &bufSize, nil)
|
||||
if ret == PDH_MORE_DATA {
|
||||
buff = make([]byte, bufSize)
|
||||
bufSize = uint32(len(buff))
|
||||
ret = PdhGetCounterInfo(counterHandle, 0, &bufSize, &buff[0])
|
||||
if ret == ERROR_SUCCESS {
|
||||
ci := (*PDH_COUNTER_INFO)(unsafe.Pointer(&buff[0]))
|
||||
return UTF16PtrToString(ci.SzFullPath), nil
|
||||
}
|
||||
}
|
||||
return "", NewPdhError(ret)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
var bufSize uint32
|
||||
var buff []uint16
|
||||
|
||||
ret := PdhExpandWildCardPath(counterPath, nil, &bufSize)
|
||||
if ret == PDH_MORE_DATA {
|
||||
buff = make([]uint16, bufSize)
|
||||
bufSize = uint32(len(buff))
|
||||
ret = PdhExpandWildCardPath(counterPath, &buff[0], &bufSize)
|
||||
if ret == ERROR_SUCCESS {
|
||||
list := UTF16ToStringArray(buff)
|
||||
return list, nil
|
||||
}
|
||||
}
|
||||
return nil, NewPdhError(ret)
|
||||
}
|
||||
|
||||
//GetFormattedCounterValueDouble computes a displayable value for the specified counter
|
||||
func (m *PerformanceQueryImpl) GetFormattedCounterValueDouble(hCounter PDH_HCOUNTER) (float64, error) {
|
||||
var counterType uint32
|
||||
var value PDH_FMT_COUNTERVALUE_DOUBLE
|
||||
ret := PdhGetFormattedCounterValueDouble(hCounter, &counterType, &value)
|
||||
if ret == ERROR_SUCCESS {
|
||||
if value.CStatus == PDH_CSTATUS_VALID_DATA || value.CStatus == PDH_CSTATUS_NEW_DATA {
|
||||
return value.DoubleValue, nil
|
||||
} else {
|
||||
return 0, NewPdhError(value.CStatus)
|
||||
}
|
||||
} else {
|
||||
return 0, NewPdhError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *PerformanceQueryImpl) CollectData() error {
|
||||
if m.query == 0 {
|
||||
return errors.New("uninitialised query")
|
||||
}
|
||||
ret := PdhCollectQueryData(m.query)
|
||||
if ret != ERROR_SUCCESS {
|
||||
return NewPdhError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PerformanceQueryImpl) AddEnglishCounterSupported() bool {
|
||||
return PdhAddEnglishCounterSupported()
|
||||
}
|
||||
|
||||
// UTF16PtrToString converts Windows API LPTSTR (pointer to string) to go string
|
||||
func UTF16PtrToString(s *uint16) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
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(stringLine) + 1
|
||||
remainingBuf := buf[nextLineStart:]
|
||||
stringLine = UTF16PtrToString(&remainingBuf[0])
|
||||
}
|
||||
return strings
|
||||
}
|
|
@ -5,11 +5,13 @@ package win_perf_counters
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var sampleConfig = `
|
||||
|
@ -20,6 +22,8 @@ var sampleConfig = `
|
|||
## agent, it will not be gathered.
|
||||
## Settings:
|
||||
# PrintValid = false # Print All matching performance counters
|
||||
# Period after which counters will be reread from configuration and wildcards in counter paths expanded
|
||||
CountersRefreshInterval="1m"
|
||||
|
||||
[[inputs.win_perf_counters.object]]
|
||||
# Processor usage, alternative to native, reports on a per core.
|
||||
|
@ -53,7 +57,7 @@ var sampleConfig = `
|
|||
Measurement = "win_system"
|
||||
|
||||
[[inputs.win_perf_counters.object]]
|
||||
# Example query where the Instance portion must be removed to get data back,
|
||||
# Example counterPath where the Instance portion must be removed to get data back,
|
||||
# such as from the Memory object.
|
||||
ObjectName = "Memory"
|
||||
Counters = [
|
||||
|
@ -61,17 +65,20 @@ var sampleConfig = `
|
|||
"Page Faults/sec", "Pages/sec", "Transition Faults/sec",
|
||||
"Pool Nonpaged Bytes", "Pool Paged Bytes"
|
||||
]
|
||||
Instances = ["------"] # Use 6 x - to remove the Instance bit from the query.
|
||||
Instances = ["------"] # Use 6 x - to remove the Instance bit from the counterPath.
|
||||
Measurement = "win_mem"
|
||||
`
|
||||
|
||||
type Win_PerfCounters struct {
|
||||
PrintValid bool
|
||||
PreVistaSupport bool
|
||||
Object []perfobject
|
||||
PrintValid bool
|
||||
//deprecated: determined dynamically
|
||||
PreVistaSupport bool
|
||||
Object []perfobject
|
||||
CountersRefreshInterval internal.Duration
|
||||
|
||||
configParsed bool
|
||||
itemCache []*item
|
||||
lastRefreshed time.Time
|
||||
counters []*counter
|
||||
query PerformanceQuery
|
||||
}
|
||||
|
||||
type perfobject struct {
|
||||
|
@ -84,56 +91,101 @@ type perfobject struct {
|
|||
IncludeTotal bool
|
||||
}
|
||||
|
||||
type item struct {
|
||||
query string
|
||||
type counter struct {
|
||||
counterPath string
|
||||
objectName string
|
||||
counter string
|
||||
instance string
|
||||
measurement string
|
||||
include_total bool
|
||||
handle PDH_HQUERY
|
||||
includeTotal bool
|
||||
counterHandle PDH_HCOUNTER
|
||||
}
|
||||
|
||||
var sanitizedChars = strings.NewReplacer("/sec", "_persec", "/Sec", "_persec",
|
||||
" ", "_", "%", "Percent", `\`, "")
|
||||
|
||||
func (m *Win_PerfCounters) AddItem(query string, objectName string, counter string, instance string,
|
||||
measurement string, include_total bool) error {
|
||||
//General Counter path pattern is: \\computer\object(parent/instance#index)\counter
|
||||
//parent/instance#index part is skipped in single instance objects (e.g. Memory): \\computer\object\counter
|
||||
|
||||
var handle PDH_HQUERY
|
||||
var counterHandle PDH_HCOUNTER
|
||||
ret := PdhOpenQuery(0, 0, &handle)
|
||||
if m.PreVistaSupport {
|
||||
ret = PdhAddCounter(handle, query, 0, &counterHandle)
|
||||
var counterPathRE = regexp.MustCompile(`.*\\(.*)\\(.*)`)
|
||||
var objectInstanceRE = regexp.MustCompile(`(.*)\((.*)\)`)
|
||||
|
||||
//extractObjectInstanceCounterFromQuery gets object name, instance name (if available) and counter name from counter path
|
||||
func extractObjectInstanceCounterFromQuery(query string) (object string, instance string, counter string, err error) {
|
||||
pathParts := counterPathRE.FindAllStringSubmatch(query, -1)
|
||||
if pathParts == nil || len(pathParts[0]) != 3 {
|
||||
err = errors.New("Could not extract counter info from: " + query)
|
||||
return
|
||||
}
|
||||
counter = pathParts[0][2]
|
||||
//try to get instance name
|
||||
objectInstanceParts := objectInstanceRE.FindAllStringSubmatch(pathParts[0][1], -1)
|
||||
if objectInstanceParts == nil || len(objectInstanceParts[0]) != 3 {
|
||||
object = pathParts[0][1]
|
||||
} else {
|
||||
ret = PdhAddEnglishCounter(handle, query, 0, &counterHandle)
|
||||
object = objectInstanceParts[0][1]
|
||||
instance = objectInstanceParts[0][2]
|
||||
}
|
||||
|
||||
// Call PdhCollectQueryData one time to check existence of the counter
|
||||
ret = PdhCollectQueryData(handle)
|
||||
if ret != ERROR_SUCCESS {
|
||||
PdhCloseQuery(handle)
|
||||
return errors.New(PdhFormatError(ret))
|
||||
}
|
||||
|
||||
newItem := &item{query, objectName, counter, instance, measurement,
|
||||
include_total, handle, counterHandle}
|
||||
m.itemCache = append(m.itemCache, newItem)
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Win_PerfCounters) Description() string {
|
||||
return "Input plugin to query Performance Counters on Windows operating systems"
|
||||
return "Input plugin to counterPath Performance Counters on Windows operating systems"
|
||||
}
|
||||
|
||||
func (m *Win_PerfCounters) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (m *Win_PerfCounters) AddItem(counterPath string, instance string, measurement string, includeTotal bool) error {
|
||||
if !m.query.AddEnglishCounterSupported() {
|
||||
_, err := m.query.AddCounterToQuery(counterPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
counterHandle, err := m.query.AddEnglishCounterToQuery(counterPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
counterPath, err = m.query.GetCounterPath(counterHandle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
counters, err := m.query.ExpandWildCardPath(counterPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, counterPath := range counters {
|
||||
var err error
|
||||
counterHandle, err := m.query.AddCounterToQuery(counterPath)
|
||||
|
||||
parsedObjectName, parsedInstance, parsedCounter, err := extractObjectInstanceCounterFromQuery(counterPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if parsedInstance == "_Total" && instance == "*" && !includeTotal {
|
||||
continue
|
||||
}
|
||||
|
||||
newItem := &counter{counterPath, parsedObjectName, parsedCounter, parsedInstance, measurement,
|
||||
includeTotal, counterHandle}
|
||||
m.counters = append(m.counters, newItem)
|
||||
|
||||
if m.PrintValid {
|
||||
log.Printf("Valid: %s\n", counterPath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Win_PerfCounters) ParseConfig() error {
|
||||
var query string
|
||||
var counterPath string
|
||||
|
||||
if len(m.Object) > 0 {
|
||||
for _, PerfObject := range m.Object {
|
||||
|
@ -142,21 +194,16 @@ func (m *Win_PerfCounters) ParseConfig() error {
|
|||
objectname := PerfObject.ObjectName
|
||||
|
||||
if instance == "------" {
|
||||
query = "\\" + objectname + "\\" + counter
|
||||
counterPath = "\\" + objectname + "\\" + counter
|
||||
} else {
|
||||
query = "\\" + objectname + "(" + instance + ")\\" + counter
|
||||
counterPath = "\\" + objectname + "(" + instance + ")\\" + counter
|
||||
}
|
||||
|
||||
err := m.AddItem(query, objectname, counter, instance,
|
||||
PerfObject.Measurement, PerfObject.IncludeTotal)
|
||||
err := m.AddItem(counterPath, instance, PerfObject.Measurement, PerfObject.IncludeTotal)
|
||||
|
||||
if err == nil {
|
||||
if m.PrintValid {
|
||||
fmt.Printf("Valid: %s\n", query)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
if PerfObject.FailOnMissing || PerfObject.WarnOnMissing {
|
||||
fmt.Printf("Invalid query: '%s'. Error: %s", query, err.Error())
|
||||
log.Printf("Invalid counterPath: '%s'. Error: %s\n", counterPath, err.Error())
|
||||
}
|
||||
if PerfObject.FailOnMissing {
|
||||
return err
|
||||
|
@ -165,32 +212,39 @@ func (m *Win_PerfCounters) ParseConfig() error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
} else {
|
||||
err := errors.New("No performance objects configured!")
|
||||
err := errors.New("no performance objects configured")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Win_PerfCounters) GetParsedItemsForTesting() []*item {
|
||||
return m.itemCache
|
||||
}
|
||||
|
||||
func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
|
||||
// Parse the config once
|
||||
if !m.configParsed {
|
||||
err := m.ParseConfig()
|
||||
m.configParsed = true
|
||||
var err error
|
||||
|
||||
if m.lastRefreshed.IsZero() || (m.CountersRefreshInterval.Duration.Nanoseconds() > 0 && m.lastRefreshed.Add(m.CountersRefreshInterval.Duration).Before(time.Now())) {
|
||||
m.counters = m.counters[:0]
|
||||
|
||||
err = m.query.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var bufSize uint32
|
||||
var bufCount uint32
|
||||
var size uint32 = uint32(unsafe.Sizeof(PDH_FMT_COUNTERVALUE_ITEM_DOUBLE{}))
|
||||
var emptyBuf [1]PDH_FMT_COUNTERVALUE_ITEM_DOUBLE // need at least 1 addressable null ptr.
|
||||
err = m.ParseConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//some counters need two data samples before computing a value
|
||||
err = m.query.CollectData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.lastRefreshed = time.Now()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
type InstanceGrouping struct {
|
||||
name string
|
||||
|
@ -200,78 +254,40 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
|
|||
|
||||
var collectFields = make(map[InstanceGrouping]map[string]interface{})
|
||||
|
||||
err = m.query.CollectData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// For iterate over the known metrics and get the samples.
|
||||
for _, metric := range m.itemCache {
|
||||
for _, metric := range m.counters {
|
||||
// collect
|
||||
ret := PdhCollectQueryData(metric.handle)
|
||||
if ret == ERROR_SUCCESS {
|
||||
ret = PdhGetFormattedCounterArrayDouble(metric.counterHandle, &bufSize,
|
||||
&bufCount, &emptyBuf[0]) // uses null ptr here according to MSDN.
|
||||
if ret == PDH_MORE_DATA {
|
||||
filledBuf := make([]PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size)
|
||||
if len(filledBuf) == 0 {
|
||||
continue
|
||||
}
|
||||
ret = PdhGetFormattedCounterArrayDouble(metric.counterHandle,
|
||||
&bufSize, &bufCount, &filledBuf[0])
|
||||
for i := 0; i < int(bufCount); i++ {
|
||||
c := filledBuf[i]
|
||||
var s string = UTF16PtrToString(c.SzName)
|
||||
value, err := m.query.GetFormattedCounterValueDouble(metric.counterHandle)
|
||||
if err == nil {
|
||||
measurement := sanitizedChars.Replace(metric.measurement)
|
||||
if measurement == "" {
|
||||
measurement = "win_perf_counters"
|
||||
}
|
||||
|
||||
var add bool
|
||||
|
||||
if metric.include_total {
|
||||
// If IncludeTotal is set, include all.
|
||||
add = true
|
||||
} else if metric.instance == "*" && !strings.Contains(s, "_Total") {
|
||||
// Catch if set to * and that it is not a '*_Total*' instance.
|
||||
add = true
|
||||
} else if metric.instance == s {
|
||||
// Catch if we set it to total or some form of it
|
||||
add = true
|
||||
} else if strings.Contains(metric.instance, "#") && strings.HasPrefix(metric.instance, s) {
|
||||
// If you are using a multiple instance identifier such as "w3wp#1"
|
||||
// phd.dll returns only the first 2 characters of the identifier.
|
||||
add = true
|
||||
s = metric.instance
|
||||
} else if metric.instance == "------" {
|
||||
add = true
|
||||
}
|
||||
|
||||
if add {
|
||||
tags := make(map[string]string)
|
||||
if s != "" {
|
||||
tags["instance"] = s
|
||||
}
|
||||
tags["objectname"] = metric.objectName
|
||||
|
||||
measurement := sanitizedChars.Replace(metric.measurement)
|
||||
if measurement == "" {
|
||||
measurement = "win_perf_counters"
|
||||
}
|
||||
var instance = InstanceGrouping{measurement, s, metric.objectName}
|
||||
|
||||
if collectFields[instance] == nil {
|
||||
collectFields[instance] = make(map[string]interface{})
|
||||
}
|
||||
collectFields[instance][sanitizedChars.Replace(metric.counter)] = float32(c.FmtValue.DoubleValue)
|
||||
}
|
||||
}
|
||||
|
||||
filledBuf = nil
|
||||
// Need to at least set bufSize to zero, because if not, the function will not
|
||||
// return PDH_MORE_DATA and will not set the bufSize.
|
||||
bufCount = 0
|
||||
bufSize = 0
|
||||
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 {
|
||||
//ignore invalid data from 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 {
|
||||
return fmt.Errorf("error while getting value for counter %s: %v", metric.counterPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for instance, fields := range collectFields {
|
||||
var tags = map[string]string{
|
||||
"instance": instance.instance,
|
||||
"objectname": instance.objectname,
|
||||
}
|
||||
if len(instance.instance) > 0 {
|
||||
tags["instance"] = instance.instance
|
||||
}
|
||||
acc.AddFields(instance.name, fields, tags)
|
||||
}
|
||||
|
||||
|
@ -279,5 +295,7 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error {
|
|||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("win_perf_counters", func() telegraf.Input { return &Win_PerfCounters{} })
|
||||
inputs.Add("win_perf_counters", func() telegraf.Input {
|
||||
return &Win_PerfCounters{query: &PerformanceQueryImpl{}, CountersRefreshInterval: internal.Duration{Duration: time.Second * 60}}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,592 @@
|
|||
// +build windows
|
||||
|
||||
package win_perf_counters
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TestWinPerformanceQueryImpl(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
var query PerformanceQuery
|
||||
var hCounter PDH_HCOUNTER
|
||||
var err error
|
||||
query = &PerformanceQueryImpl{}
|
||||
|
||||
err = query.Close()
|
||||
require.Error(t, err, "uninitialized query must return errors")
|
||||
|
||||
_, err = query.AddCounterToQuery("")
|
||||
require.Error(t, err, "uninitialized query must return errors")
|
||||
assert.True(t, strings.Contains(err.Error(), "uninitialised"))
|
||||
|
||||
_, err = query.AddEnglishCounterToQuery("")
|
||||
require.Error(t, err, "uninitialized query must return errors")
|
||||
assert.True(t, strings.Contains(err.Error(), "uninitialised"))
|
||||
|
||||
err = query.CollectData()
|
||||
require.Error(t, err, "uninitialized query must return errors")
|
||||
assert.True(t, strings.Contains(err.Error(), "uninitialised"))
|
||||
|
||||
err = query.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
counterPath := "\\Processor Information(_Total)\\% Processor Time"
|
||||
|
||||
hCounter, err = query.AddCounterToQuery(counterPath)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, hCounter)
|
||||
|
||||
err = query.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = query.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
hCounter, err = query.AddEnglishCounterToQuery(counterPath)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, hCounter)
|
||||
|
||||
cp, err := query.GetCounterPath(hCounter)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasSuffix(cp, counterPath))
|
||||
|
||||
err = query.CollectData()
|
||||
require.NoError(t, err)
|
||||
time.Sleep(time.Second)
|
||||
|
||||
err = query.CollectData()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = query.GetFormattedCounterValueDouble(hCounter)
|
||||
require.NoError(t, err)
|
||||
|
||||
counterPath = "\\Process(*)\\% Processor Time"
|
||||
paths, err := query.ExpandWildCardPath(counterPath)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, paths)
|
||||
assert.True(t, len(paths) > 1)
|
||||
|
||||
counterPath = "\\Process(_Total)\\*"
|
||||
paths, err = query.ExpandWildCardPath(counterPath)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, paths)
|
||||
assert.True(t, len(paths) > 1)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet1(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 Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet2(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 Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
if len(m.counters) == 1 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(m.counters) == 0 {
|
||||
var errorstring1 = "No results returned from the counterPath: " + string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(m.counters) > 1 {
|
||||
var errorstring1 = "Too many results returned from the counterPath: " + string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet3(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 2)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
counters[1] = "% Idle Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
if len(m.counters) == 2 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(m.counters) < 2 {
|
||||
|
||||
var errorstring1 = "Too few results returned from the counterPath. " + string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(m.counters) > 2 {
|
||||
|
||||
var errorstring1 = "Too many results returned from the counterPath: " + string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet4(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
var instances = make([]string, 2)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
instances[1] = "0,1"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
if len(m.counters) == 2 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(m.counters) < 2 {
|
||||
|
||||
var errorstring1 = "Too few results returned from the counterPath: " + string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(m.counters) > 2 {
|
||||
|
||||
var errorstring1 = "Too many results returned from the counterPath: " + string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet5(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
var instances = make([]string, 2)
|
||||
var counters = make([]string, 2)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
instances[1] = "0,1"
|
||||
counters[0] = "% Processor Time"
|
||||
counters[1] = "% Idle Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
if len(m.counters) == 4 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(m.counters) < 4 {
|
||||
var errorstring1 = "Too few results returned from the counterPath: " +
|
||||
string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(m.counters) > 4 {
|
||||
var errorstring1 = "Too many results returned from the counterPath: " +
|
||||
string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet6(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 := "System"
|
||||
instances[0] = "------"
|
||||
counters[0] = "Context Switches/sec"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet7(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 3)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
counters[1] = "% Processor TimeERROR"
|
||||
counters[2] = "% Idle Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
objectname,
|
||||
counters,
|
||||
instances,
|
||||
measurement,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
if len(m.counters) == 2 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(m.counters) < 2 {
|
||||
var errorstring1 = "Too few results returned from the counterPath: " +
|
||||
string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(m.counters) > 2 {
|
||||
var errorstring1 = "Too many results returned from the counterPath: " +
|
||||
string(len(m.counters))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigError1(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 InformationERROR"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigError2(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] = "SuperERROR"
|
||||
counters[0] = "% C1 Time"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
var acc testutil.Accumulator
|
||||
err = m.Gather(&acc)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigError3(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 Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor TimeERROR"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
m.query.Open()
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersCollect1(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 Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "Parking Status"
|
||||
|
||||
var expectedCounter = "Parking_Status"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
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)
|
||||
assert.Len(t, acc.Metrics, 2)
|
||||
|
||||
for _, metric := range acc.Metrics {
|
||||
_, ok := metric.Fields[expectedCounter]
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
}
|
||||
func TestWinPerfcountersCollect2(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration test in short mode")
|
||||
}
|
||||
|
||||
var instances = make([]string, 2)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
instances[1] = "0,0"
|
||||
counters[0] = "Performance Limit Flags"
|
||||
|
||||
var expectedCounter = "Performance_Limit_Flags"
|
||||
|
||||
var measurement = "test"
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: true,
|
||||
IncludeTotal: false,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects, query: &PerformanceQueryImpl{}}
|
||||
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)
|
||||
|
||||
assert.Len(t, acc.Metrics, 4)
|
||||
|
||||
for _, metric := range acc.Metrics {
|
||||
_, ok := metric.Fields[expectedCounter]
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
}
|
|
@ -4,528 +4,462 @@ package win_perf_counters
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWinPerfcountersConfigGet1(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
type testCounter struct {
|
||||
handle PDH_HCOUNTER
|
||||
path string
|
||||
value float64
|
||||
}
|
||||
type FakePerformanceQuery struct {
|
||||
counters map[string]testCounter
|
||||
addEnglishSupported bool
|
||||
expandPaths map[string][]string
|
||||
openCalled bool
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet2(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
func (m *FakePerformanceQuery) Open() error {
|
||||
if m.openCalled {
|
||||
err := m.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
m.openCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
func (m *FakePerformanceQuery) Close() error {
|
||||
if !m.openCalled {
|
||||
return errors.New("CloSe: uninitialised query")
|
||||
}
|
||||
m.openCalled = false
|
||||
return nil
|
||||
}
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
var parsedItems = m.GetParsedItemsForTesting()
|
||||
|
||||
if len(parsedItems) == 1 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(parsedItems) == 0 {
|
||||
var errorstring1 string = "No results returned from the query: " + string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(parsedItems) > 1 {
|
||||
var errorstring1 string = "Too many results returned from the query: " + string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
func (m *FakePerformanceQuery) AddCounterToQuery(counterPath string) (PDH_HCOUNTER, error) {
|
||||
if !m.openCalled {
|
||||
return 0, errors.New("AddCounterToQuery: uninitialised query")
|
||||
}
|
||||
if c, ok := m.counters[counterPath]; ok {
|
||||
return c.handle, nil
|
||||
} else {
|
||||
return 0, errors.New(fmt.Sprintf("AddCounterToQuery: invalid counter path: %s", counterPath))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet3(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 2)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
counters[1] = "% Idle Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
func (m *FakePerformanceQuery) AddEnglishCounterToQuery(counterPath string) (PDH_HCOUNTER, error) {
|
||||
if !m.openCalled {
|
||||
return 0, errors.New("AddEnglishCounterToQuery: uninitialised query")
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
var parsedItems = m.GetParsedItemsForTesting()
|
||||
|
||||
if len(parsedItems) == 2 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(parsedItems) < 2 {
|
||||
|
||||
var errorstring1 string = "Too few results returned from the query. " + string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(parsedItems) > 2 {
|
||||
|
||||
var errorstring1 string = "Too many results returned from the query: " + string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
if c, ok := m.counters[counterPath]; ok {
|
||||
return c.handle, nil
|
||||
} else {
|
||||
return 0, fmt.Errorf("AddEnglishCounterToQuery: invalid counter path: %s", counterPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet4(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 2)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
instances[1] = "0,1"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
func (m *FakePerformanceQuery) GetCounterPath(counterHandle PDH_HCOUNTER) (string, error) {
|
||||
for _, counter := range m.counters {
|
||||
if counter.handle == counterHandle {
|
||||
return counter.path, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("GetCounterPath: invalid handle: %d", counterHandle)
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
var parsedItems = m.GetParsedItemsForTesting()
|
||||
|
||||
if len(parsedItems) == 2 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(parsedItems) < 2 {
|
||||
|
||||
var errorstring1 string = "Too few results returned from the query: " + string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(parsedItems) > 2 {
|
||||
|
||||
var errorstring1 string = "Too many results returned from the query: " + string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
func (m *FakePerformanceQuery) ExpandWildCardPath(counterPath string) ([]string, error) {
|
||||
if e, ok := m.expandPaths[counterPath]; ok {
|
||||
return e, nil
|
||||
} else {
|
||||
return []string{}, fmt.Errorf("ExpandWildCardPath: invalid counter path: %s", counterPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet5(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 2)
|
||||
var counters = make([]string, 2)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
instances[1] = "0,1"
|
||||
counters[0] = "% Processor Time"
|
||||
counters[1] = "% Idle Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
func (m *FakePerformanceQuery) GetFormattedCounterValueDouble(counterHandle PDH_HCOUNTER) (float64, error) {
|
||||
if !m.openCalled {
|
||||
return 0, errors.New("GetFormattedCounterValueDouble: uninitialised query")
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
|
||||
var parsedItems = m.GetParsedItemsForTesting()
|
||||
|
||||
if len(parsedItems) == 4 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(parsedItems) < 4 {
|
||||
var errorstring1 string = "Too few results returned from the query: " +
|
||||
string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(parsedItems) > 4 {
|
||||
var errorstring1 string = "Too many results returned from the query: " +
|
||||
string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
for _, counter := range m.counters {
|
||||
if counter.handle == counterHandle {
|
||||
if counter.value > 0 {
|
||||
return counter.value, nil
|
||||
} else {
|
||||
if counter.value == 0 {
|
||||
return 0, NewPdhError(PDH_INVALID_DATA)
|
||||
} else {
|
||||
return 0, NewPdhError(PDH_CALC_NEGATIVE_VALUE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("GetFormattedCounterValueDouble: invalid handle: %d", counterHandle)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet6(t *testing.T) {
|
||||
func (m *FakePerformanceQuery) CollectData() error {
|
||||
if !m.openCalled {
|
||||
return errors.New("CollectData: uninitialised query")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "System"
|
||||
instances[0] = "------"
|
||||
counters[0] = "Context Switches/sec"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
func (m *FakePerformanceQuery) AddEnglishCounterSupported() bool {
|
||||
return m.addEnglishSupported
|
||||
}
|
||||
|
||||
func createPerfObject(measurement string, object string, instances []string, counters []string, failOnMissing bool, includeTotal bool) []perfobject {
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
ObjectName: object,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
WarnOnMissing: false,
|
||||
FailOnMissing: failOnMissing,
|
||||
IncludeTotal: includeTotal,
|
||||
}
|
||||
perfobjects := []perfobject{PerfObject}
|
||||
return perfobjects
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
func createCounterMap(counterPaths []string, values []float64) map[string]testCounter {
|
||||
counters := make(map[string]testCounter)
|
||||
for i, cp := range counterPaths {
|
||||
counters[cp] = testCounter{
|
||||
PDH_HCOUNTER(i),
|
||||
cp,
|
||||
values[i],
|
||||
}
|
||||
}
|
||||
return counters
|
||||
}
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
func TestAddItemSimple(t *testing.T) {
|
||||
var err error
|
||||
cps1 := []string{"\\O(I)\\C"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: nil, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(cps1, []float64{1.1}),
|
||||
expandPaths: map[string][]string{
|
||||
cps1[0]: cps1,
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.AddItem(cps1[0], "I", "test", false)
|
||||
require.NoError(t, err)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigGet7(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 3)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
counters[1] = "% Processor TimeERROR"
|
||||
counters[2] = "% Idle Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = false
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
func TestAddItemInvalidCountPath(t *testing.T) {
|
||||
var err error
|
||||
cps1 := []string{"\\O\\C"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: nil, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(cps1, []float64{1.1}),
|
||||
expandPaths: map[string][]string{
|
||||
cps1[0]: {"\\O/C"},
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
|
||||
var parsedItems = m.GetParsedItemsForTesting()
|
||||
|
||||
if len(parsedItems) == 2 {
|
||||
require.NoError(t, nil)
|
||||
} else if len(parsedItems) < 2 {
|
||||
var errorstring1 string = "Too few results returned from the query: " +
|
||||
string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
} else if len(parsedItems) > 2 {
|
||||
var errorstring1 string = "Too many results returned from the query: " +
|
||||
string(len(parsedItems))
|
||||
err2 := errors.New(errorstring1)
|
||||
require.NoError(t, err2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigError1(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor InformationERROR"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
err = m.AddItem("\\O\\C", "*", "test", false)
|
||||
require.Error(t, err)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigError2(t *testing.T) {
|
||||
func TestParseConfigBasic(t *testing.T) {
|
||||
var err error
|
||||
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false)
|
||||
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3, 1.4}),
|
||||
expandPaths: map[string][]string{
|
||||
cps1[0]: {cps1[0]},
|
||||
cps1[1]: {cps1[1]},
|
||||
cps1[2]: {cps1[2]},
|
||||
cps1[3]: {cps1[3]},
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, m.counters, 4)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
func TestParseConfigNoInstance(t *testing.T) {
|
||||
var err error
|
||||
perfObjects := createPerfObject("m", "O", []string{"------"}, []string{"C1", "C2"}, false, false)
|
||||
cps1 := []string{"\\O\\C1", "\\O\\C2"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(cps1, []float64{1.1, 1.2}),
|
||||
expandPaths: map[string][]string{
|
||||
cps1[0]: {cps1[0]},
|
||||
cps1[1]: {cps1[1]},
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, m.counters, 2)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
objectname := "Processor"
|
||||
instances[0] = "SuperERROR"
|
||||
counters[0] = "% C1 Time"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
func TestParseConfigInvalidCounterError(t *testing.T) {
|
||||
var err error
|
||||
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, true, false)
|
||||
cps1 := []string{"\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}),
|
||||
expandPaths: map[string][]string{
|
||||
cps1[0]: {cps1[0]},
|
||||
cps1[1]: {cps1[1]},
|
||||
cps1[2]: {cps1[2]},
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.ParseConfig()
|
||||
require.Error(t, err)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersConfigError3(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "% Processor TimeERROR"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
|
||||
err := m.ParseConfig()
|
||||
require.Error(t, err)
|
||||
func TestParseConfigInvalidCounterNoError(t *testing.T) {
|
||||
var err error
|
||||
perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false)
|
||||
cps1 := []string{"\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}),
|
||||
expandPaths: map[string][]string{
|
||||
cps1[0]: {cps1[0]},
|
||||
cps1[1]: {cps1[1]},
|
||||
cps1[2]: {cps1[2]},
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestWinPerfcountersCollect1(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 1)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
counters[0] = "Parking Status"
|
||||
|
||||
var expectedCounter string = "Parking_Status"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
var acc testutil.Accumulator
|
||||
err := m.Gather(&acc)
|
||||
func TestParseConfigTotal(t *testing.T) {
|
||||
var err error
|
||||
perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, true, true)
|
||||
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(_Total)\\C1", "\\O(_Total)\\C2"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}),
|
||||
expandPaths: map[string][]string{
|
||||
"\\O(*)\\*": cps1,
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, m.counters, 4)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
err = m.Gather(&acc)
|
||||
|
||||
tags := map[string]string{
|
||||
"instance": instances[0],
|
||||
"objectname": objectname,
|
||||
}
|
||||
fields := map[string]interface{}{
|
||||
expectedCounter: float32(0),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, measurement, fields, tags)
|
||||
perfObjects[0].IncludeTotal = false
|
||||
|
||||
m = Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}),
|
||||
expandPaths: map[string][]string{
|
||||
"\\O(*)\\*": cps1,
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, m.counters, 2)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
func TestWinPerfcountersCollect2(t *testing.T) {
|
||||
|
||||
var instances = make([]string, 2)
|
||||
var counters = make([]string, 1)
|
||||
var perfobjects = make([]perfobject, 1)
|
||||
func TestParseConfigExpand(t *testing.T) {
|
||||
var err error
|
||||
perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, false, false)
|
||||
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}),
|
||||
expandPaths: map[string][]string{
|
||||
"\\O(*)\\*": cps1,
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}}
|
||||
err = m.query.Open()
|
||||
require.NoError(t, err)
|
||||
err = m.ParseConfig()
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, m.counters, 4)
|
||||
err = m.query.Close()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
objectname := "Processor Information"
|
||||
instances[0] = "_Total"
|
||||
instances[1] = "0,0"
|
||||
counters[0] = "Performance Limit Flags"
|
||||
|
||||
var expectedCounter string = "Performance_Limit_Flags"
|
||||
|
||||
var measurement string = "test"
|
||||
var warnonmissing bool = false
|
||||
var failonmissing bool = true
|
||||
var includetotal bool = false
|
||||
|
||||
PerfObject := perfobject{
|
||||
ObjectName: objectname,
|
||||
Instances: instances,
|
||||
Counters: counters,
|
||||
Measurement: measurement,
|
||||
WarnOnMissing: warnonmissing,
|
||||
FailOnMissing: failonmissing,
|
||||
IncludeTotal: includetotal,
|
||||
func TestSimpleGather(t *testing.T) {
|
||||
var err error
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping long taking test in short mode")
|
||||
}
|
||||
|
||||
perfobjects[0] = PerfObject
|
||||
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfobjects}
|
||||
var acc testutil.Accumulator
|
||||
err := m.Gather(&acc)
|
||||
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{1.2}),
|
||||
expandPaths: map[string][]string{
|
||||
cp1: {cp1},
|
||||
},
|
||||
addEnglishSupported: false,
|
||||
}}
|
||||
var acc1 testutil.Accumulator
|
||||
err = m.Gather(&acc1)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
err = m.Gather(&acc)
|
||||
|
||||
tags := map[string]string{
|
||||
"instance": instances[0],
|
||||
"objectname": objectname,
|
||||
fields1 := map[string]interface{}{
|
||||
"C": float32(1.2),
|
||||
}
|
||||
fields := map[string]interface{}{
|
||||
expectedCounter: float32(0),
|
||||
tags1 := map[string]string{
|
||||
"instance": "I",
|
||||
"objectname": "O",
|
||||
}
|
||||
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
||||
}
|
||||
|
||||
func TestGatherInvalidDataIgnore(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{"C1", "C2", "C3"}, false, false)
|
||||
cps1 := []string{"\\O(I)\\C1", "\\O(I)\\C2", "\\O(I)\\C3"}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: &FakePerformanceQuery{
|
||||
counters: createCounterMap(cps1, []float64{1.2, -1, 0}),
|
||||
expandPaths: map[string][]string{
|
||||
cps1[0]: {cps1[0]},
|
||||
cps1[1]: {cps1[1]},
|
||||
cps1[2]: {cps1[2]},
|
||||
},
|
||||
addEnglishSupported: false,
|
||||
}}
|
||||
var acc1 testutil.Accumulator
|
||||
err = m.Gather(&acc1)
|
||||
require.NoError(t, err)
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"C1": float32(1.2),
|
||||
}
|
||||
tags1 := map[string]string{
|
||||
"instance": "I",
|
||||
"objectname": "O",
|
||||
}
|
||||
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
||||
}
|
||||
|
||||
func TestGatherRefreshing(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{"*"}, []string{"*"}, 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}),
|
||||
expandPaths: map[string][]string{
|
||||
"\\O(*)\\*": cps1,
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}
|
||||
m := Win_PerfCounters{PrintValid: false, Object: perfObjects, query: fpm, CountersRefreshInterval: internal.Duration{Duration: time.Second * 10}}
|
||||
var acc1 testutil.Accumulator
|
||||
err = m.Gather(&acc1)
|
||||
assert.Len(t, m.counters, 4)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, acc1.Metrics, 2)
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"C1": float32(1.1),
|
||||
"C2": float32(1.2),
|
||||
}
|
||||
tags1 := map[string]string{
|
||||
"instance": "I1",
|
||||
"objectname": "O",
|
||||
}
|
||||
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
||||
|
||||
fields2 := map[string]interface{}{
|
||||
"C1": float32(1.3),
|
||||
"C2": float32(1.4),
|
||||
}
|
||||
tags2 := map[string]string{
|
||||
"instance": "I2",
|
||||
"objectname": "O",
|
||||
}
|
||||
acc1.AssertContainsTaggedFields(t, measurement, fields2, tags2)
|
||||
cps2 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2", "\\O(I3)\\C1", "\\O(I3)\\C2"}
|
||||
fpm = &FakePerformanceQuery{
|
||||
counters: createCounterMap(append(cps2, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 0}),
|
||||
expandPaths: map[string][]string{
|
||||
"\\O(*)\\*": cps2,
|
||||
},
|
||||
addEnglishSupported: true,
|
||||
}
|
||||
m.query = fpm
|
||||
fpm.Open()
|
||||
var acc2 testutil.Accumulator
|
||||
|
||||
fields3 := map[string]interface{}{
|
||||
"C1": float32(1.5),
|
||||
"C2": float32(1.6),
|
||||
}
|
||||
tags3 := map[string]string{
|
||||
"instance": "I3",
|
||||
"objectname": "O",
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, measurement, fields, tags)
|
||||
tags = map[string]string{
|
||||
"instance": instances[1],
|
||||
"objectname": objectname,
|
||||
}
|
||||
fields = map[string]interface{}{
|
||||
expectedCounter: float32(0),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, measurement, fields, tags)
|
||||
//test before elapsing CounterRefreshRate counters are not refreshed
|
||||
err = m.Gather(&acc2)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, m.counters, 4)
|
||||
assert.Len(t, acc2.Metrics, 2)
|
||||
|
||||
acc2.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
||||
acc2.AssertContainsTaggedFields(t, measurement, fields2, tags2)
|
||||
acc2.AssertDoesNotContainsTaggedFields(t, measurement, fields3, tags3)
|
||||
time.Sleep(m.CountersRefreshInterval.Duration)
|
||||
|
||||
var acc3 testutil.Accumulator
|
||||
err = m.Gather(&acc3)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, acc3.Metrics, 3)
|
||||
|
||||
acc3.AssertContainsTaggedFields(t, measurement, fields1, tags1)
|
||||
acc3.AssertContainsTaggedFields(t, measurement, fields2, tags2)
|
||||
|
||||
acc3.AssertContainsTaggedFields(t, measurement, fields3, tags3)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue