Skip to content

Commit

Permalink
Refactor procstat input (#2540)
Browse files Browse the repository at this point in the history
fixes #1636 
fixes #2315
  • Loading branch information
danielnelson authored Mar 17, 2017
1 parent 8514acd commit a962e95
Show file tree
Hide file tree
Showing 6 changed files with 594 additions and 273 deletions.
91 changes: 91 additions & 0 deletions plugins/inputs/procstat/pgrep.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package procstat

import (
"fmt"
"io/ioutil"
"os/exec"
"strconv"
"strings"
)

type PIDFinder interface {
PidFile(path string) ([]PID, error)
Pattern(pattern string) ([]PID, error)
Uid(user string) ([]PID, error)
FullPattern(path string) ([]PID, error)
}

// Implemention of PIDGatherer that execs pgrep to find processes
type Pgrep struct {
path string
}

func NewPgrep() (PIDFinder, error) {
path, err := exec.LookPath("pgrep")
if err != nil {
return nil, fmt.Errorf("Could not find pgrep binary: %s", err)
}
return &Pgrep{path}, nil
}

func (pg *Pgrep) 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
}

func (pg *Pgrep) Pattern(pattern string) ([]PID, error) {
args := []string{pattern}
return find(pg.path, args)
}

func (pg *Pgrep) Uid(user string) ([]PID, error) {
args := []string{"-u", user}
return find(pg.path, args)
}

func (pg *Pgrep) FullPattern(pattern string) ([]PID, error) {
args := []string{"-f", pattern}
return find(pg.path, args)
}

func find(path string, args []string) ([]PID, error) {
out, err := run(path, args)
if err != nil {
return nil, err
}

return parseOutput(out)
}

func run(path string, args []string) (string, error) {
out, err := exec.Command(path, args...).Output()
if err != nil {
return "", fmt.Errorf("Error running %s: %s", path, err)
}
return string(out), err
}

func parseOutput(out string) ([]PID, error) {
pids := []PID{}
fields := strings.Fields(out)
for _, field := range fields {
pid, err := strconv.Atoi(field)
if err != nil {
return nil, err
}
if err == nil {
pids = append(pids, PID(pid))
}
}
return pids, nil
}
60 changes: 60 additions & 0 deletions plugins/inputs/procstat/process.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package procstat

import (
"fmt"
"time"

"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/process"
)

type Process interface {
PID() PID
Tags() map[string]string

IOCounters() (*process.IOCountersStat, error)
MemoryInfo() (*process.MemoryInfoStat, error)
Name() (string, error)
NumCtxSwitches() (*process.NumCtxSwitchesStat, error)
NumFDs() (int32, error)
NumThreads() (int32, error)
Percent(interval time.Duration) (float64, error)
Times() (*cpu.TimesStat, error)
}

type Proc struct {
hasCPUTimes bool
tags map[string]string
*process.Process
}

func NewProc(pid PID) (Process, error) {
process, err := process.NewProcess(int32(pid))
if err != nil {
return nil, err
}

proc := &Proc{
Process: process,
hasCPUTimes: false,
tags: make(map[string]string),
}
return proc, nil
}

func (p *Proc) Tags() map[string]string {
return p.tags
}

func (p *Proc) PID() PID {
return PID(p.Process.Pid)
}

func (p *Proc) Percent(interval time.Duration) (float64, error) {
cpu_perc, err := p.Process.Percent(time.Duration(0))
if !p.hasCPUTimes && err == nil {
p.hasCPUTimes = true
return 0, fmt.Errorf("Must call Percent twice to compute percent cpu.")
}
return cpu_perc, err
}
Loading

0 comments on commit a962e95

Please sign in to comment.