Skip to content
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

Refactor procstat input #2540

Merged
merged 1 commit into from
Mar 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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