-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
procstats patterns without pgrep #3559
Changes from 28 commits
9d4c282
a54fd8d
c47eaef
a2f429b
4b26b52
8b66be9
54ffbd2
62285d9
0722c4a
aff075b
e402310
d85d89b
56a0296
452f496
e1e32ef
93fc937
e2f374c
37c6416
e97d339
ed23fe3
8f008d3
aab50e7
78d4544
50fd95a
690ef25
0ecb670
f115e18
797ec89
fc0f21c
5a4c56e
80c07ae
20470f8
d75e3db
529fd53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package procstat | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/shirou/gopsutil/process" | ||
) | ||
|
||
//NativeFinder uses gopsutil to find processes | ||
type NativeFinder struct { | ||
} | ||
|
||
//NewNativeFinder ... | ||
func NewNativeFinder() (PIDFinder, error) { | ||
return &NativeFinder{}, nil | ||
} | ||
|
||
//Uid will return all pids for the given user | ||
func (pg *NativeFinder) Uid(user string) ([]PID, error) { | ||
pids, err := getPidsByUser(user) | ||
if err != nil { | ||
return pids, err | ||
} | ||
return pids, nil | ||
} | ||
|
||
//PidFile returns the pid from the pid file given. | ||
func (pg *NativeFinder) PidFile(path string) ([]PID, error) { | ||
var pids []PID | ||
pidString, err := ioutil.ReadFile(path) | ||
if err != nil { | ||
return pids, fmt.Errorf("Failed to read pidfile '%s'. Error: '%s'", | ||
path, err) | ||
} | ||
pid, err := strconv.Atoi(strings.TrimSpace(string(pidString))) | ||
if err != nil { | ||
return pids, err | ||
} | ||
pids = append(pids, PID(pid)) | ||
return pids, nil | ||
|
||
} | ||
|
||
//getPidsByUser ... | ||
func getPidsByUser(username string) ([]PID, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just merge this into |
||
var dst []PID | ||
procs, err := process.Processes() | ||
if err != nil { | ||
return dst, err | ||
} | ||
for _, p := range procs { | ||
user, err := p.Username() | ||
if err != nil { | ||
//skip, this can happen if we don't have permissions or | ||
//the pid no longer exists | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs |
||
continue | ||
} | ||
if user == username { | ||
dst = append(dst, PID(p.Pid)) | ||
} | ||
} | ||
return dst, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// +build !windows | ||
|
||
package procstat | ||
|
||
import ( | ||
"regexp" | ||
|
||
"github.com/shirou/gopsutil/process" | ||
) | ||
|
||
//Pattern matches on the process name | ||
func (pg *NativeFinder) Pattern(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 { | ||
name, err := p.Exe() | ||
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(name) { | ||
pids = append(pids, PID(p.Pid)) | ||
} | ||
} | ||
return pids, err | ||
} | ||
|
||
//FullPattern matches on the command line when the proccess 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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
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 | ||
func (pg *NativeFinder) Pattern(pattern string) ([]PID, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this looks the same as the notwindows version, lets put shared implementation in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed |
||
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 { | ||
name, err := p.Name() | ||
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(name) { | ||
pids = append(pids, PID(p.Pid)) | ||
} | ||
} | ||
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 '%s'", variable, qType, value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use %q here to get quoting with escaping of 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 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package procstat | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"os/user" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGather_RealPattern(t *testing.T) { | ||
pg, err := NewNativeFinder() | ||
require.NoError(t, err) | ||
pids, err := pg.Pattern(`procstat`) | ||
require.NoError(t, err) | ||
fmt.Println(pids) | ||
assert.Equal(t, len(pids) > 0, true) | ||
} | ||
|
||
func TestGather_RealFullPattern(t *testing.T) { | ||
pg, err := NewNativeFinder() | ||
require.NoError(t, err) | ||
pids, err := pg.FullPattern(`%procstat%`) | ||
require.NoError(t, err) | ||
fmt.Println(pids) | ||
assert.Equal(t, len(pids) > 0, true) | ||
} | ||
|
||
func TestGather_RealUser(t *testing.T) { | ||
user, err := user.Current() | ||
require.NoError(t, err) | ||
pg, err := NewNativeFinder() | ||
require.NoError(t, err) | ||
pids, err := pg.Uid(user.Username) | ||
require.NoError(t, err) | ||
fmt.Println(pids) | ||
assert.Equal(t, len(pids) > 0, true) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will have to remember to take a second pass at this documentation, so that it matches the current design