forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add native Go method for finding pids to procstat (influxdata#3559)
- Loading branch information
1 parent
12d62e6
commit a7571d5
Showing
10 changed files
with
301 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
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) { | ||
var dst []PID | ||
procs, err := process.Processes() | ||
if err != nil { | ||
return dst, err | ||
} | ||
for _, p := range procs { | ||
username, err := p.Username() | ||
if err != nil { | ||
//skip, this can happen if we don't have permissions or | ||
//the pid no longer exists | ||
continue | ||
} | ||
if username == user { | ||
dst = append(dst, PID(p.Pid)) | ||
} | ||
} | ||
return dst, 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 | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) { | ||
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 %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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.