Skip to content

Commit

Permalink
Use gopsutil to search by process full pattern on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
danielnelson committed Jun 5, 2020
1 parent f037d3d commit aa0d0c9
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 85 deletions.
26 changes: 26 additions & 0 deletions plugins/inputs/procstat/native_finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"strconv"
"strings"
"regexp"

"github.com/shirou/gopsutil/process"
)
Expand Down Expand Up @@ -55,3 +56,28 @@ func (pg *NativeFinder) PidFile(path string) ([]PID, error) {
return pids, nil

}

//FullPattern matches on the command line when the process was executed
func (pg *NativeFinder) FullPattern(pattern string) ([]PID, error) {
var pids []PID
regxPattern, err := regexp.Compile(pattern)
if err != nil {
return pids, err
}
procs, err := process.Processes()
if err != nil {
return pids, err
}
for _, p := range procs {
cmd, err := p.Cmdline()
if err != nil {
//skip, this can be caused by the pid no longer existing
//or you having no permissions to access it
continue
}
if regxPattern.MatchString(cmd) {
pids = append(pids, PID(p.Pid))
}
}
return pids, err
}
25 changes: 0 additions & 25 deletions plugins/inputs/procstat/native_finder_notwindows.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,3 @@ func (pg *NativeFinder) Pattern(pattern string) ([]PID, error) {
}
return pids, err
}

//FullPattern matches on the command line when the process was executed
func (pg *NativeFinder) FullPattern(pattern string) ([]PID, error) {
var pids []PID
regxPattern, err := regexp.Compile(pattern)
if err != nil {
return pids, err
}
procs, err := process.Processes()
if err != nil {
return pids, err
}
for _, p := range procs {
cmd, err := p.Cmdline()
if err != nil {
//skip, this can be caused by the pid no longer existing
//or you having no permissions to access it
continue
}
if regxPattern.MatchString(cmd) {
pids = append(pids, PID(p.Pid))
}
}
return pids, err
}
29 changes: 29 additions & 0 deletions plugins/inputs/procstat/native_finder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package procstat

import (
"testing"

"github.com/stretchr/testify/require"
)

func BenchmarkPattern(b *testing.B) {
f, err := NewNativeFinder()
require.NoError(b, err)
for n := 0; n < b.N; n++ {
_, err := f.Pattern(".*")
if err != nil {
panic(err)
}
}
}

func BenchmarkFullPattern(b *testing.B) {
f, err := NewNativeFinder()
require.NoError(b, err)
for n := 0; n < b.N; n++ {
_, err := f.FullPattern(".*")
if err != nil {
panic(err)
}
}
}
61 changes: 1 addition & 60 deletions plugins/inputs/procstat/native_finder_windows.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
package procstat

import (
"context"
"fmt"
"regexp"
"time"

"github.com/StackExchange/wmi"
"github.com/shirou/gopsutil/process"
)

//Timeout is the timeout used when making wmi calls
var Timeout = 5 * time.Second

type queryType string

const (
like = queryType("LIKE")
equals = queryType("=")
notEqual = queryType("!=")
)

//Pattern matches on the process name
// Pattern matches on the process name
func (pg *NativeFinder) Pattern(pattern string) ([]PID, error) {
var pids []PID
regxPattern, err := regexp.Compile(pattern)
Expand All @@ -45,47 +30,3 @@ func (pg *NativeFinder) Pattern(pattern string) ([]PID, error) {
}
return pids, err
}

//FullPattern matches the cmdLine on windows and will find a pattern using a WMI like query
func (pg *NativeFinder) FullPattern(pattern string) ([]PID, error) {
var pids []PID
procs, err := getWin32ProcsByVariable("CommandLine", like, pattern, Timeout)
if err != nil {
return pids, err
}
for _, p := range procs {
pids = append(pids, PID(p.ProcessID))
}
return pids, nil
}

//GetWin32ProcsByVariable allows you to query any variable with a like query
func getWin32ProcsByVariable(variable string, qType queryType, value string, timeout time.Duration) ([]process.Win32_Process, error) {
var dst []process.Win32_Process
var query string
// should look like "WHERE CommandLine LIKE "procstat"
query = fmt.Sprintf("WHERE %s %s %q", variable, qType, value)
q := wmi.CreateQuery(&dst, query)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
err := WMIQueryWithContext(ctx, q, &dst)
if err != nil {
return []process.Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
}
return dst, nil
}

// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
errChan := make(chan error, 1)
go func() {
errChan <- wmi.Query(query, dst, connectServerArgs...)
}()

select {
case <-ctx.Done():
return ctx.Err()
case err := <-errChan:
return err
}
}

0 comments on commit aa0d0c9

Please sign in to comment.