From 2529d5fa16d1ec695aec679b4b4b3ab921bc34f9 Mon Sep 17 00:00:00 2001 From: Sven Rebhan <36194019+srebhan@users.noreply.github.com> Date: Fri, 27 Jan 2023 18:22:25 +0100 Subject: [PATCH] feat(inputs.win_perf_counters): add remote system support (#12556) --- plugins/inputs/win_perf_counters/README.md | 63 +- .../win_perf_counters/performance_query.go | 11 + .../win_perf_counters/win_perf_counters.go | 304 ++-- .../win_perf_counters_integration_test.go | 238 ++- .../win_perf_counters_test.go | 1407 +++++++++++++---- 5 files changed, 1529 insertions(+), 494 deletions(-) diff --git a/plugins/inputs/win_perf_counters/README.md b/plugins/inputs/win_perf_counters/README.md index 41cf5badd..bbe874dbf 100644 --- a/plugins/inputs/win_perf_counters/README.md +++ b/plugins/inputs/win_perf_counters/README.md @@ -26,6 +26,20 @@ For more information on concepts and terminology including object, counter, and instance names, see the help in the Windows Performance Monitor app. +### Schema + +*Measurement name* is specified per performance object +or `win_perf_counters` by default. + +*Tags:* + +- source - computer name, as specified in the `Sources` parameter. Name `localhost` is translated into the host name +- objectname - normalized name of the performance object +- instance - instance name, if performance object supports multiple instances, otherwise omitted + +*Fields* are counters of the performance object. +The field name is normalized counter name. + ### Plugin wide Plugin wide entries are underneath `[[inputs.win_perf_counters]]`. @@ -124,6 +138,27 @@ errors](pdh.go). Example: `IgnoredErrors=["PDH_NO_DATA"]` +#### Sources + +(Optional) + +Host names or ip addresses of computers to gather all performance counters from. +The user running Telegraf must be authenticated to the remote computer(s). +E.g. via Windows sharing `net use \\SQL-SERVER-01`. +Use either localhost (`"localhost"`) or real local computer name to gather +counters also from localhost among other computers. Skip, if gather only from +localhost. + +If a performance counter is present only on specific hosts set `Sources` param +on the specific counter level configuration to override global (plugin wide) +sources. + +Example: +`Sources = ["localhost", "SQL-SERVER-01", "SQL-SERVER-02", "SQL-SERVER-03"]` + +Default: +`Sources = ["localhost"]` + ### Object See Entry below. @@ -181,6 +216,13 @@ This must be specified for every counter you want the results of, or use `["*"]` for all the counters of the object, if the `UseWildcardsExpansion` param is set to `true`. +#### Sources (Object) + +(Optional) + +Overrides the [Sources](#sources) global parameter for current performance +object. See [Sources](#sources) description for more details. + #### Measurement (Optional) @@ -204,8 +246,17 @@ 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 +Note: Time based counters (i.e. *% Processor Time*) are reported in hundredths of nanoseconds. +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` @@ -623,11 +674,17 @@ to check the counter path on the command line. E.g. `typeperf If no metrics are emitted even with the default config, you may need to repair your performance counters. -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. 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: ```batchfile lodctr /r ``` + +## Metrics + +## Example Output diff --git a/plugins/inputs/win_perf_counters/performance_query.go b/plugins/inputs/win_perf_counters/performance_query.go index fdb3b85a4..232711457 100644 --- a/plugins/inputs/win_perf_counters/performance_query.go +++ b/plugins/inputs/win_perf_counters/performance_query.go @@ -33,6 +33,10 @@ type PerformanceQuery interface { IsVistaOrNewer() bool } +type PerformanceQueryCreator interface { + NewPerformanceQuery(string) PerformanceQuery +} + // PdhError represents error returned from Performance Counters API type PdhError struct { ErrorCode uint32 @@ -55,6 +59,13 @@ type PerformanceQueryImpl struct { query PDH_HQUERY } +type PerformanceQueryCreatorImpl struct { +} + +func (m PerformanceQueryCreatorImpl) NewPerformanceQuery(string) PerformanceQuery { + return &PerformanceQueryImpl{} +} + // 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 { diff --git a/plugins/inputs/win_perf_counters/win_perf_counters.go b/plugins/inputs/win_perf_counters/win_perf_counters.go index 7d981cd6b..5a1dc4187 100644 --- a/plugins/inputs/win_perf_counters/win_perf_counters.go +++ b/plugins/inputs/win_perf_counters/win_perf_counters.go @@ -7,7 +7,9 @@ import ( _ "embed" "errors" "fmt" + "os" "strings" + "sync" "time" "github.com/influxdata/telegraf" @@ -18,7 +20,7 @@ import ( //go:embed sample.conf var sampleConfig string -type Win_PerfCounters struct { +type WinPerfCounters struct { PrintValid bool `toml:"PrintValid"` PreVistaSupport bool `toml:"PreVistaSupport" deprecated:"1.7.0;determined dynamically"` UsePerfCounterTime bool @@ -27,15 +29,29 @@ type Win_PerfCounters struct { UseWildcardsExpansion bool LocalizeWildcardsExpansion bool IgnoredErrors []string `toml:"IgnoredErrors"` + Sources []string Log telegraf.Logger lastRefreshed time.Time - counters []*counter - query PerformanceQuery + queryCreator PerformanceQueryCreator + hostCounters map[string]*hostCountersInfo + // cached os.Hostname() + cachedHostname string +} + +type hostCountersInfo struct { + // computer name used as key and for printing + computer string + // computer name used in tag + tag string + counters []*counter + query PerformanceQuery + timestamp time.Time } type perfobject struct { + Sources []string ObjectName string Counters []string Instances []string @@ -48,6 +64,7 @@ type perfobject struct { type counter struct { counterPath string + computer string objectName string counter string instance string @@ -63,20 +80,22 @@ type instanceGrouping struct { objectname string } +type fieldGrouping map[instanceGrouping]map[string]interface{} + var sanitizedChars = strings.NewReplacer("/sec", "_persec", "/Sec", "_persec", " ", "_", "%", "Percent", `\`, "") // extractCounterInfoFromCounterPath gets object name, instance name (if available) and counter name from counter path // 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 -func extractCounterInfoFromCounterPath(counterPath string) (object string, instance string, counter string, err error) { - +func extractCounterInfoFromCounterPath(counterPath string) (string, string, string, string, error) { + leftComputerBorderIndex := -1 rightObjectBorderIndex := -1 leftObjectBorderIndex := -1 leftCounterBorderIndex := -1 rightInstanceBorderIndex := -1 leftInstanceBorderIndex := -1 - bracketLevel := 0 + var bracketLevel int for i := len(counterPath) - 1; i >= 0; i-- { switch counterPath[i] { @@ -86,6 +105,8 @@ func extractCounterInfoFromCounterPath(counterPath string) (object string, insta leftCounterBorderIndex = i } else if leftObjectBorderIndex == -1 { leftObjectBorderIndex = i + } else if leftComputerBorderIndex == -1 { + leftComputerBorderIndex = i } } case '(': @@ -105,31 +126,46 @@ func extractCounterInfoFromCounterPath(counterPath string) (object string, insta rightObjectBorderIndex = leftCounterBorderIndex } if rightObjectBorderIndex == -1 || leftObjectBorderIndex == -1 { - err = errors.New("cannot parse object from: " + counterPath) - return + return "", "", "", "", errors.New("cannot parse object from: " + counterPath) + } + + var computer, object, instance, counter string + if leftComputerBorderIndex > -1 { + // validate there is leading \\ and not empty computer (\\\O) + if leftComputerBorderIndex != 1 || leftComputerBorderIndex == leftObjectBorderIndex-1 { + return "", "", "", "", errors.New("cannot parse computer from: " + counterPath) + } + computer = counterPath[leftComputerBorderIndex+1 : leftObjectBorderIndex] } if leftInstanceBorderIndex > -1 && rightInstanceBorderIndex > -1 { instance = counterPath[leftInstanceBorderIndex+1 : rightInstanceBorderIndex] } else if (leftInstanceBorderIndex == -1 && rightInstanceBorderIndex > -1) || (leftInstanceBorderIndex > -1 && rightInstanceBorderIndex == -1) { - err = errors.New("cannot parse instance from: " + counterPath) - return + return "", "", "", "", errors.New("cannot parse instance from: " + counterPath) } object = counterPath[leftObjectBorderIndex+1 : rightObjectBorderIndex] counter = counterPath[leftCounterBorderIndex+1:] - return + return computer, object, instance, counter, nil } -func newCounter( - counterHandle PDH_HCOUNTER, - counterPath string, - objectName string, - instance string, - counterName string, - measurement string, - includeTotal bool, - useRawValue bool, -) *counter { +func (m *WinPerfCounters) SampleConfig() string { + return sampleConfig +} + +func (m *WinPerfCounters) hostname() string { + if m.cachedHostname != "" { + return m.cachedHostname + } + hostname, err := os.Hostname() + if err != nil { + m.cachedHostname = "localhost" + } else { + m.cachedHostname = hostname + } + return m.cachedHostname +} + +func newCounter(counterHandle PDH_HCOUNTER, counterPath string, computer string, objectName string, instance string, counterName string, measurement string, includeTotal bool, useRawValue bool) *counter { measurementName := sanitizedChars.Replace(measurement) if measurementName == "" { measurementName = "win_perf_counters" @@ -138,59 +174,68 @@ func newCounter( if useRawValue { newCounterName += "_Raw" } - return &counter{counterPath, objectName, newCounterName, instance, measurementName, + return &counter{counterPath, computer, objectName, newCounterName, instance, measurementName, includeTotal, useRawValue, counterHandle} } -func (*Win_PerfCounters) SampleConfig() string { - return sampleConfig -} - -func (m *Win_PerfCounters) AddItem( - counterPath string, - objectName string, - instance string, - counterName string, - measurement string, - includeTotal bool, - useRawValue bool, -) error { +func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, counterName, measurement string, includeTotal bool, useRawValue bool) error { origCounterPath := counterPath var err error var counterHandle PDH_HCOUNTER - if !m.query.IsVistaOrNewer() { - counterHandle, err = m.query.AddCounterToQuery(counterPath) + + sourceTag := computer + if computer == "localhost" { + sourceTag = m.hostname() + } + if m.hostCounters == nil { + m.hostCounters = make(map[string]*hostCountersInfo) + } + hostCounter, ok := m.hostCounters[computer] + if !ok { + hostCounter = &hostCountersInfo{computer: computer, tag: sourceTag} + m.hostCounters[computer] = hostCounter + hostCounter.query = m.queryCreator.NewPerformanceQuery(computer) + if err = hostCounter.query.Open(); err != nil { + return err + } + hostCounter.counters = make([]*counter, 0) + } + + if !hostCounter.query.IsVistaOrNewer() { + counterHandle, err = hostCounter.query.AddCounterToQuery(counterPath) if err != nil { return err } } else { - counterHandle, err = m.query.AddEnglishCounterToQuery(counterPath) + counterHandle, err = hostCounter.query.AddEnglishCounterToQuery(counterPath) if err != nil { return err } - } if m.UseWildcardsExpansion { origInstance := instance - counterPath, err = m.query.GetCounterPath(counterHandle) + counterPath, err = hostCounter.query.GetCounterPath(counterHandle) if err != nil { return err } - counters, err := m.query.ExpandWildCardPath(counterPath) + counters, err := hostCounter.query.ExpandWildCardPath(counterPath) if err != nil { return err } - origObjectName, _, origCounterName, err := extractCounterInfoFromCounterPath(origCounterPath) + _, origObjectName, _, origCounterName, err := extractCounterInfoFromCounterPath(origCounterPath) if err != nil { return err } for _, counterPath := range counters { - var err error + _, err := hostCounter.query.AddCounterToQuery(counterPath) + if err != nil { + return err + } - objectName, instance, counterName, err = extractCounterInfoFromCounterPath(counterPath) + computer, objectName, instance, counterName, err = extractCounterInfoFromCounterPath(counterPath) if err != nil { return err } @@ -209,11 +254,15 @@ func (m *Win_PerfCounters) AddItem( } else { newInstance = instance } - counterPath = formatPath(origObjectName, newInstance, origCounterName) - counterHandle, err = m.query.AddEnglishCounterToQuery(counterPath) + counterPath = formatPath(computer, origObjectName, newInstance, origCounterName) + counterHandle, err = hostCounter.query.AddEnglishCounterToQuery(counterPath) + if err != nil { + return err + } newItem = newCounter( counterHandle, counterPath, + computer, origObjectName, instance, origCounterName, measurement, @@ -221,10 +270,14 @@ func (m *Win_PerfCounters) AddItem( useRawValue, ) } else { - counterHandle, err = m.query.AddCounterToQuery(counterPath) + counterHandle, err = hostCounter.query.AddCounterToQuery(counterPath) + if err != nil { + return err + } newItem = newCounter( counterHandle, counterPath, + computer, objectName, instance, counterName, @@ -238,7 +291,7 @@ func (m *Win_PerfCounters) AddItem( continue } - m.counters = append(m.counters, newItem) + hostCounter.counters = append(hostCounter.counters, newItem) if m.PrintValid { m.Log.Infof("Valid: %s", counterPath) @@ -248,6 +301,7 @@ func (m *Win_PerfCounters) AddItem( newItem := newCounter( counterHandle, counterPath, + computer, objectName, instance, counterName, @@ -255,7 +309,7 @@ func (m *Win_PerfCounters) AddItem( includeTotal, useRawValue, ) - m.counters = append(m.counters, newItem) + hostCounter.counters = append(hostCounter.counters, newItem) if m.PrintValid { m.Log.Infof("Valid: %s", counterPath) } @@ -266,19 +320,41 @@ func (m *Win_PerfCounters) AddItem( const emptyInstance = "------" -func formatPath(objectname string, instance string, counter string) string { +func formatPath(computer, objectname, instance, counter string) string { + path := "" if instance == emptyInstance { - return "\\" + objectname + "\\" + counter + path = fmt.Sprintf(`\%s\%s`, objectname, counter) } else { - return "\\" + objectname + "(" + instance + ")\\" + counter + path = fmt.Sprintf(`\%s(%s)\%s`, objectname, instance, counter) } + if computer != "" && computer != "localhost" { + path = fmt.Sprintf(`\\%s%s`, computer, path) + } + return path } -func (m *Win_PerfCounters) ParseConfig() error { +func (m *WinPerfCounters) ParseConfig() error { var counterPath string - if len(m.Object) > 0 { - for _, PerfObject := range m.Object { + if len(m.Sources) == 0 { + m.Sources = []string{"localhost"} + } + + if len(m.Object) <= 0 { + err := errors.New("no performance objects configured") + return err + } + + for _, PerfObject := range m.Object { + computers := PerfObject.Sources + if len(computers) == 0 { + computers = m.Sources + } + for _, computer := range computers { + if computer == "" { + // localhost as a computer name in counter path doesn't work + computer = "localhost" + } for _, counter := range PerfObject.Counters { if len(PerfObject.Instances) == 0 { m.Log.Warnf("Missing 'Instances' param for object '%s'\n", PerfObject.ObjectName) @@ -286,13 +362,12 @@ func (m *Win_PerfCounters) ParseConfig() error { for _, instance := range PerfObject.Instances { objectname := PerfObject.ObjectName - counterPath = formatPath(objectname, instance, counter) - - err := m.AddItem(counterPath, objectname, instance, counter, PerfObject.Measurement, PerfObject.IncludeTotal, PerfObject.UseRawValues) + counterPath = formatPath(computer, objectname, instance, counter) + err := m.AddItem(counterPath, computer, objectname, instance, counter, PerfObject.Measurement, PerfObject.IncludeTotal, PerfObject.UseRawValues) if err != nil { if PerfObject.FailOnMissing || PerfObject.WarnOnMissing { - m.Log.Errorf("Invalid counterPath: '%s'. Error: %s\n", counterPath, err.Error()) + m.Log.Errorf("invalid counterPath: '%s'. Error: %s\n", counterPath, err.Error()) } if PerfObject.FailOnMissing { return err @@ -301,15 +376,12 @@ func (m *Win_PerfCounters) ParseConfig() error { } } } - return nil - } else { - err := errors.New("no performance objects configured") - return err } + return nil } -func (m *Win_PerfCounters) checkError(err error) error { +func (m *WinPerfCounters) checkError(err error) error { if pdhErr, ok := err.(*PdhError); ok { for _, ignoredErrors := range m.IgnoredErrors { if PDHErrors[pdhErr.ErrorCode] == ignoredErrors { @@ -322,54 +394,74 @@ func (m *Win_PerfCounters) checkError(err error) error { return err } -func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error { +func (m *WinPerfCounters) Gather(acc telegraf.Accumulator) error { // Parse the config once var err error if m.lastRefreshed.IsZero() || (m.CountersRefreshInterval > 0 && m.lastRefreshed.Add(time.Duration(m.CountersRefreshInterval)).Before(time.Now())) { - if m.counters != nil { - m.counters = m.counters[:0] - } - - if err = m.query.Open(); err != nil { + if err = m.cleanQueries(); err != nil { return err } if err = m.ParseConfig(); err != nil { return err } - //some counters need two data samples before computing a value - if err = m.query.CollectData(); err != nil { - return m.checkError(err) + for _, hostCounterSet := range m.hostCounters { + //some counters need two data samples before computing a value + if err = hostCounterSet.query.CollectData(); err != nil { + return m.checkError(err) + } } m.lastRefreshed = time.Now() - + // minimum time between collecting two samples time.Sleep(time.Second) } - var collectFields = make(map[instanceGrouping]map[string]interface{}) - - var timestamp time.Time - if m.UsePerfCounterTime && m.query.IsVistaOrNewer() { - timestamp, err = m.query.CollectDataWithTime() - if err != nil { - return err - } - } else { - timestamp = time.Now() - if err = m.query.CollectData(); err != nil { - return err + for _, hostCounterSet := range m.hostCounters { + if m.UsePerfCounterTime && hostCounterSet.query.IsVistaOrNewer() { + hostCounterSet.timestamp, err = hostCounterSet.query.CollectDataWithTime() + if err != nil { + return err + } + } else { + hostCounterSet.timestamp = time.Now() + if err = hostCounterSet.query.CollectData(); err != nil { + return err + } } } + var wg sync.WaitGroup + //iterate over computers + for _, hostCounterInfo := range m.hostCounters { + wg.Add(1) + go func(hostInfo *hostCountersInfo) { + m.Log.Debugf("gathering from %s", hostInfo.computer) + start := time.Now() + err := m.gatherComputerCounters(hostInfo, acc) + m.Log.Debugf("gathering from %s finished in %.3fs", hostInfo.computer, time.Since(start)) + if err != nil { + acc.AddError(fmt.Errorf("error during collecting data on host '%s': %s", hostInfo.computer, err.Error())) + } + wg.Done() + }(hostCounterInfo) + } + + wg.Wait() + return nil +} + +func (m *WinPerfCounters) gatherComputerCounters(hostCounterInfo *hostCountersInfo, acc telegraf.Accumulator) error { var value interface{} + var err error + collectedFields := make(fieldGrouping) // For iterate over the known metrics and get the samples. - for _, metric := range m.counters { + for _, metric := range hostCounterInfo.counters { // collect if m.UseWildcardsExpansion { if metric.useRawValue { - value, err = m.query.GetRawCounterValue(metric.counterHandle) + value, err = hostCounterInfo.query.GetRawCounterValue(metric.counterHandle) } else { - value, err = m.query.GetFormattedCounterValueDouble(metric.counterHandle) + value, err = hostCounterInfo.query.GetFormattedCounterValueDouble(metric.counterHandle) } if err != nil { //ignore invalid data as some counters from process instances returns this sometimes @@ -379,13 +471,13 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error { m.Log.Warnf("error while getting value for counter %q, instance: %s, will skip metric: %v", metric.counterPath, metric.instance, err) continue } - addCounterMeasurement(metric, metric.instance, value, collectFields) + addCounterMeasurement(metric, metric.instance, value, collectedFields) } else { var counterValues []CounterValue if metric.useRawValue { - counterValues, err = m.query.GetRawCounterArray(metric.counterHandle) + counterValues, err = hostCounterInfo.query.GetRawCounterArray(metric.counterHandle) } else { - counterValues, err = m.query.GetFormattedCounterArrayDouble(metric.counterHandle) + counterValues, err = hostCounterInfo.query.GetFormattedCounterArrayDouble(metric.counterHandle) } if err != nil { //ignore invalid data as some counters from process instances returns this sometimes @@ -404,22 +496,34 @@ func (m *Win_PerfCounters) Gather(acc telegraf.Accumulator) error { } if shouldIncludeMetric(metric, cValue) { - addCounterMeasurement(metric, cValue.InstanceName, cValue.Value, collectFields) + addCounterMeasurement(metric, cValue.InstanceName, cValue.Value, collectedFields) } } } } - - for instance, fields := range collectFields { + for instance, fields := range collectedFields { var tags = map[string]string{ "objectname": instance.objectname, } if len(instance.instance) > 0 { tags["instance"] = instance.instance } - acc.AddFields(instance.name, fields, tags, timestamp) + if len(hostCounterInfo.tag) > 0 { + tags["source"] = hostCounterInfo.tag + } + acc.AddFields(instance.name, fields, tags, hostCounterInfo.timestamp) } + return nil +} + +func (m *WinPerfCounters) cleanQueries() error { + for _, hostCounterInfo := range m.hostCounters { + if err := hostCounterInfo.query.Close(); err != nil { + return err + } + } + m.hostCounters = nil return nil } @@ -442,7 +546,7 @@ func shouldIncludeMetric(metric *counter, cValue CounterValue) bool { return false } -func addCounterMeasurement(metric *counter, instanceName string, value interface{}, collectFields map[instanceGrouping]map[string]interface{}) { +func addCounterMeasurement(metric *counter, instanceName string, value interface{}, collectFields fieldGrouping) { var instance = instanceGrouping{metric.measurement, instanceName, metric.objectName} if collectFields[instance] == nil { collectFields[instance] = make(map[string]interface{}) @@ -461,7 +565,7 @@ func isKnownCounterDataError(err error) bool { return false } -func (m *Win_PerfCounters) Init() error { +func (m *WinPerfCounters) Init() error { if m.UseWildcardsExpansion && !m.LocalizeWildcardsExpansion { // Counters must not have wildcards with this option @@ -494,10 +598,10 @@ func (m *Win_PerfCounters) Init() error { func init() { inputs.Add("win_perf_counters", func() telegraf.Input { - return &Win_PerfCounters{ - query: &PerformanceQueryImpl{}, + return &WinPerfCounters{ CountersRefreshInterval: config.Duration(time.Second * 60), LocalizeWildcardsExpansion: true, + queryCreator: &PerformanceQueryCreatorImpl{}, } }) } diff --git a/plugins/inputs/win_perf_counters/win_perf_counters_integration_test.go b/plugins/inputs/win_perf_counters/win_perf_counters_integration_test.go index d2588ef53..7aebb4e50 100644 --- a/plugins/inputs/win_perf_counters/win_perf_counters_integration_test.go +++ b/plugins/inputs/win_perf_counters/win_perf_counters_integration_test.go @@ -3,15 +3,13 @@ package win_perf_counters import ( - "errors" "fmt" "strings" "testing" "time" - "github.com/stretchr/testify/require" - "github.com/influxdata/telegraf/testutil" + "github.com/stretchr/testify/require" ) func TestWinPerformanceQueryImplIntegration(t *testing.T) { @@ -152,13 +150,12 @@ func TestWinPerfcountersConfigGet1Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.NoError(t, err) @@ -191,26 +188,26 @@ func TestWinPerfcountersConfigGet2Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.NoError(t, err) - if len(m.counters) == 1 { + hostCounters, ok := m.hostCounters["localhost"] + require.True(t, ok) + + if len(hostCounters.counters) == 1 { require.NoError(t, nil) - } else if len(m.counters) == 0 { - var errorstring1 = "No results returned from the counterPath" - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) == 0 { + err2 := fmt.Errorf("no results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) - } else if len(m.counters) > 1 { - var errorstring1 = fmt.Sprintf("Too many results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) > 1 { + err2 := fmt.Errorf("too many results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) } } @@ -220,6 +217,7 @@ func TestWinPerfcountersConfigGet3Integration(t *testing.T) { t.Skip("Skipping integration test in short mode") } + var sources = make([]string, 1) var instances = make([]string, 1) var counters = make([]string, 2) var perfobjects = make([]perfobject, 1) @@ -228,10 +226,12 @@ func TestWinPerfcountersConfigGet3Integration(t *testing.T) { instances[0] = "_Total" counters[0] = "% Processor Time" counters[1] = "% Idle Time" + sources[0] = "localhost" var measurement = "test" PerfObject := perfobject{ + Sources: sources, ObjectName: objectname, Instances: instances, Counters: counters, @@ -243,28 +243,26 @@ func TestWinPerfcountersConfigGet3Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.NoError(t, err) - if len(m.counters) == 2 { + hostCounters, ok := m.hostCounters["localhost"] + require.True(t, ok) + + if len(hostCounters.counters) == 2 { require.NoError(t, nil) - } else if len(m.counters) < 2 { - - var errorstring1 = fmt.Sprintf("Too few results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) < 2 { + err2 := fmt.Errorf("too few results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) - } else if len(m.counters) > 2 { - - var errorstring1 = fmt.Sprintf("Too many results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) > 2 { + err2 := fmt.Errorf("too many results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) } } @@ -297,28 +295,26 @@ func TestWinPerfcountersConfigGet4Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.NoError(t, err) - if len(m.counters) == 2 { + hostCounters, ok := m.hostCounters["localhost"] + require.True(t, ok) + + if len(hostCounters.counters) == 2 { require.NoError(t, nil) - } else if len(m.counters) < 2 { - - var errorstring1 = fmt.Sprintf("Too few results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) < 2 { + err2 := fmt.Errorf("too few results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) - } else if len(m.counters) > 2 { - - var errorstring1 = fmt.Sprintf("Too many results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) > 2 { + err2 := fmt.Errorf("too many results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) } } @@ -352,26 +348,26 @@ func TestWinPerfcountersConfigGet5Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.NoError(t, err) - if len(m.counters) == 4 { + hostCounters, ok := m.hostCounters["localhost"] + require.True(t, ok) + + if len(hostCounters.counters) == 4 { require.NoError(t, nil) - } else if len(m.counters) < 4 { - var errorstring1 = fmt.Sprintf("Too few results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) < 4 { + err2 := fmt.Errorf("too few results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) - } else if len(m.counters) > 4 { - var errorstring1 = fmt.Sprintf("Too many results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) > 4 { + err2 := fmt.Errorf("too many results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) } } @@ -403,16 +399,18 @@ func TestWinPerfcountersConfigGet6Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.NoError(t, err) + + _, ok := m.hostCounters["localhost"] + require.True(t, ok) } func TestWinPerfcountersConfigGet7Integration(t *testing.T) { @@ -433,38 +431,34 @@ func TestWinPerfcountersConfigGet7Integration(t *testing.T) { var measurement = "test" PerfObject := perfobject{ - objectname, - counters, - instances, - measurement, - false, - false, - false, - false, + ObjectName: objectname, + Counters: counters, + Instances: instances, + Measurement: measurement, } perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.NoError(t, err) - if len(m.counters) == 2 { + hostCounters, ok := m.hostCounters["localhost"] + require.True(t, ok) + + if len(hostCounters.counters) == 2 { require.NoError(t, nil) - } else if len(m.counters) < 2 { - var errorstring1 = fmt.Sprintf("Too few results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) < 2 { + err2 := fmt.Errorf("too few results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) - } else if len(m.counters) > 2 { - var errorstring1 = fmt.Sprintf("Too many results returned from the counterPath: %v", len(m.counters)) - err2 := errors.New(errorstring1) + } else if len(hostCounters.counters) > 2 { + err2 := fmt.Errorf("too many results returned from the counterPath: %v", len(hostCounters.counters)) require.NoError(t, err2) } } @@ -496,13 +490,12 @@ func TestWinPerfcountersConfigError1Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.Error(t, err) @@ -535,13 +528,12 @@ func TestWinPerfcountersConfigError2Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() var acc testutil.Accumulator @@ -576,13 +568,12 @@ func TestWinPerfcountersConfigError3Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } - _ = m.query.Open() err := m.ParseConfig() require.Error(t, err) @@ -616,11 +607,11 @@ func TestWinPerfcountersCollect1Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ - PrintValid: false, - Object: perfobjects, - query: &PerformanceQueryImpl{}, - Log: testutil.Logger{}, + m := WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + Log: testutil.Logger{}, } var acc testutil.Accumulator err := m.Gather(&acc) @@ -667,14 +658,15 @@ func TestWinPerfcountersCollect2Integration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ + m := WinPerfCounters{ PrintValid: false, UsePerfCounterTime: true, Object: perfobjects, - query: &PerformanceQueryImpl{}, + queryCreator: &PerformanceQueryCreatorImpl{}, UseWildcardsExpansion: true, Log: testutil.Logger{}, } + var acc testutil.Accumulator err := m.Gather(&acc) require.NoError(t, err) @@ -721,11 +713,11 @@ func TestWinPerfcountersCollectRawIntegration(t *testing.T) { perfobjects[0] = PerfObject - m := Win_PerfCounters{ + m := WinPerfCounters{ PrintValid: false, Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, UseWildcardsExpansion: true, - query: &PerformanceQueryImpl{}, Log: testutil.Logger{}, } var acc testutil.Accumulator @@ -746,7 +738,13 @@ func TestWinPerfcountersCollectRawIntegration(t *testing.T) { } // Test *Array way - m = Win_PerfCounters{PrintValid: false, Object: perfobjects, UseWildcardsExpansion: false, query: &PerformanceQueryImpl{}, Log: testutil.Logger{}} + m = WinPerfCounters{ + PrintValid: false, + Object: perfobjects, + queryCreator: &PerformanceQueryCreatorImpl{}, + UseWildcardsExpansion: false, + Log: testutil.Logger{}, + } var acc2 testutil.Accumulator err = m.Gather(&acc) require.NoError(t, err) diff --git a/plugins/inputs/win_perf_counters/win_perf_counters_test.go b/plugins/inputs/win_perf_counters/win_perf_counters_test.go index 91cc5fdaf..5156338f8 100644 --- a/plugins/inputs/win_perf_counters/win_perf_counters_test.go +++ b/plugins/inputs/win_perf_counters/win_perf_counters_test.go @@ -5,6 +5,7 @@ package win_perf_counters import ( "errors" "fmt" + "os" "testing" "time" @@ -30,7 +31,7 @@ type FakePerformanceQuery struct { var MetricTime = time.Date(2018, 5, 28, 12, 0, 0, 0, time.UTC) func (m *testCounter) ToCounterValue(raw bool) *CounterValue { - _, inst, _, _ := extractCounterInfoFromCounterPath(m.path) + _, _, inst, _, _ := extractCounterInfoFromCounterPath(m.path) if inst == "" { inst = "--" } @@ -224,7 +225,21 @@ func (m *FakePerformanceQuery) IsVistaOrNewer() bool { return m.vistaAndNewer } -func createPerfObject(measurement string, object string, instances []string, counters []string, failOnMissing, includeTotal, useRawValues bool) []perfobject { +type FakePerformanceQueryCreator struct { + fakeQueries map[string]*FakePerformanceQuery +} + +func (m FakePerformanceQueryCreator) NewPerformanceQuery(computer string) PerformanceQuery { + var ret PerformanceQuery + var ok bool + ret = nil + if ret, ok = m.fakeQueries[computer]; !ok { + panic(fmt.Errorf("query for %s not found", computer)) + } + return ret +} + +func createPerfObject(computer string, measurement string, object string, instances []string, counters []string, failOnMissing bool, includeTotal bool, useRawValues bool) []perfobject { PerfObject := perfobject{ ObjectName: object, Instances: instances, @@ -235,8 +250,11 @@ func createPerfObject(measurement string, object string, instances []string, cou IncludeTotal: includeTotal, UseRawValues: useRawValues, } - perfobjects := []perfobject{PerfObject} - return perfobjects + if computer != "" { + PerfObject.Sources = []string{computer} + } + perfObjects := []perfobject{PerfObject} + return perfObjects } func createCounterMap(counterPaths []string, values []float64, status []uint32) map[string]testCounter { @@ -252,25 +270,37 @@ func createCounterMap(counterPaths []string, values []float64, status []uint32) return counters } +var cachedHostname string + +func hostname() string { + if cachedHostname == "" { + var err error + if cachedHostname, err = os.Hostname(); err != nil { + cachedHostname = "localhost" + } + } + return cachedHostname +} + var counterPathsAndRes = map[string][]string{ - "\\O\\CT": {"O", "", "CT"}, - "\\O\\CT(i)": {"O", "", "CT(i)"}, - "\\O\\CT(d:\\f\\i)": {"O", "", "CT(d:\\f\\i)"}, - "\\\\CM\\O\\CT": {"O", "", "CT"}, - "\\O(I)\\CT": {"O", "I", "CT"}, - "\\O(I)\\CT(i)": {"O", "I", "CT(i)"}, - "\\O(I)\\CT(i)x": {"O", "I", "CT(i)x"}, - "\\O(I)\\CT(d:\\f\\i)": {"O", "I", "CT(d:\\f\\i)"}, - "\\\\CM\\O(I)\\CT": {"O", "I", "CT"}, - "\\O(d:\\f\\I)\\CT": {"O", "d:\\f\\I", "CT"}, - "\\O(d:\\f\\I(d))\\CT": {"O", "d:\\f\\I(d)", "CT"}, - "\\O(d:\\f\\I(d)x)\\CT": {"O", "d:\\f\\I(d)x", "CT"}, - "\\O(d:\\f\\I)\\CT(i)": {"O", "d:\\f\\I", "CT(i)"}, - "\\O(d:\\f\\I)\\CT(d:\\f\\i)": {"O", "d:\\f\\I", "CT(d:\\f\\i)"}, - "\\\\CM\\O(d:\\f\\I)\\CT": {"O", "d:\\f\\I", "CT"}, - "\\\\CM\\O(d:\\f\\I)\\CT(d:\\f\\i)": {"O", "d:\\f\\I", "CT(d:\\f\\i)"}, - "\\O(I(info))\\CT": {"O", "I(info)", "CT"}, - "\\\\CM\\O(I(info))\\CT": {"O", "I(info)", "CT"}, + "\\O\\CT": {"", "O", "", "CT"}, + "\\O\\CT(i)": {"", "O", "", "CT(i)"}, + "\\O\\CT(d:\\f\\i)": {"", "O", "", "CT(d:\\f\\i)"}, + "\\\\CM\\O\\CT": {"CM", "O", "", "CT"}, + "\\O(I)\\CT": {"", "O", "I", "CT"}, + "\\O(I)\\CT(i)": {"", "O", "I", "CT(i)"}, + "\\O(I)\\CT(i)x": {"", "O", "I", "CT(i)x"}, + "\\O(I)\\CT(d:\\f\\i)": {"", "O", "I", "CT(d:\\f\\i)"}, + "\\\\CM\\O(I)\\CT": {"CM", "O", "I", "CT"}, + "\\O(d:\\f\\I)\\CT": {"", "O", "d:\\f\\I", "CT"}, + "\\O(d:\\f\\I(d))\\CT": {"", "O", "d:\\f\\I(d)", "CT"}, + "\\O(d:\\f\\I(d)x)\\CT": {"", "O", "d:\\f\\I(d)x", "CT"}, + "\\O(d:\\f\\I)\\CT(i)": {"", "O", "d:\\f\\I", "CT(i)"}, + "\\O(d:\\f\\I)\\CT(d:\\f\\i)": {"", "O", "d:\\f\\I", "CT(d:\\f\\i)"}, + "\\\\CM\\O(d:\\f\\I)\\CT": {"CM", "O", "d:\\f\\I", "CT"}, + "\\\\CM\\O(d:\\f\\I)\\CT(d:\\f\\i)": {"CM", "O", "d:\\f\\I", "CT(d:\\f\\i)"}, + "\\O(I(info))\\CT": {"", "O", "I(info)", "CT"}, + "\\\\CM\\O(I(info))\\CT": {"CM", "O", "I(info)", "CT"}, } var invalidCounterPaths = []string{ @@ -282,16 +312,20 @@ var invalidCounterPaths = []string{ "\\O(I/C)", "\\O(I\\)C", "\\O(I\\C)", + "\\CM\\O(I)\\C", + "\\CM\\O\\C", + "\\\\C\\O(I)\\C)", + "\\\\C\\O\\C)", } func TestCounterPathParsing(t *testing.T) { for path, vals := range counterPathsAndRes { - o, i, c, err := extractCounterInfoFromCounterPath(path) + h, o, i, c, err := extractCounterInfoFromCounterPath(path) require.NoError(t, err) - require.Equalf(t, vals, []string{o, i, c}, "arrays: %#v and %#v are not equal", vals, []string{o, i, c}) + require.Equalf(t, vals, []string{h, o, i, c}, "arrays: %#v and %#v are not equal", vals, []string{o, i, c}) } for _, path := range invalidCounterPaths { - _, _, _, err := extractCounterInfoFromCounterPath(path) + _, _, _, _, err := extractCounterInfoFromCounterPath(path) require.Error(t, err) } } @@ -299,263 +333,867 @@ func TestCounterPathParsing(t *testing.T) { func TestAddItemSimple(t *testing.T) { var err error cps1 := []string{"\\O(I)\\C"} - m := Win_PerfCounters{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: nil, - query: &FakePerformanceQuery{ - counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}), - expandPaths: map[string][]string{ - cps1[0]: cps1, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}), + expandPaths: map[string][]string{ + cps1[0]: cps1, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() - require.NoError(t, err) - err = m.AddItem(cps1[0], "O", "I", "c", "test", false, true) - require.NoError(t, err) - err = m.query.Close() + }, + }, + } + err = m.AddItem(cps1[0], "localhost", "O", "I", "c", "test", false, false) require.NoError(t, err) + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 1) + require.True(t, counters.counters[0].computer == "localhost") + require.True(t, counters.counters[0].objectName == "O") + require.True(t, counters.counters[0].instance == "I") + require.True(t, counters.counters[0].counter == "c") + require.True(t, counters.counters[0].measurement == "test") + require.False(t, counters.counters[0].includeTotal) } func TestAddItemInvalidCountPath(t *testing.T) { var err error cps1 := []string{"\\O\\C"} - m := Win_PerfCounters{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: nil, UseWildcardsExpansion: true, - query: &FakePerformanceQuery{ - counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}), - expandPaths: map[string][]string{ - cps1[0]: {"\\O/C"}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}), + expandPaths: map[string][]string{ + cps1[0]: {"\\O/C"}, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() + }, + }, + } require.NoError(t, err) - err = m.AddItem("\\O\\C", "O", "------", "C", "test", false, false) + err = m.AddItem("\\O\\C", "localhost", "O", "------", "C", "test", false, false) require.Error(t, err) - err = m.query.Close() - require.NoError(t, err) } func TestParseConfigBasic(t *testing.T) { var err error - perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, 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{ + m := WinPerfCounters{ + Sources: []string{"localhost"}, Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3, 1.4}, []uint32{0, 0, 0, 0}), - expandPaths: map[string][]string{ - cps1[0]: {cps1[0]}, - cps1[1]: {cps1[1]}, - cps1[2]: {cps1[2]}, - cps1[3]: {cps1[3]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3, 1.4}, []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + cps1[1]: {cps1[1]}, + cps1[2]: {cps1[2]}, + cps1[3]: {cps1[3]}, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() + }, + }, + } require.NoError(t, err) err = m.ParseConfig() require.NoError(t, err) - require.Len(t, m.counters, 4) - err = m.query.Close() + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + err = m.cleanQueries() require.NoError(t, err) - m.UseWildcardsExpansion = true - m.counters = nil - err = m.query.Open() + err = m.ParseConfig() + require.NoError(t, err) + counters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) +} + +func TestParseConfigMultiComps(t *testing.T) { + var err error + perfObjects := []perfobject{ + createPerfObject("", "m", "O", []string{"I"}, []string{"C"}, false, false, false)[0], + createPerfObject("", "m", "O1", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)[0], + createPerfObject("", "m", "O2", []string{"I"}, []string{"C1", "C2", "C3"}, false, false, false)[0], + } + cps11 := []string{"\\O(I)\\C"} + cps12 := []string{"\\\\cmp1\\O(I)\\C"} + cps13 := []string{"\\\\cmp2\\O(I)\\C"} + cps21 := []string{"\\O1(I1)\\C1", "\\O1(I1)\\C2", "\\O1(I2)\\C1", "\\O1(I2)\\C2"} + cps22 := []string{"\\\\cmp1\\O1(I1)\\C1", "\\\\cmp1\\O1(I1)\\C2", "\\\\cmp1\\O1(I2)\\C1", "\\\\cmp1\\O1(I2)\\C2"} + cps23 := []string{"\\\\cmp2\\O1(I1)\\C1", "\\\\cmp2\\O1(I1)\\C2", "\\\\cmp2\\O1(I2)\\C1", "\\\\cmp2\\O1(I2)\\C2"} + cps31 := []string{"\\O2(I)\\C1", "\\O2(I)\\C2", "\\O2(I)\\C3"} + cps32 := []string{"\\\\cmp1\\O2(I)\\C1", "\\\\cmp1\\O2(I)\\C2", "\\\\cmp1\\O2(I)\\C3"} + cps33 := []string{"\\\\cmp2\\O2(I)\\C1", "\\\\cmp2\\O2(I)\\C2", "\\\\cmp2\\O2(I)\\C3"} + m := WinPerfCounters{ + Sources: []string{"localhost", "cmp1", "cmp2"}, + Log: testutil.Logger{}, + PrintValid: false, + Object: perfObjects, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{ + "localhost": { + counters: createCounterMap(append(append(cps11, cps21...), cps31...), + []float64{1.1, 1.1, 1.2, 2.1, 2.2, 1.1, 1.2, 1.3}, + []uint32{0, 0, 0, 0, 0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps11[0]: {cps11[0]}, + cps21[0]: {cps21[0]}, + cps21[1]: {cps21[1]}, + cps21[2]: {cps21[2]}, + cps21[3]: {cps21[3]}, + cps31[0]: {cps31[0]}, + cps31[1]: {cps31[1]}, + cps31[2]: {cps31[2]}, + }, + vistaAndNewer: true, + }, + "cmp1": { + counters: createCounterMap(append(append(cps12, cps22...), cps32...), + []float64{1.1, 1.1, 1.2, 2.1, 2.2, 1.1, 1.2, 1.3}, + []uint32{0, 0, 0, 0, 0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps12[0]: {cps12[0]}, + cps22[0]: {cps22[0]}, + cps22[1]: {cps22[1]}, + cps22[2]: {cps22[2]}, + cps22[3]: {cps22[3]}, + cps32[0]: {cps32[0]}, + cps32[1]: {cps32[1]}, + cps32[2]: {cps32[2]}, + }, + vistaAndNewer: true, + }, + "cmp2": { + counters: createCounterMap(append(append(cps13, cps23...), cps33...), + []float64{1.1, 1.1, 1.2, 2.1, 2.2, 1.1, 1.2, 1.3}, + []uint32{0, 0, 0, 0, 0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps13[0]: {cps13[0]}, + cps23[0]: {cps23[0]}, + cps23[1]: {cps23[1]}, + cps23[2]: {cps23[2]}, + cps23[3]: {cps23[3]}, + cps33[0]: {cps33[0]}, + cps33[1]: {cps33[1]}, + cps33[2]: {cps33[2]}, + }, + vistaAndNewer: true, + }, + }, + }, + } require.NoError(t, err) err = m.ParseConfig() require.NoError(t, err) - require.Len(t, m.counters, 4) - err = m.query.Close() + require.Len(t, m.hostCounters, 3) + + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 8) + require.True(t, counters.tag == hostname()) + require.True(t, counters.counters[0].computer == "localhost") + require.True(t, counters.counters[0].objectName == "O") + require.True(t, counters.counters[0].instance == "I") + require.True(t, counters.counters[0].counter == "C") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[1].computer == "localhost") + require.True(t, counters.counters[1].objectName == "O1") + require.True(t, counters.counters[1].instance == "I1") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "localhost") + require.True(t, counters.counters[2].objectName == "O1") + require.True(t, counters.counters[2].instance == "I2") + require.True(t, counters.counters[2].counter == "C1") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "localhost") + require.True(t, counters.counters[3].objectName == "O1") + require.True(t, counters.counters[3].instance == "I1") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + require.True(t, counters.counters[4].computer == "localhost") + require.True(t, counters.counters[4].objectName == "O1") + require.True(t, counters.counters[4].instance == "I2") + require.True(t, counters.counters[4].counter == "C2") + require.True(t, counters.counters[4].measurement == "m") + require.True(t, !counters.counters[4].includeTotal) + require.True(t, counters.counters[5].computer == "localhost") + require.True(t, counters.counters[5].objectName == "O2") + require.True(t, counters.counters[5].instance == "I") + require.True(t, counters.counters[5].counter == "C1") + require.True(t, counters.counters[5].measurement == "m") + require.True(t, !counters.counters[5].includeTotal) + require.True(t, counters.counters[6].computer == "localhost") + require.True(t, counters.counters[6].objectName == "O2") + require.True(t, counters.counters[6].instance == "I") + require.True(t, counters.counters[6].counter == "C2") + require.True(t, counters.counters[6].measurement == "m") + require.True(t, !counters.counters[6].includeTotal) + require.True(t, counters.counters[7].computer == "localhost") + require.True(t, counters.counters[7].objectName == "O2") + require.True(t, counters.counters[7].instance == "I") + require.True(t, counters.counters[7].counter == "C3") + require.True(t, counters.counters[7].measurement == "m") + require.True(t, !counters.counters[7].includeTotal) + + counters, ok = m.hostCounters["cmp1"] + require.True(t, ok) + require.Len(t, counters.counters, 8) + require.True(t, counters.tag == "cmp1") + require.True(t, counters.counters[0].computer == "cmp1") + require.True(t, counters.counters[0].objectName == "O") + require.True(t, counters.counters[0].instance == "I") + require.True(t, counters.counters[0].counter == "C") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[1].computer == "cmp1") + require.True(t, counters.counters[1].objectName == "O1") + require.True(t, counters.counters[1].instance == "I1") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "cmp1") + require.True(t, counters.counters[2].objectName == "O1") + require.True(t, counters.counters[2].instance == "I2") + require.True(t, counters.counters[2].counter == "C1") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "cmp1") + require.True(t, counters.counters[3].objectName == "O1") + require.True(t, counters.counters[3].instance == "I1") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + require.True(t, counters.counters[4].computer == "cmp1") + require.True(t, counters.counters[4].objectName == "O1") + require.True(t, counters.counters[4].instance == "I2") + require.True(t, counters.counters[4].counter == "C2") + require.True(t, counters.counters[4].measurement == "m") + require.True(t, !counters.counters[4].includeTotal) + require.True(t, counters.counters[5].computer == "cmp1") + require.True(t, counters.counters[5].objectName == "O2") + require.True(t, counters.counters[5].instance == "I") + require.True(t, counters.counters[5].counter == "C1") + require.True(t, counters.counters[5].measurement == "m") + require.True(t, !counters.counters[5].includeTotal) + require.True(t, counters.counters[6].computer == "cmp1") + require.True(t, counters.counters[6].objectName == "O2") + require.True(t, counters.counters[6].instance == "I") + require.True(t, counters.counters[6].counter == "C2") + require.True(t, counters.counters[6].measurement == "m") + require.True(t, !counters.counters[6].includeTotal) + require.True(t, counters.counters[7].computer == "cmp1") + require.True(t, counters.counters[7].objectName == "O2") + require.True(t, counters.counters[7].instance == "I") + require.True(t, counters.counters[7].counter == "C3") + require.True(t, counters.counters[7].measurement == "m") + require.True(t, !counters.counters[7].includeTotal) + + counters, ok = m.hostCounters["cmp2"] + require.True(t, ok) + require.Len(t, counters.counters, 8) + require.True(t, counters.tag == "cmp2") + require.True(t, counters.counters[0].computer == "cmp2") + require.True(t, counters.counters[0].objectName == "O") + require.True(t, counters.counters[0].instance == "I") + require.True(t, counters.counters[0].counter == "C") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[1].computer == "cmp2") + require.True(t, counters.counters[1].objectName == "O1") + require.True(t, counters.counters[1].instance == "I1") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "cmp2") + require.True(t, counters.counters[2].objectName == "O1") + require.True(t, counters.counters[2].instance == "I2") + require.True(t, counters.counters[2].counter == "C1") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "cmp2") + require.True(t, counters.counters[3].objectName == "O1") + require.True(t, counters.counters[3].instance == "I1") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + require.True(t, counters.counters[4].computer == "cmp2") + require.True(t, counters.counters[4].objectName == "O1") + require.True(t, counters.counters[4].instance == "I2") + require.True(t, counters.counters[4].counter == "C2") + require.True(t, counters.counters[4].measurement == "m") + require.True(t, !counters.counters[4].includeTotal) + require.True(t, counters.counters[5].computer == "cmp2") + require.True(t, counters.counters[5].objectName == "O2") + require.True(t, counters.counters[5].instance == "I") + require.True(t, counters.counters[5].counter == "C1") + require.True(t, counters.counters[5].measurement == "m") + require.True(t, !counters.counters[5].includeTotal) + require.True(t, counters.counters[6].computer == "cmp2") + require.True(t, counters.counters[6].objectName == "O2") + require.True(t, counters.counters[6].instance == "I") + require.True(t, counters.counters[6].counter == "C2") + require.True(t, counters.counters[6].measurement == "m") + require.True(t, !counters.counters[6].includeTotal) + require.True(t, counters.counters[7].computer == "cmp2") + require.True(t, counters.counters[7].objectName == "O2") + require.True(t, counters.counters[7].instance == "I") + require.True(t, counters.counters[7].counter == "C3") + require.True(t, counters.counters[7].measurement == "m") + require.True(t, !counters.counters[7].includeTotal) + +} + +func TestParseConfigMultiCompsOverrideMultiplePerfObjects(t *testing.T) { + var err error + perfObjects := []perfobject{ + createPerfObject("localhost", "m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)[0], + createPerfObject("cmp1", "m", "O1", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)[0], + createPerfObject("cmp2", "m", "O2", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)[0], + } + cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"} + cps2 := []string{"\\\\cmp1\\O1(I1)\\C1", "\\\\cmp1\\O1(I1)\\C2", "\\\\cmp1\\O1(I2)\\C1", "\\\\cmp1\\O1(I2)\\C2"} + cps3 := []string{"\\\\cmp2\\O2(I1)\\C1", "\\\\cmp2\\O2(I1)\\C2", "\\\\cmp2\\O2(I2)\\C1", "\\\\cmp2\\O2(I2)\\C2"} + m := WinPerfCounters{ + Log: testutil.Logger{}, + PrintValid: false, + Object: perfObjects, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, + []float64{1.1, 1.2, 1.3, 1.4}, + []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + cps1[1]: {cps1[1]}, + cps1[2]: {cps1[2]}, + cps1[3]: {cps1[3]}, + }, + vistaAndNewer: true, + }, + "cmp1": { + counters: createCounterMap(cps2, + []float64{2.1, 2.2, 2.3, 2.4}, + []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps2[0]: {cps2[0]}, + cps2[1]: {cps2[1]}, + cps2[2]: {cps2[2]}, + cps2[3]: {cps2[3]}, + }, + vistaAndNewer: true, + }, + "cmp2": { + counters: createCounterMap(cps3, + []float64{3.1, 3.2, 3.3, 3.4}, + []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps3[0]: {cps3[0]}, + cps3[1]: {cps3[1]}, + cps3[2]: {cps3[2]}, + cps3[3]: {cps3[3]}, + }, + vistaAndNewer: true, + }, + }, + }, + } require.NoError(t, err) + err = m.ParseConfig() + require.NoError(t, err) + require.Len(t, m.hostCounters, 3) + + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + require.True(t, counters.counters[0].computer == "localhost") + require.True(t, counters.counters[0].objectName == "O") + require.True(t, counters.counters[0].instance == "I1") + require.True(t, counters.counters[0].counter == "C1") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[1].computer == "localhost") + require.True(t, counters.counters[1].objectName == "O") + require.True(t, counters.counters[1].instance == "I2") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "localhost") + require.True(t, counters.counters[2].objectName == "O") + require.True(t, counters.counters[2].instance == "I1") + require.True(t, counters.counters[2].counter == "C2") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "localhost") + require.True(t, counters.counters[3].objectName == "O") + require.True(t, counters.counters[3].instance == "I2") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + + counters, ok = m.hostCounters["cmp1"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + require.True(t, counters.counters[0].computer == "cmp1") + require.True(t, counters.counters[0].objectName == "O1") + require.True(t, counters.counters[0].instance == "I1") + require.True(t, counters.counters[0].counter == "C1") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[1].computer == "cmp1") + require.True(t, counters.counters[1].objectName == "O1") + require.True(t, counters.counters[1].instance == "I2") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "cmp1") + require.True(t, counters.counters[2].objectName == "O1") + require.True(t, counters.counters[2].instance == "I1") + require.True(t, counters.counters[2].counter == "C2") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "cmp1") + require.True(t, counters.counters[3].objectName == "O1") + require.True(t, counters.counters[3].instance == "I2") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + + counters, ok = m.hostCounters["cmp2"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + require.True(t, counters.counters[0].computer == "cmp2") + require.True(t, counters.counters[0].objectName == "O2") + require.True(t, counters.counters[0].instance == "I1") + require.True(t, counters.counters[0].counter == "C1") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[1].computer == "cmp2") + require.True(t, counters.counters[1].objectName == "O2") + require.True(t, counters.counters[1].instance == "I2") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "cmp2") + require.True(t, counters.counters[2].objectName == "O2") + require.True(t, counters.counters[2].instance == "I1") + require.True(t, counters.counters[2].counter == "C2") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "cmp2") + require.True(t, counters.counters[3].objectName == "O2") + require.True(t, counters.counters[3].instance == "I2") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + +} + +func TestParseConfigMultiCompsOverrideOnePerfObject(t *testing.T) { + var err error + + PerfObject := perfobject{ + Sources: []string{"cmp1", "cmp2"}, + ObjectName: "O", + Instances: []string{"I1", "I2"}, + Counters: []string{"C1", "C2"}, + Measurement: "m", + WarnOnMissing: false, + FailOnMissing: false, + IncludeTotal: false, + } + cps11 := []string{"\\\\cmp1\\O(I1)\\C1", "\\\\cmp1\\O(I1)\\C2", "\\\\cmp1\\O(I2)\\C1", "\\\\cmp1\\O(I2)\\C2"} + cps12 := []string{"\\\\cmp2\\O(I1)\\C1", "\\\\cmp2\\O(I1)\\C2", "\\\\cmp2\\O(I2)\\C1", "\\\\cmp2\\O(I2)\\C2"} + cps21 := []string{"\\O1(I)\\C"} + cps22 := []string{"\\\\cmp1\\O1(I)\\C"} + m := WinPerfCounters{ + Sources: []string{"localhost", "cmp1"}, + Log: testutil.Logger{}, + PrintValid: false, + Object: []perfobject{PerfObject, createPerfObject("", "m", "O1", []string{"I"}, []string{"C"}, false, false, false)[0]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{ + "localhost": { + counters: createCounterMap(cps21, + []float64{1.1}, + []uint32{0}), + expandPaths: map[string][]string{ + cps21[0]: {cps21[0]}, + }, + vistaAndNewer: true, + }, + "cmp1": { + counters: createCounterMap(append(cps11, cps22...), + []float64{2.1, 2.1, 2.2, 2.3, 2.4}, + []uint32{0, 0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps11[0]: {cps11[0]}, + cps11[1]: {cps11[1]}, + cps11[2]: {cps11[2]}, + cps11[3]: {cps11[3]}, + cps22[0]: {cps22[0]}, + }, + vistaAndNewer: true, + }, + "cmp2": { + counters: createCounterMap(cps12, + []float64{3.1, 3.2, 3.3, 3.4}, + []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps12[0]: {cps12[0]}, + cps12[1]: {cps12[1]}, + cps12[2]: {cps12[2]}, + cps12[3]: {cps12[3]}, + }, + vistaAndNewer: true, + }, + }, + }, + } + require.NoError(t, err) + err = m.ParseConfig() + require.NoError(t, err) + require.Len(t, m.hostCounters, 3) + + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 1) + require.True(t, counters.tag == hostname()) + require.True(t, counters.counters[0].computer == "localhost") + require.True(t, counters.counters[0].objectName == "O1") + require.True(t, counters.counters[0].instance == "I") + require.True(t, counters.counters[0].counter == "C") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + + counters, ok = m.hostCounters["cmp1"] + require.True(t, ok) + require.Len(t, counters.counters, 5) + require.True(t, counters.tag == "cmp1") + require.True(t, counters.counters[0].computer == "cmp1") + require.True(t, counters.counters[0].objectName == "O") + require.True(t, counters.counters[0].instance == "I1") + require.True(t, counters.counters[0].counter == "C1") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[0].computer == "cmp1") + require.True(t, counters.counters[1].objectName == "O") + require.True(t, counters.counters[1].instance == "I2") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "cmp1") + require.True(t, counters.counters[2].objectName == "O") + require.True(t, counters.counters[2].instance == "I1") + require.True(t, counters.counters[2].counter == "C2") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "cmp1") + require.True(t, counters.counters[3].objectName == "O") + require.True(t, counters.counters[3].instance == "I2") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + require.True(t, counters.counters[4].computer == "cmp1") + require.True(t, counters.counters[4].objectName == "O1") + require.True(t, counters.counters[4].instance == "I") + require.True(t, counters.counters[4].counter == "C") + require.True(t, counters.counters[4].measurement == "m") + require.True(t, !counters.counters[4].includeTotal) + + counters, ok = m.hostCounters["cmp2"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + require.True(t, counters.tag == "cmp2") + require.True(t, counters.counters[0].computer == "cmp2") + require.True(t, counters.counters[0].objectName == "O") + require.True(t, counters.counters[0].instance == "I1") + require.True(t, counters.counters[0].counter == "C1") + require.True(t, counters.counters[0].measurement == "m") + require.True(t, !counters.counters[0].includeTotal) + require.True(t, counters.counters[1].computer == "cmp2") + require.True(t, counters.counters[1].objectName == "O") + require.True(t, counters.counters[1].instance == "I2") + require.True(t, counters.counters[1].counter == "C1") + require.True(t, counters.counters[1].measurement == "m") + require.True(t, !counters.counters[1].includeTotal) + require.True(t, counters.counters[2].computer == "cmp2") + require.True(t, counters.counters[2].objectName == "O") + require.True(t, counters.counters[2].instance == "I1") + require.True(t, counters.counters[2].counter == "C2") + require.True(t, counters.counters[2].measurement == "m") + require.True(t, !counters.counters[2].includeTotal) + require.True(t, counters.counters[3].computer == "cmp2") + require.True(t, counters.counters[3].objectName == "O") + require.True(t, counters.counters[3].instance == "I2") + require.True(t, counters.counters[3].counter == "C2") + require.True(t, counters.counters[3].measurement == "m") + require.True(t, !counters.counters[3].includeTotal) + +} + +func TestParseConfigLocalhost(t *testing.T) { + + var err error + perfObjects := createPerfObject("localhost", "m", "O", []string{"------"}, []string{"C"}, false, false, false) + cps1 := []string{"\\O\\C"} + m := WinPerfCounters{ + Log: testutil.Logger{}, + PrintValid: false, + Object: perfObjects, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + }, + vistaAndNewer: true, + }, + }, + }, + } + + err = m.ParseConfig() + require.NoError(t, err) + + hostCounters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, hostCounters.counters, 1) + require.Equal(t, "localhost", hostCounters.counters[0].computer) + require.Equal(t, "localhost", hostCounters.computer, hostCounters.computer) + require.Equal(t, hostname(), hostCounters.tag) + + err = m.cleanQueries() + require.NoError(t, err) + + m.Object[0].Sources = []string{""} + + err = m.ParseConfig() + require.NoError(t, err) + + hostCounters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, hostCounters.counters, 1) + require.Equal(t, "localhost", hostCounters.counters[0].computer) + require.Equal(t, "localhost", hostCounters.computer, hostCounters.computer) + require.Equal(t, hostname(), hostCounters.tag) } func TestParseConfigNoInstance(t *testing.T) { var err error - perfObjects := createPerfObject("m", "O", []string{"------"}, []string{"C1", "C2"}, false, false, false) + perfObjects := createPerfObject("", "m", "O", []string{"------"}, []string{"C1", "C2"}, false, false, false) cps1 := []string{"\\O\\C1", "\\O\\C2"} - m := Win_PerfCounters{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, UseWildcardsExpansion: false, - query: &FakePerformanceQuery{ - counters: createCounterMap(cps1, []float64{1.1, 1.2}, []uint32{0, 0}), - expandPaths: map[string][]string{ - cps1[0]: {cps1[0]}, - cps1[1]: {cps1[1]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.1, 1.2}, []uint32{0, 0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + cps1[1]: {cps1[1]}, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() - require.NoError(t, err) + }, + }, + } + err = m.ParseConfig() require.NoError(t, err) - require.Len(t, m.counters, 2) - err = m.query.Close() - require.NoError(t, err) + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) m.UseWildcardsExpansion = true - m.counters = nil - - err = m.query.Open() + err = m.cleanQueries() require.NoError(t, err) + err = m.ParseConfig() require.NoError(t, err) - require.Len(t, m.counters, 2) - err = m.query.Close() - require.NoError(t, err) + counters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) } func TestParseConfigInvalidCounterError(t *testing.T) { var err error - perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, true, false, 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{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}, []uint32{0, 0, 0}), - expandPaths: map[string][]string{ - cps1[0]: {cps1[0]}, - cps1[1]: {cps1[1]}, - cps1[2]: {cps1[2]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}, []uint32{0, 0, 0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + cps1[1]: {cps1[1]}, + cps1[2]: {cps1[2]}, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() - require.NoError(t, err) + }, + }, + } + err = m.ParseConfig() require.Error(t, err) - err = m.query.Close() - require.NoError(t, err) + err = m.cleanQueries() + require.NoError(t, err) m.UseWildcardsExpansion = true - m.counters = nil - err = m.query.Open() - require.NoError(t, err) err = m.ParseConfig() require.Error(t, err) - err = m.query.Close() + err = m.cleanQueries() require.NoError(t, err) } func TestParseConfigInvalidCounterNoError(t *testing.T) { var err error - perfObjects := createPerfObject("m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, 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{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}, []uint32{0, 0, 0}), - expandPaths: map[string][]string{ - cps1[0]: {cps1[0]}, - cps1[1]: {cps1[1]}, - cps1[2]: {cps1[2]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}, []uint32{0, 0, 0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + cps1[1]: {cps1[1]}, + cps1[2]: {cps1[2]}, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() - require.NoError(t, err) + }, + }, + } + err = m.ParseConfig() require.NoError(t, err) - err = m.query.Close() + err = m.cleanQueries() require.NoError(t, err) m.UseWildcardsExpansion = true - m.counters = nil - err = m.query.Open() - require.NoError(t, err) err = m.ParseConfig() require.NoError(t, err) - err = m.query.Close() + err = m.cleanQueries() require.NoError(t, err) - } func TestParseConfigTotalExpansion(t *testing.T) { var err error - perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, true, true, false) + 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{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, UseWildcardsExpansion: true, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}), - expandPaths: map[string][]string{ - "\\O(*)\\*": cps1, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}), + expandPaths: map[string][]string{ + "\\O(*)\\*": cps1, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() - require.NoError(t, err) + }, + }, + LocalizeWildcardsExpansion: true, + } err = m.ParseConfig() require.NoError(t, err) - require.Len(t, m.counters, 4) - err = m.query.Close() + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + err = m.cleanQueries() require.NoError(t, err) perfObjects[0].IncludeTotal = false - m = Win_PerfCounters{ + m = WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, UseWildcardsExpansion: true, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}), - expandPaths: map[string][]string{ - "\\O(*)\\*": cps1, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}), + expandPaths: map[string][]string{ + "\\O(*)\\*": cps1, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() - require.NoError(t, err) + }, + }, + LocalizeWildcardsExpansion: true, + } + err = m.ParseConfig() require.NoError(t, err) - require.Len(t, m.counters, 2) - err = m.query.Close() + counters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) + err = m.cleanQueries() require.NoError(t, err) } func TestParseConfigExpand(t *testing.T) { var err error - perfObjects := createPerfObject("m", "O", []string{"*"}, []string{"*"}, false, 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{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, UseWildcardsExpansion: true, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}), - expandPaths: map[string][]string{ - "\\O(*)\\*": cps1, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}), + expandPaths: map[string][]string{ + "\\O(*)\\*": cps1, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} - err = m.query.Open() - require.NoError(t, err) + }, + }, + LocalizeWildcardsExpansion: true, + } err = m.ParseConfig() require.NoError(t, err) - require.Len(t, m.counters, 4) - err = m.query.Close() + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + err = m.cleanQueries() require.NoError(t, err) } @@ -565,19 +1203,23 @@ 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, false) + perfObjects := createPerfObject("", measurement, "O", []string{"I"}, []string{"C"}, false, false, false) cp1 := "\\O(I)\\C" - m := Win_PerfCounters{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{0}), - expandPaths: map[string][]string{ - cp1: {cp1}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{0}), + expandPaths: map[string][]string{ + cp1: {cp1}, + }, + vistaAndNewer: false, }, - vistaAndNewer: false, - }} + }, + }, + } var acc1 testutil.Accumulator err = m.Gather(&acc1) require.NoError(t, err) @@ -588,11 +1230,13 @@ func TestSimpleGather(t *testing.T) { tags1 := map[string]string{ "instance": "I", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) m.UseWildcardsExpansion = true - m.counters = nil + err = m.cleanQueries() + require.NoError(t, err) m.lastRefreshed = time.Time{} var acc2 testutil.Accumulator @@ -600,6 +1244,8 @@ func TestSimpleGather(t *testing.T) { err = m.Gather(&acc2) require.NoError(t, err) acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) + err = m.cleanQueries() + require.NoError(t, err) } func TestSimpleGatherNoData(t *testing.T) { @@ -608,19 +1254,23 @@ 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, false) + perfObjects := createPerfObject("", measurement, "O", []string{"I"}, []string{"C"}, false, false, false) cp1 := "\\O(I)\\C" - m := Win_PerfCounters{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{PDH_NO_DATA}), - expandPaths: map[string][]string{ - cp1: {cp1}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{PDH_NO_DATA}), + expandPaths: map[string][]string{ + cp1: {cp1}, + }, + vistaAndNewer: false, }, - vistaAndNewer: false, - }} + }, + }, + } var acc1 testutil.Accumulator err = m.Gather(&acc1) // this "PDH_NO_DATA" error should not be returned to caller, but checked, and handled @@ -638,7 +1288,8 @@ func TestSimpleGatherNoData(t *testing.T) { acc1.AssertDoesNotContainsTaggedFields(t, measurement, fields1, tags1) m.UseWildcardsExpansion = true - m.counters = nil + err = m.cleanQueries() + require.NoError(t, err) m.lastRefreshed = time.Time{} var acc2 testutil.Accumulator @@ -646,6 +1297,8 @@ func TestSimpleGatherNoData(t *testing.T) { err = m.Gather(&acc2) require.NoError(t, err) acc1.AssertDoesNotContainsTaggedFields(t, measurement, fields1, tags1) + err = m.cleanQueries() + require.NoError(t, err) } func TestSimpleGatherWithTimestamp(t *testing.T) { @@ -654,20 +1307,25 @@ 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, false) + perfObjects := createPerfObject("", measurement, "O", []string{"I"}, []string{"C"}, false, false, false) cp1 := "\\O(I)\\C" - m := Win_PerfCounters{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, UsePerfCounterTime: true, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{0}), - expandPaths: map[string][]string{ - cp1: {cp1}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{0}), + expandPaths: map[string][]string{ + cp1: {cp1}, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} + }, + }, + } + var acc1 testutil.Accumulator err = m.Gather(&acc1) require.NoError(t, err) @@ -678,45 +1336,61 @@ func TestSimpleGatherWithTimestamp(t *testing.T) { tags1 := map[string]string{ "instance": "I", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) require.True(t, acc1.HasTimestamp(measurement, MetricTime)) + err = m.cleanQueries() + require.NoError(t, err) } func TestGatherError(t *testing.T) { + if testing.Short() { + t.Skip("Skipping long taking test in short mode") + } var err error - expectedError := "error while getting value for counter \\O(I)\\C: The information passed is not valid.\r\n" + expectedError := "error during collecting data on host 'localhost': 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, false) + perfObjects := createPerfObject("", measurement, "O", []string{"I"}, []string{"C"}, false, false, false) cp1 := "\\O(I)\\C" - m := Win_PerfCounters{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap([]string{cp1}, []float64{-2}, []uint32{PDH_PLA_VALIDATION_WARNING}), - expandPaths: map[string][]string{ - cp1: {cp1}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap([]string{cp1}, []float64{-2}, []uint32{PDH_PLA_VALIDATION_WARNING}), + expandPaths: map[string][]string{ + cp1: {cp1}, + }, + vistaAndNewer: false, }, - vistaAndNewer: false, - }} + }, + }, + } var acc1 testutil.Accumulator err = m.Gather(&acc1) - require.Error(t, err) - require.Equal(t, expectedError, err.Error()) + require.NoError(t, err) + require.Len(t, acc1.Errors, 1) + require.Equal(t, expectedError, acc1.Errors[0].Error()) m.UseWildcardsExpansion = true - m.counters = nil + err = m.cleanQueries() + require.NoError(t, err) m.lastRefreshed = time.Time{} var acc2 testutil.Accumulator err = m.Gather(&acc2) - require.Error(t, err) - require.Equal(t, expectedError, err.Error()) + require.NoError(t, err) + require.Len(t, acc2.Errors, 1) + require.Equal(t, expectedError, acc2.Errors[0].Error()) + + err = m.cleanQueries() + require.NoError(t, err) } func TestGatherInvalidDataIgnore(t *testing.T) { @@ -725,21 +1399,25 @@ 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, 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{ + m := WinPerfCounters{ Log: testutil.Logger{}, PrintValid: false, Object: perfObjects, - query: &FakePerformanceQuery{ - counters: createCounterMap(cps1, []float64{1.2, 1, 0}, []uint32{0, PDH_INVALID_DATA, 0}), - expandPaths: map[string][]string{ - cps1[0]: {cps1[0]}, - cps1[1]: {cps1[1]}, - cps1[2]: {cps1[2]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, []float64{1.2, 1, 0}, []uint32{0, PDH_INVALID_DATA, 0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + cps1[1]: {cps1[1]}, + cps1[2]: {cps1[2]}, + }, + vistaAndNewer: false, }, - vistaAndNewer: false, - }} + }, + }, + } var acc1 testutil.Accumulator err = m.Gather(&acc1) require.NoError(t, err) @@ -751,17 +1429,21 @@ func TestGatherInvalidDataIgnore(t *testing.T) { tags1 := map[string]string{ "instance": "I", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) m.UseWildcardsExpansion = true - m.counters = nil + err = m.cleanQueries() + require.NoError(t, err) m.lastRefreshed = time.Time{} var acc2 testutil.Accumulator err = m.Gather(&acc2) require.NoError(t, err) acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) + err = m.cleanQueries() + require.NoError(t, err) } // tests with expansion @@ -771,7 +1453,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, 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}), @@ -780,19 +1462,25 @@ func TestGatherRefreshingWithExpansion(t *testing.T) { }, vistaAndNewer: true, } - m := Win_PerfCounters{ - Log: testutil.Logger{}, - PrintValid: false, - Object: perfObjects, - UseWildcardsExpansion: true, - query: fpm, + m := WinPerfCounters{ + Log: testutil.Logger{}, + PrintValid: false, + Object: perfObjects, + UseWildcardsExpansion: true, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm}, + }, CountersRefreshInterval: config.Duration(time.Second * 10), LocalizeWildcardsExpansion: true, } var acc1 testutil.Accumulator err = m.Gather(&acc1) - require.Len(t, m.counters, 4) require.NoError(t, err) + + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) + require.Len(t, acc1.Metrics, 2) fields1 := map[string]interface{}{ @@ -802,6 +1490,7 @@ func TestGatherRefreshingWithExpansion(t *testing.T) { tags1 := map[string]string{ "instance": "I1", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) @@ -812,8 +1501,10 @@ func TestGatherRefreshingWithExpansion(t *testing.T) { tags2 := map[string]string{ "instance": "I2", "objectname": "O", + "source": hostname(), } 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}, []uint32{0, 0, 0, 0, 0, 0, 0}), @@ -822,8 +1513,10 @@ func TestGatherRefreshingWithExpansion(t *testing.T) { }, vistaAndNewer: true, } - m.query = fpm - _ = fpm.Open() + + m.queryCreator = &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm}, + } var acc2 testutil.Accumulator fields3 := map[string]interface{}{ @@ -833,12 +1526,15 @@ func TestGatherRefreshingWithExpansion(t *testing.T) { tags3 := map[string]string{ "instance": "I3", "objectname": "O", + "source": hostname(), } //test before elapsing CounterRefreshRate counters are not refreshed err = m.Gather(&acc2) require.NoError(t, err) - require.Len(t, m.counters, 4) + counters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) require.Len(t, acc2.Metrics, 2) acc2.AssertContainsTaggedFields(t, measurement, fields1, tags1) @@ -855,6 +1551,8 @@ func TestGatherRefreshingWithExpansion(t *testing.T) { acc3.AssertContainsTaggedFields(t, measurement, fields2, tags2) acc3.AssertContainsTaggedFields(t, measurement, fields3, tags3) + err = m.cleanQueries() + require.NoError(t, err) } @@ -864,7 +1562,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, 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}), @@ -874,16 +1572,20 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { }, vistaAndNewer: true, } - m := Win_PerfCounters{ - Log: testutil.Logger{}, - PrintValid: false, - Object: perfObjects, - UseWildcardsExpansion: false, - query: fpm, + m := WinPerfCounters{ + Log: testutil.Logger{}, + PrintValid: false, + Object: perfObjects, + UseWildcardsExpansion: false, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm}, + }, CountersRefreshInterval: config.Duration(time.Second * 10)} var acc1 testutil.Accumulator err = m.Gather(&acc1) - require.Len(t, m.counters, 2) + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) require.NoError(t, err) require.Len(t, acc1.Metrics, 2) @@ -894,6 +1596,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { tags1 := map[string]string{ "instance": "I1", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) @@ -904,6 +1607,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { tags2 := map[string]string{ "instance": "I2", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields2, tags2) //test finding new instance @@ -920,8 +1624,14 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { }, vistaAndNewer: true, } - m.query = fpm - _ = fpm.Open() + + err = m.cleanQueries() + require.NoError(t, err) + m.lastRefreshed = time.Time{} + m.queryCreator = &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm}, + } + var acc2 testutil.Accumulator fields3 := map[string]interface{}{ @@ -931,19 +1641,23 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { tags3 := map[string]string{ "instance": "I3", "objectname": "O", + "source": hostname(), } //test before elapsing CounterRefreshRate counters are not refreshed + err = m.Gather(&acc2) require.NoError(t, err) - require.Len(t, m.counters, 2) + counters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) require.Len(t, acc2.Metrics, 3) acc2.AssertContainsTaggedFields(t, measurement, fields1, tags1) 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, 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( @@ -958,11 +1672,14 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { }, vistaAndNewer: true, } - m.query = fpm + err = m.cleanQueries() + m.lastRefreshed = time.Time{} + require.NoError(t, err) + m.queryCreator = &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm}, + } m.Object = perfObjects - _ = fpm.Open() - time.Sleep(time.Duration(m.CountersRefreshInterval)) var acc3 testutil.Accumulator @@ -977,6 +1694,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { tags4 := map[string]string{ "instance": "I1", "objectname": "O", + "source": hostname(), } fields5 := map[string]interface{}{ "C1": 1.4, @@ -986,11 +1704,13 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) { tags5 := map[string]string{ "instance": "I2", "objectname": "O", + "source": hostname(), } acc3.AssertContainsTaggedFields(t, measurement, fields4, tags4) acc3.AssertContainsTaggedFields(t, measurement, fields5, tags5) - + err = m.cleanQueries() + require.NoError(t, err) } func TestGatherTotalNoExpansion(t *testing.T) { @@ -999,25 +1719,31 @@ func TestGatherTotalNoExpansion(t *testing.T) { } var err error measurement := "m" - perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, true, false) + 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{ + m := WinPerfCounters{ 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, 1.2, 1.3, 1.4}, []uint32{0, 0, 0, 0, 0, 0}), - expandPaths: map[string][]string{ - "\\O(*)\\C1": {cps1[0], cps1[2]}, - "\\O(*)\\C2": {cps1[1], cps1[3]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + 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}), + expandPaths: map[string][]string{ + "\\O(*)\\C1": {cps1[0], cps1[2]}, + "\\O(*)\\C2": {cps1[1], cps1[3]}, + }, + vistaAndNewer: true, }, - vistaAndNewer: true, - }} + }, + }, + } var acc1 testutil.Accumulator err = m.Gather(&acc1) require.NoError(t, err) - require.Len(t, m.counters, 2) + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) require.Len(t, acc1.Metrics, 2) fields1 := map[string]interface{}{ "C1": 1.1, @@ -1026,6 +1752,7 @@ func TestGatherTotalNoExpansion(t *testing.T) { tags1 := map[string]string{ "instance": "I1", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) @@ -1036,23 +1763,149 @@ func TestGatherTotalNoExpansion(t *testing.T) { tags2 := map[string]string{ "instance": "_Total", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields2, tags2) perfObjects[0].IncludeTotal = false - m.counters = nil + err = m.cleanQueries() + require.NoError(t, err) + m.UseWildcardsExpansion = true m.lastRefreshed = time.Time{} var acc2 testutil.Accumulator err = m.Gather(&acc2) require.NoError(t, err) - require.Len(t, m.counters, 2) + counters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) require.Len(t, acc2.Metrics, 1) acc2.AssertContainsTaggedFields(t, measurement, fields1, tags1) - acc2.AssertDoesNotContainsTaggedFields(t, measurement, fields2, tags2) + err = m.cleanQueries() + require.NoError(t, err) +} + +func TestGatherMultiComps(t *testing.T) { + var err error + perfObjects := []perfobject{ + createPerfObject("", "m", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)[0], + createPerfObject("cmp1", "m1", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)[0], + createPerfObject("cmp2", "m2", "O", []string{"I1", "I2"}, []string{"C1", "C2"}, false, false, false)[0], + } + cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"} + cps2 := []string{"\\\\cmp1\\O(I1)\\C1", "\\\\cmp1\\O(I1)\\C2", "\\\\cmp1\\O(I2)\\C1", "\\\\cmp1\\O(I2)\\C2"} + cps3 := []string{"\\\\cmp2\\O(I1)\\C1", "\\\\cmp2\\O(I1)\\C2", "\\\\cmp2\\O(I2)\\C1", "\\\\cmp2\\O(I2)\\C2"} + m := WinPerfCounters{ + Log: testutil.Logger{}, + PrintValid: false, + Object: perfObjects, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + counters: createCounterMap(cps1, + []float64{1.1, 1.2, 1.3, 1.4}, + []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps1[0]: {cps1[0]}, + cps1[1]: {cps1[1]}, + cps1[2]: {cps1[2]}, + cps1[3]: {cps1[3]}, + }, + vistaAndNewer: true, + }, + "cmp1": { + counters: createCounterMap(cps2, + []float64{2.1, 2.2, 2.3, 2.4}, + []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps2[0]: {cps2[0]}, + cps2[1]: {cps2[1]}, + cps2[2]: {cps2[2]}, + cps2[3]: {cps2[3]}, + }, + vistaAndNewer: true, + }, + "cmp2": { + counters: createCounterMap(cps3, + []float64{3.1, 3.2, 3.3, 3.4}, + []uint32{0, 0, 0, 0}), + expandPaths: map[string][]string{ + cps3[0]: {cps3[0]}, + cps3[1]: {cps3[1]}, + cps3[2]: {cps3[2]}, + cps3[3]: {cps3[3]}, + }, + vistaAndNewer: true, + }, + }, + }, + } + var acc testutil.Accumulator + err = m.Gather(&acc) + require.NoError(t, err) + require.Len(t, acc.Metrics, 6) + fields1 := map[string]interface{}{ + "C1": 1.1, + "C2": 1.2, + } + tags1 := map[string]string{ + "instance": "I1", + "objectname": "O", + "source": hostname(), + } + fields2 := map[string]interface{}{ + "C1": 1.3, + "C2": 1.4, + } + tags2 := map[string]string{ + "instance": "I2", + "objectname": "O", + "source": hostname(), + } + acc.AssertContainsTaggedFields(t, "m", fields1, tags1) + acc.AssertContainsTaggedFields(t, "m", fields2, tags2) + fields3 := map[string]interface{}{ + "C1": 2.1, + "C2": 2.2, + } + tags3 := map[string]string{ + "instance": "I1", + "objectname": "O", + "source": "cmp1", + } + fields4 := map[string]interface{}{ + "C1": 2.3, + "C2": 2.4, + } + tags4 := map[string]string{ + "instance": "I2", + "objectname": "O", + "source": "cmp1", + } + acc.AssertContainsTaggedFields(t, "m1", fields3, tags3) + acc.AssertContainsTaggedFields(t, "m1", fields4, tags4) + fields5 := map[string]interface{}{ + "C1": 3.1, + "C2": 3.2, + } + tags5 := map[string]string{ + "instance": "I1", + "objectname": "O", + "source": "cmp2", + } + fields6 := map[string]interface{}{ + "C1": 3.3, + "C2": 3.4, + } + tags6 := map[string]string{ + "instance": "I2", + "objectname": "O", + "source": "cmp2", + } + acc.AssertContainsTaggedFields(t, "m2", fields5, tags5) + acc.AssertContainsTaggedFields(t, "m2", fields6, tags6) } func TestGatherRaw(t *testing.T) { @@ -1061,25 +1914,31 @@ func TestGatherRaw(t *testing.T) { } var err error measurement := "m" - perfObjects := createPerfObject(measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, true, true) + 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{ + m := WinPerfCounters{ 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]}, + queryCreator: &FakePerformanceQueryCreator{ + fakeQueries: map[string]*FakePerformanceQuery{"localhost": { + 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, }, - vistaAndNewer: true, - }} + }, + }, + } var acc1 testutil.Accumulator err = m.Gather(&acc1) require.NoError(t, err) - require.Len(t, m.counters, 2) + counters, ok := m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 2) require.Len(t, acc1.Metrics, 2) fields1 := map[string]interface{}{ "C1_Raw": int64(1), @@ -1088,6 +1947,7 @@ func TestGatherRaw(t *testing.T) { tags1 := map[string]string{ "instance": "I1", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1) @@ -1098,21 +1958,25 @@ func TestGatherRaw(t *testing.T) { tags2 := map[string]string{ "instance": "_Total", "objectname": "O", + "source": hostname(), } acc1.AssertContainsTaggedFields(t, measurement, fields2, tags2) m.UseWildcardsExpansion = true - m.counters = nil + err = m.cleanQueries() + require.NoError(t, err) m.lastRefreshed = time.Time{} var acc2 testutil.Accumulator err = m.Gather(&acc2) require.NoError(t, err) - require.Len(t, m.counters, 4) //expanded counters + + counters, ok = m.hostCounters["localhost"] + require.True(t, ok) + require.Len(t, counters.counters, 4) //expanded counters require.Len(t, acc2.Metrics, 2) acc2.AssertContainsTaggedFields(t, measurement, fields1, tags1) - acc2.AssertContainsTaggedFields(t, measurement, fields2, tags2) } @@ -1160,15 +2024,15 @@ func TestUTF16ToStringArray(t *testing.T) { } func TestNoWildcards(t *testing.T) { - m := Win_PerfCounters{ - Object: createPerfObject("measurement", "object", []string{"instance"}, []string{"counter*"}, false, false, false), + m := WinPerfCounters{ + 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, false), + m = WinPerfCounters{ + Object: createPerfObject("", "measurement", "object?", []string{"instance"}, []string{"counter"}, false, false, false), UseWildcardsExpansion: true, LocalizeWildcardsExpansion: false, Log: testutil.Logger{}, @@ -1183,15 +2047,16 @@ func TestLocalizeWildcardsExpansion(t *testing.T) { } const counter = "% Processor Time" - m := Win_PerfCounters{ - query: &PerformanceQueryImpl{}, + m := WinPerfCounters{ + queryCreator: &PerformanceQueryCreatorImpl{}, CountersRefreshInterval: config.Duration(time.Second * 60), - Object: createPerfObject("measurement", "Processor Information", - []string{"_Total"}, []string{counter}, false, false, false), + Object: createPerfObject("", "measurement", "Processor Information", + []string{"_Total"}, []string{counter}, true, false, false), LocalizeWildcardsExpansion: false, UseWildcardsExpansion: true, Log: testutil.Logger{}, } + require.NoError(t, m.Init()) var acc testutil.Accumulator require.NoError(t, m.Gather(&acc)) @@ -1233,7 +2098,7 @@ func TestCheckError(t *testing.T) { for _, tc := range tests { t.Run(tc.Name, func(t *testing.T) { - m := Win_PerfCounters{ + m := WinPerfCounters{ IgnoredErrors: tc.IgnoredErrors, }