148 lines
3.3 KiB
Go
148 lines
3.3 KiB
Go
package procstat
|
|
|
|
import (
|
|
"time"
|
|
"regexp"
|
|
"strconv"
|
|
|
|
"github.com/shirou/gopsutil/process"
|
|
|
|
"github.com/influxdata/telegraf"
|
|
)
|
|
|
|
type SpecProcessor struct {
|
|
Prefix string
|
|
tags map[string]string
|
|
fields map[string]interface{}
|
|
acc telegraf.Accumulator
|
|
proc *process.Process
|
|
}
|
|
|
|
func NewSpecProcessor(
|
|
processName string,
|
|
prefix string,
|
|
cmdlineRegex string,
|
|
parentCmdlineRegex string,
|
|
acc telegraf.Accumulator,
|
|
p *process.Process,
|
|
tags map[string]string,
|
|
) *SpecProcessor {
|
|
if processName != "" {
|
|
tags["process_name"] = processName
|
|
} else {
|
|
name, err := p.Name()
|
|
if err == nil {
|
|
tags["process_name"] = name
|
|
}
|
|
}
|
|
|
|
if cmdlineRegex != "" {
|
|
val := CmdlineSubstrings(p, &cmdlineRegex)
|
|
for i, value := range val {
|
|
tags["cmdline." + strconv.Itoa(i)] = value
|
|
}
|
|
}
|
|
|
|
ppid, err := p.Ppid()
|
|
if err == nil {
|
|
tags["ppid"] = strconv.Itoa(int(ppid))
|
|
|
|
pp, err := process.NewProcess(ppid)
|
|
if err == nil {
|
|
parentName, err := pp.Name()
|
|
if err == nil {
|
|
tags["parent_name"] = parentName
|
|
}
|
|
if parentCmdlineRegex != "" {
|
|
val := CmdlineSubstrings(pp, &parentCmdlineRegex)
|
|
for i, value := range val {
|
|
tags["pcmdline." + strconv.Itoa(i)] = value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return &SpecProcessor{
|
|
Prefix: prefix,
|
|
tags: tags,
|
|
fields: make(map[string]interface{}),
|
|
acc: acc,
|
|
proc: p,
|
|
}
|
|
}
|
|
|
|
func CmdlineSubstrings(p *process.Process, regex *string) []string {
|
|
cmdline, err := p.Cmdline()
|
|
if err == nil {
|
|
re, err := regexp.Compile(*regex)
|
|
if err == nil {
|
|
cmdlineSubmatch := re.FindStringSubmatch(cmdline)
|
|
if cmdlineSubmatch != nil {
|
|
return cmdlineSubmatch[1:]
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *SpecProcessor) pushMetrics() {
|
|
var prefix string
|
|
if p.Prefix != "" {
|
|
prefix = p.Prefix + "_"
|
|
}
|
|
fields := map[string]interface{}{}
|
|
|
|
numThreads, err := p.proc.NumThreads()
|
|
if err == nil {
|
|
fields[prefix+"num_threads"] = numThreads
|
|
}
|
|
|
|
fds, err := p.proc.NumFDs()
|
|
if err == nil {
|
|
fields[prefix+"num_fds"] = fds
|
|
}
|
|
|
|
ctx, err := p.proc.NumCtxSwitches()
|
|
if err == nil {
|
|
fields[prefix+"voluntary_context_switches"] = ctx.Voluntary
|
|
fields[prefix+"involuntary_context_switches"] = ctx.Involuntary
|
|
}
|
|
|
|
io, err := p.proc.IOCounters()
|
|
if err == nil {
|
|
fields[prefix+"read_count"] = io.ReadCount
|
|
fields[prefix+"write_count"] = io.WriteCount
|
|
fields[prefix+"read_bytes"] = io.ReadBytes
|
|
fields[prefix+"write_bytes"] = io.WriteCount
|
|
}
|
|
|
|
cpu_time, err := p.proc.Times()
|
|
if err == nil {
|
|
fields[prefix+"cpu_time_user"] = cpu_time.User
|
|
fields[prefix+"cpu_time_system"] = cpu_time.System
|
|
fields[prefix+"cpu_time_idle"] = cpu_time.Idle
|
|
fields[prefix+"cpu_time_nice"] = cpu_time.Nice
|
|
fields[prefix+"cpu_time_iowait"] = cpu_time.Iowait
|
|
fields[prefix+"cpu_time_irq"] = cpu_time.Irq
|
|
fields[prefix+"cpu_time_soft_irq"] = cpu_time.Softirq
|
|
fields[prefix+"cpu_time_steal"] = cpu_time.Steal
|
|
fields[prefix+"cpu_time_stolen"] = cpu_time.Stolen
|
|
fields[prefix+"cpu_time_guest"] = cpu_time.Guest
|
|
fields[prefix+"cpu_time_guest_nice"] = cpu_time.GuestNice
|
|
}
|
|
|
|
cpu_perc, err := p.proc.Percent(time.Duration(0))
|
|
if err == nil && cpu_perc != 0 {
|
|
fields[prefix+"cpu_usage"] = cpu_perc
|
|
}
|
|
|
|
mem, err := p.proc.MemoryInfo()
|
|
if err == nil {
|
|
fields[prefix+"memory_rss"] = mem.RSS
|
|
fields[prefix+"memory_vms"] = mem.VMS
|
|
fields[prefix+"memory_swap"] = mem.Swap
|
|
}
|
|
|
|
p.acc.AddFields("procstat", fields, p.tags)
|
|
}
|