Add new measurement with results of pgrep lookup to procstat input (#4307)

This commit is contained in:
maxunt 2018-06-19 11:47:13 -07:00 committed by Daniel Nelson
parent 8b678b9041
commit 86e4cd0083
4 changed files with 53 additions and 8 deletions

View File

@ -11,6 +11,7 @@ import (
"os/exec"
"strconv"
"strings"
"syscall"
"time"
"unicode"
)
@ -193,3 +194,15 @@ func RandomSleep(max time.Duration, shutdown chan struct{}) {
return
}
}
// Exit status takes the error from exec.Command
// and returns the exit status and true
// if error is not exit status, will return 0 and false
func ExitStatus(err error) (int, bool) {
if exiterr, ok := err.(*exec.ExitError); ok {
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
return status.ExitStatus(), true
}
}
return 0, false
}

View File

@ -6,6 +6,8 @@ import (
"os/exec"
"strconv"
"strings"
"github.com/influxdata/telegraf/internal"
)
// Implemention of PIDGatherer that execs pgrep to find processes
@ -62,6 +64,12 @@ func find(path string, args []string) ([]PID, error) {
func run(path string, args []string) (string, error) {
out, err := exec.Command(path, args...).Output()
//if exit code 1, ie no processes found, do not return error
if i, _ := internal.ExitStatus(err); i == 1 {
return "", nil
}
if err != nil {
return "", fmt.Errorf("Error running %s: %s", path, err)
}

View File

@ -97,7 +97,7 @@ func (p *Procstat) Gather(acc telegraf.Accumulator) error {
p.createProcess = defaultProcess
}
procs, err := p.updateProcesses(p.procs)
procs, err := p.updateProcesses(acc, p.procs)
if err != nil {
acc.AddError(fmt.Errorf("E! Error: procstat getting process, exe: [%s] pidfile: [%s] pattern: [%s] user: [%s] %s",
p.Exe, p.PidFile, p.Pattern, p.User, err.Error()))
@ -230,8 +230,8 @@ func (p *Procstat) addMetrics(proc Process, acc telegraf.Accumulator) {
}
// Update monitored Processes
func (p *Procstat) updateProcesses(prevInfo map[PID]Process) (map[PID]Process, error) {
pids, tags, err := p.findPids()
func (p *Procstat) updateProcesses(acc telegraf.Accumulator, prevInfo map[PID]Process) (map[PID]Process, error) {
pids, tags, err := p.findPids(acc)
if err != nil {
return nil, err
}
@ -281,9 +281,9 @@ func (p *Procstat) getPIDFinder() (PIDFinder, error) {
}
// Get matching PIDs and their initial tags
func (p *Procstat) findPids() ([]PID, map[string]string, error) {
func (p *Procstat) findPids(acc telegraf.Accumulator) ([]PID, map[string]string, error) {
var pids []PID
var tags map[string]string
tags := make(map[string]string)
var err error
f, err := p.getPIDFinder()
@ -313,7 +313,18 @@ func (p *Procstat) findPids() ([]PID, map[string]string, error) {
err = fmt.Errorf("Either exe, pid_file, user, pattern, systemd_unit, or cgroup must be specified")
}
return pids, tags, err
rTags := make(map[string]string)
for k, v := range tags {
rTags[k] = v
}
//adds a metric with info on the pgrep query
fields := make(map[string]interface{})
tags["pid_finder"] = p.PidFinder
fields["pid_count"] = len(pids)
acc.AddFields("procstat_lookup", fields, tags)
return pids, rTags, err
}
// execCommand is so tests can mock out exec.Command usage.

View File

@ -343,7 +343,8 @@ func TestGather_systemdUnitPIDs(t *testing.T) {
createPIDFinder: pidFinder([]PID{}, nil),
SystemdUnit: "TestGather_systemdUnitPIDs",
}
pids, tags, err := p.findPids()
var acc testutil.Accumulator
pids, tags, err := p.findPids(&acc)
require.NoError(t, err)
assert.Equal(t, []PID{11408}, pids)
assert.Equal(t, "TestGather_systemdUnitPIDs", tags["systemd_unit"])
@ -364,8 +365,20 @@ func TestGather_cgroupPIDs(t *testing.T) {
createPIDFinder: pidFinder([]PID{}, nil),
CGroup: td,
}
pids, tags, err := p.findPids()
var acc testutil.Accumulator
pids, tags, err := p.findPids(&acc)
require.NoError(t, err)
assert.Equal(t, []PID{1234, 5678}, pids)
assert.Equal(t, td, tags["cgroup"])
}
func TestProcstatLookupMetric(t *testing.T) {
p := Procstat{
createPIDFinder: pidFinder([]PID{543}, nil),
Exe: "-Gsys",
}
var acc testutil.Accumulator
err := acc.GatherError(p.Gather)
require.NoError(t, err)
require.Equal(t, len(p.procs)+1, len(acc.Metrics))
}