From 90b4a1e4358fc82af4aec10b795f49690e223179 Mon Sep 17 00:00:00 2001 From: Vlasta Hajek Date: Sun, 2 Sep 2018 03:59:03 +0200 Subject: [PATCH] Fix instance and object name in performance counters with backslashes (#4572) --- .../win_perf_counters/win_perf_counters.go | 66 +++++++++++++------ .../win_perf_counters_test.go | 46 ++++++++++++- 2 files changed, 92 insertions(+), 20 deletions(-) diff --git a/plugins/inputs/win_perf_counters/win_perf_counters.go b/plugins/inputs/win_perf_counters/win_perf_counters.go index d2ace5231..06a1a333c 100644 --- a/plugins/inputs/win_perf_counters/win_perf_counters.go +++ b/plugins/inputs/win_perf_counters/win_perf_counters.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "log" - "regexp" "strings" "time" @@ -119,28 +118,57 @@ type instanceGrouping struct { var sanitizedChars = strings.NewReplacer("/sec", "_persec", "/Sec", "_persec", " ", "_", "%", "Percent", `\`, "") -//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 +// 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) { -var counterPathRE = regexp.MustCompile(`.*\\(.*)\\(.*)`) -var objectInstanceRE = regexp.MustCompile(`(.*)\((.*)\)`) + rightObjectBorderIndex := -1 + leftObjectBorderIndex := -1 + leftCounterBorderIndex := -1 + rightInstanceBorderIndex := -1 + leftInstanceBorderIndex := -1 + bracketLevel := 0 -//extractObjectInstanceCounterFromQuery gets object name, instance name (if available) and counter name from counter path -func extractObjectInstanceCounterFromQuery(query string) (object string, instance string, counter string, err error) { - pathParts := counterPathRE.FindAllStringSubmatch(query, -1) - if pathParts == nil || len(pathParts[0]) != 3 { - err = errors.New("Could not extract counter info from: " + query) + for i := len(counterPath) - 1; i >= 0; i-- { + switch counterPath[i] { + case '\\': + if bracketLevel == 0 { + if leftCounterBorderIndex == -1 { + leftCounterBorderIndex = i + } else if leftObjectBorderIndex == -1 { + leftObjectBorderIndex = i + } + } + case '(': + bracketLevel-- + if leftInstanceBorderIndex == -1 && bracketLevel == 0 && leftObjectBorderIndex == -1 && leftCounterBorderIndex > -1 { + leftInstanceBorderIndex = i + rightObjectBorderIndex = i + } + case ')': + if rightInstanceBorderIndex == -1 && bracketLevel == 0 && leftCounterBorderIndex > -1 { + rightInstanceBorderIndex = i + } + bracketLevel++ + } + } + if rightObjectBorderIndex == -1 { + rightObjectBorderIndex = leftCounterBorderIndex + } + if rightObjectBorderIndex == -1 || leftObjectBorderIndex == -1 { + err = errors.New("cannot parse object from: " + counterPath) return } - counter = pathParts[0][2] - //try to get instance name - objectInstanceParts := objectInstanceRE.FindAllStringSubmatch(pathParts[0][1], -1) - if objectInstanceParts == nil || len(objectInstanceParts[0]) != 3 { - object = pathParts[0][1] - } else { - object = objectInstanceParts[0][1] - instance = objectInstanceParts[0][2] + + 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 } + object = counterPath[leftObjectBorderIndex+1 : rightObjectBorderIndex] + counter = counterPath[leftCounterBorderIndex+1:] return } @@ -184,7 +212,7 @@ func (m *Win_PerfCounters) AddItem(counterPath string, objectName string, instan var err error counterHandle, err := m.query.AddCounterToQuery(counterPath) - objectName, instance, counterName, err = extractObjectInstanceCounterFromQuery(counterPath) + objectName, instance, counterName, err = extractCounterInfoFromCounterPath(counterPath) if err != nil { return 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 07e1941a9..81959ef8c 100644 --- a/plugins/inputs/win_perf_counters/win_perf_counters_test.go +++ b/plugins/inputs/win_perf_counters/win_perf_counters_test.go @@ -28,7 +28,7 @@ type FakePerformanceQuery struct { var MetricTime = time.Date(2018, 5, 28, 12, 0, 0, 0, time.UTC) func (m *testCounter) ToCounterValue() *CounterValue { - _, inst, _, _ := extractObjectInstanceCounterFromQuery(m.path) + _, inst, _, _ := extractCounterInfoFromCounterPath(m.path) if inst == "" { inst = "--" } @@ -211,6 +211,50 @@ func createCounterMap(counterPaths []string, values []float64) map[string]testCo return counters } +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"}, +} + +var invalidCounterPaths = []string{ + "\\O(I\\C", + "\\OI)\\C", + "\\O(I\\C", + "\\O/C", + "\\O(I/C", + "\\O(I/C)", + "\\O(I\\)C", + "\\O(I\\C)", +} + +func TestCounterPathParsing(t *testing.T) { + for path, vals := range counterPathsAndRes { + o, i, c, err := extractCounterInfoFromCounterPath(path) + require.NoError(t, err) + require.True(t, assert.ObjectsAreEqual(vals, []string{o, i, c}), "arrays: %#v and %#v are not equal", vals, []string{o, i, c}) + } + for _, path := range invalidCounterPaths { + _, _, _, err := extractCounterInfoFromCounterPath(path) + require.Error(t, err) + } +} + func TestAddItemSimple(t *testing.T) { var err error cps1 := []string{"\\O(I)\\C"}