Skip to content

Commit

Permalink
Perfmon - Fix regular expressions to comply to multiple parentheses i…
Browse files Browse the repository at this point in the history
…n instance name and object (#22146) (#22232)

* mofidy doc

* work on instance

* changelog

* fix tests

(cherry picked from commit 36775b2)
  • Loading branch information
narph authored Oct 29, 2020
1 parent 3f35a6c commit 55b720a
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ field. You can revert this change by configuring tags for the module and omittin
- Fix retrieving resources by ID for the azure module. {pull}21711[21711] {issue}21707[21707]
- Use timestamp from CloudWatch API when creating events. {pull}21498[21498]
- Report the correct windows events for system/filesystem {pull}21758[21758]
- Fix regular expression in windows/permfon. {pull}22146[22146] {issue}21125[21125]
- Fix azure storage event format. {pull}21845[21845]
- Fix panic in kubernetes autodiscover related to keystores {issue}21843[21843] {pull}21880[21880]
- [Kubernetes] Remove redundant dockersock volume mount {pull}22009[22009]
Expand Down
44 changes: 38 additions & 6 deletions metricbeat/helper/windows/pdh/pdh_query_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
)

var (
instanceNameRegexp = regexp.MustCompile(`.*?\((.*?)\).*`)
instanceNameRegexp = regexp.MustCompile(`(\(.+\))\\`)
objectNameRegexp = regexp.MustCompile(`(?:^\\\\[^\\]+\\|^\\)([^\\]+)`)
)

Expand Down Expand Up @@ -86,7 +86,7 @@ func (q *Query) AddCounter(counterPath string, instance string, format string, w
var instanceName string
// Extract the instance name from the counterPath.
if instance == "" || wildcard {
instanceName, err = MatchInstanceName(counterPath)
instanceName, err = matchInstanceName(counterPath)
if err != nil {
return err
}
Expand Down Expand Up @@ -233,18 +233,50 @@ func (q *Query) Close() error {
return PdhCloseQuery(q.Handle)
}

// MatchInstanceName will check first for instance and then for any objects names.
func MatchInstanceName(counterPath string) (string, error) {
// matchInstanceName will check first for instance and then for any objects names.
func matchInstanceName(counterPath string) (string, error) {
matches := instanceNameRegexp.FindStringSubmatch(counterPath)
if len(matches) != 2 {
matches = objectNameRegexp.FindStringSubmatch(counterPath)
if len(matches) == 2 {
return returnLastInstance(matches[1]), nil
}
matches = objectNameRegexp.FindStringSubmatch(counterPath)
if len(matches) == 2 {
return matches[1], nil
}
return "", errors.New("query doesn't contain an instance name. In this case you have to define 'instance_name'")
}

// returnLastInstance will return the content from the last parentheses, this covers cases as `\WF (System.Workflow) 4.0.0.0(*)\Workflows Created`.
func returnLastInstance(match string) string {
var openedParanth int
var innerMatch string
var matches []string
runeMatch := []rune(match)
for i := 0; i < len(runeMatch); i++ {
char := string(runeMatch[i])

// check if string ends between parentheses
if char == ")" {
openedParanth -= 1
}
if openedParanth > 0 {
innerMatch += char
}
if openedParanth == 0 && innerMatch != "" {
matches = append(matches, innerMatch)
innerMatch = ""
}
// check if string starts between parentheses
if char == "(" {
openedParanth += 1
}
}
if len(matches) > 0 {
return matches[len(matches)-1]
}
return match
}

// getCounterValue will retrieve the counter value based on the format applied in the config options
func getCounterValue(counter *Counter) CounterValue {
counterValue := CounterValue{Instance: counter.instanceName, Err: CounterValueError{CStatus: 0}}
Expand Down
66 changes: 65 additions & 1 deletion metricbeat/helper/windows/pdh/pdh_query_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,56 @@ func TestSuccessfulQuery(t *testing.T) {
assert.NotNil(t, list)
}

func TestMatchInstanceName(t *testing.T) {
query := "\\SQLServer:Databases(*)\\Log File(s) Used Size (KB)"
match, err := matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "*")

query = " \\\\desktop-rfooe09\\per processor network interface card activity(3, microsoft wi-fi directvirtual (gyfyg) adapter #2)\\dpcs queued/sec"
match, err = matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "3, microsoft wi-fi directvirtual (gyfyg) adapter #2")

query = " \\\\desktop-rfooe09\\ (test this scenario) per processor network interface card activity(3, microsoft wi-fi directvirtual (gyfyg) adapter #2)\\dpcs queued/sec"
match, err = matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "3, microsoft wi-fi directvirtual (gyfyg) adapter #2")

query = "\\RAS\\Bytes Received By Disconnected Clients"
match, err = matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "RAS")

query = `\\Process (chrome.exe#4)\\Bytes Received By Disconnected Clients`
match, err = matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "chrome.exe#4")

query = "\\BranchCache\\Local Cache: Cache complete file segments"
match, err = matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "BranchCache")

query = `\Synchronization(*)\Exec. Resource no-Waits AcqShrdStarveExcl/sec`
match, err = matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "*")

query = `\.NET CLR Exceptions(test hellp (dsdsd) #rfsfs #3)\# of Finallys / sec`
match, err = matchInstanceName(query)
assert.NoError(t, err)
assert.Equal(t, match, "test hellp (dsdsd) #rfsfs #3")
}

// TestInstanceNameRegexp tests regular expression for instance.
func TestInstanceNameRegexp(t *testing.T) {
queryPaths := []string{`\SQLServer:Databases(*)\Log File(s) Used Size (KB)`, `\Search Indexer(*)\L0 Indexes (Wordlists)`,
`\Search Indexer(*)\L0 Merges (flushes) Now.`, `\NUMA Node Memory(*)\Free & Zero Page List MBytes`}
for _, path := range queryPaths {
matches := instanceNameRegexp.FindStringSubmatch(path)
if assert.Len(t, matches, 2, "regular expression did not return any matches") {
assert.Equal(t, matches[1], "*")
assert.Equal(t, matches[1], "(*)")
}
}
}
Expand All @@ -114,6 +156,28 @@ func TestObjectNameRegexp(t *testing.T) {
}
}

func TestReturnLastInstance(t *testing.T) {
query := "(*)"
match := returnLastInstance(query)
assert.Equal(t, match, "*")

query = "(3, microsoft wi-fi directvirtual (gyfyg) adapter #2)"
match = returnLastInstance(query)
assert.Equal(t, match, "3, microsoft wi-fi directvirtual (gyfyg) adapter #2")

query = "(test this scenario) per processor network interface card activity(3, microsoft wi-fi directvirtual (gyfyg) adapter #2)"
match = returnLastInstance(query)
assert.Equal(t, match, "3, microsoft wi-fi directvirtual (gyfyg) adapter #2")

query = `(chrome.exe#4)`
match = returnLastInstance(query)
assert.Equal(t, match, "chrome.exe#4")

query = `(test hellp (dsdsd) #rfsfs #3)`
match = returnLastInstance(query)
assert.Equal(t, match, "test hellp (dsdsd) #rfsfs #3")
}

func TestUTF16ToStringArray(t *testing.T) {
var array = []string{
"\\\\DESKTOP-RFOOE09\\Physikalischer Datenträger(0 C:)\\Schreibvorgänge/s",
Expand Down
4 changes: 2 additions & 2 deletions metricbeat/module/windows/perfmon/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
"github.com/elastic/beats/v7/metricbeat/mb"
)

var processRegexp = regexp.MustCompile(`(.+?)#[1-9]+`)
var processRegexp = regexp.MustCompile(`(.+?[^\s])(?:#\d+|$)`)

func (re *Reader) groupToEvents(counters map[string][]pdh.CounterValue) []mb.Event {
eventMap := make(map[string]*mb.Event)
Expand Down Expand Up @@ -73,7 +73,7 @@ func (re *Reader) groupToEvents(counters map[string][]pdh.CounterValue) []mb.Eve
Error: errors.Wrapf(val.Err.Error, "failed on query=%v", counterPath),
}
if val.Instance != "" {
//will ignore instance counter
//will ignore instance index
if ok, match := matchesParentProcess(val.Instance); ok {
eventMap[eventKey].MetricSetFields.Put(counter.InstanceField, match)
} else {
Expand Down
6 changes: 5 additions & 1 deletion metricbeat/module/windows/perfmon/data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,13 @@ func TestGroupToSingleEvent(t *testing.T) {

func TestMatchesParentProcess(t *testing.T) {
ok, val := matchesParentProcess("svchost")
assert.False(t, ok)
assert.True(t, ok)
assert.Equal(t, val, "svchost")
ok, val = matchesParentProcess("svchost#54")
assert.True(t, ok)
assert.Equal(t, val, "svchost")

ok, val = matchesParentProcess("svchost (test) another #54")
assert.True(t, ok)
assert.Equal(t, val, "svchost (test) another #54")
}

0 comments on commit 55b720a

Please sign in to comment.