From 1be5d713061bebf7a28535387213c26d24d82efd Mon Sep 17 00:00:00 2001 From: Sunan Jiang Date: Thu, 5 Jan 2023 16:30:18 -0500 Subject: [PATCH 1/3] add t128_procstats and some basic passing unit test I95-48669 #time 3h --- plugins/inputs/procstat/procstat.go | 3 + plugins/inputs/procstat/t128_procstat.go | 477 ++++++++++++++++++ plugins/inputs/procstat/t128_procstat_test.go | 275 ++++++++++ 3 files changed, 755 insertions(+) create mode 100644 plugins/inputs/procstat/t128_procstat.go create mode 100644 plugins/inputs/procstat/t128_procstat_test.go diff --git a/plugins/inputs/procstat/procstat.go b/plugins/inputs/procstat/procstat.go index 915a1b13f44b4..c7ca10ede3bd2 100644 --- a/plugins/inputs/procstat/procstat.go +++ b/plugins/inputs/procstat/procstat.go @@ -572,4 +572,7 @@ func init() { inputs.Add("procstat", func() telegraf.Input { return &Procstat{} }) + inputs.Add("t128-procstat", func() telegraf.Input { + return &T128Procstat{} + }) } diff --git a/plugins/inputs/procstat/t128_procstat.go b/plugins/inputs/procstat/t128_procstat.go new file mode 100644 index 0000000000000..378ddf95fe14b --- /dev/null +++ b/plugins/inputs/procstat/t128_procstat.go @@ -0,0 +1,477 @@ +package procstat + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" +) + +type T128Procstat struct { + PidFinder string `toml:"pid_finder"` + PidFile string `toml:"pid_file"` + Exe string + Pattern string + Prefix string + CmdLineTag bool `toml:"cmdline_tag"` + ProcessName string + User string + SystemdUnit string `toml:"systemd_unit"` + IncludeSystemdChildren bool `toml:"include_systemd_children"` + CGroup string `toml:"cgroup"` + PidTag bool + WinService string `toml:"win_service"` + Mode string + + solarisMode bool + + finder PIDFinder + + createPIDFinder func() (PIDFinder, error) + procs map[PID]Process + createProcess func(PID) (Process, error) +} + +var t128sampleConfig = ` + ## PID file to monitor process + pid_file = "/var/run/nginx.pid" + ## executable name (ie, pgrep ) + # exe = "nginx" + ## pattern as argument for pgrep (ie, pgrep -f ) + # pattern = "nginx" + ## user as argument for pgrep (ie, pgrep -u ) + # user = "nginx" + ## Systemd unit name, supports globs when include_systemd_children is set to true + # systemd_unit = "nginx.service" + # include_systemd_children = false + ## CGroup name or path, supports globs + # cgroup = "systemd/system.slice/nginx.service" + + ## Windows service name + # win_service = "" + + ## override for process_name + ## This is optional; default is sourced from /proc//status + # process_name = "bar" + + ## Field name prefix + # prefix = "" + + ## When true add the full cmdline as a tag. + # cmdline_tag = false + + ## Mode to use when calculating CPU usage. Can be one of 'solaris' or 'irix'. + # mode = "irix" + + ## Add the PID as a tag instead of as a field. When collecting multiple + ## processes with otherwise matching tags this setting should be enabled to + ## ensure each process has a unique identity. + ## + ## Enabling this option may result in a large number of series, especially + ## when processes have a short lifetime. + # pid_tag = false + + ## Method to use when finding process IDs. Can be one of 'pgrep', or + ## 'native'. The pgrep finder calls the pgrep executable in the PATH while + ## the native finder performs the search directly in a manor dependent on the + ## platform. Default is 'pgrep' + # pid_finder = "pgrep" +` + +func (p *T128Procstat) SampleConfig() string { + return t128sampleConfig +} + +func (p *T128Procstat) Description() string { + return "Monitor process cpu and memory usage" +} + +func (p *T128Procstat) Gather(acc telegraf.Accumulator) error { + if p.createPIDFinder == nil { + switch p.PidFinder { + case "native": + p.createPIDFinder = NewNativeFinder + case "pgrep": + p.createPIDFinder = NewPgrep + default: + p.PidFinder = "pgrep" + p.createPIDFinder = defaultPIDFinder + } + } + if p.createProcess == nil { + p.createProcess = defaultProcess + } + + pidCount := 0 + now := time.Now() + newProcs := make(map[PID]Process, len(p.procs)) + pidTags := p.findPids() + for _, pidTag := range pidTags { + pids := pidTag.PIDS + tags := pidTag.Tags + err := pidTag.Err + pidCount += len(pids) + if err != nil { + fields := map[string]interface{}{ + "pid_count": 0, + "running": 0, + "result_code": 1, + } + tags := map[string]string{ + "pid_finder": p.PidFinder, + "result": "lookup_error", + } + acc.AddFields("procstat_lookup", fields, tags, now) + return err + } + + err = p.updateProcesses(pids, tags, p.procs, newProcs) + if err != nil { + acc.AddError(fmt.Errorf("procstat getting process, exe: [%s] pidfile: [%s] pattern: [%s] user: [%s] %s", + p.Exe, p.PidFile, p.Pattern, p.User, err.Error())) + } + } + + p.procs = newProcs + for _, proc := range p.procs { + p.addMetric(proc, acc, now) + } + + tags := make(map[string]string) + for _, pidTag := range pidTags { + for key, value := range pidTag.Tags { + tags[key] = value + } + } + + fields := map[string]interface{}{ + "pid_count": pidCount, + "running": len(p.procs), + "result_code": 0, + } + + tags["pid_finder"] = p.PidFinder + tags["result"] = "success" + acc.AddFields("procstat_lookup", fields, tags, now) + + return nil +} + +// Add metrics a single Process +func (p *T128Procstat) addMetric(proc Process, acc telegraf.Accumulator, t time.Time) { + var prefix string + if p.Prefix != "" { + prefix = p.Prefix + "_" + } + + fields := map[string]interface{}{} + + //If process_name tag is not already set, set to actual name + if _, nameInTags := proc.Tags()["process_name"]; !nameInTags { + name, err := proc.Name() + if err == nil { + proc.Tags()["process_name"] = name + } + } + + //If user tag is not already set, set to actual name + if _, ok := proc.Tags()["user"]; !ok { + user, err := proc.Username() + if err == nil { + proc.Tags()["user"] = user + } + } + + //If pid is not present as a tag, include it as a field. + if _, pidInTags := proc.Tags()["pid"]; !pidInTags { + fields["pid"] = int32(proc.PID()) + } + + //If cmd_line tag is true and it is not already set add cmdline as a tag + if p.CmdLineTag { + if _, ok := proc.Tags()["cmdline"]; !ok { + cmdline, err := proc.Cmdline() + if err == nil { + proc.Tags()["cmdline"] = cmdline + } + } + } + + createdAt, err := proc.CreateTime() //Returns epoch in ms + if err == nil { + fields[prefix+"created_at"] = createdAt * 1000000 //Convert ms to ns + } + + cpuTime, err := proc.Times() + if err == nil { + fields[prefix+"cpu_time_user"] = cpuTime.User + fields[prefix+"cpu_time_system"] = cpuTime.System + fields[prefix+"cpu_time_idle"] = cpuTime.Idle + fields[prefix+"cpu_time_nice"] = cpuTime.Nice + fields[prefix+"cpu_time_iowait"] = cpuTime.Iowait + fields[prefix+"cpu_time_irq"] = cpuTime.Irq + fields[prefix+"cpu_time_soft_irq"] = cpuTime.Softirq + fields[prefix+"cpu_time_steal"] = cpuTime.Steal + fields[prefix+"cpu_time_guest"] = cpuTime.Guest + fields[prefix+"cpu_time_guest_nice"] = cpuTime.GuestNice + } + + cpuPerc, err := proc.Percent(time.Duration(0)) + if err == nil { + if p.solarisMode { + fields[prefix+"cpu_usage"] = cpuPerc / float64(runtime.NumCPU()) + } else { + fields[prefix+"cpu_usage"] = cpuPerc + } + } + + mem, err := proc.MemoryInfo() + if err == nil { + fields[prefix+"memory_rss"] = mem.RSS + fields[prefix+"memory_vms"] = mem.VMS + fields[prefix+"memory_swap"] = mem.Swap + fields[prefix+"memory_data"] = mem.Data + fields[prefix+"memory_stack"] = mem.Stack + fields[prefix+"memory_locked"] = mem.Locked + } + + ppid, err := proc.Ppid() + if err == nil { + fields[prefix+"ppid"] = ppid + } + + acc.AddFields("procstat", fields, proc.Tags(), t) +} + +// Update monitored Processes +func (p *T128Procstat) updateProcesses(pids []PID, tags map[string]string, prevInfo map[PID]Process, procs map[PID]Process) error { + for _, pid := range pids { + info, ok := prevInfo[pid] + if ok { + // Assumption: if a process has no name, it probably does not exist + if name, _ := info.Name(); name == "" { + continue + } + procs[pid] = info + } else { + proc, err := p.createProcess(pid) + if err != nil { + // No problem; process may have ended after we found it + continue + } + // Assumption: if a process has no name, it probably does not exist + if name, _ := proc.Name(); name == "" { + continue + } + procs[pid] = proc + + // Add initial tags + for k, v := range tags { + proc.Tags()[k] = v + } + + // Add pid tag if needed + if p.PidTag { + proc.Tags()["pid"] = strconv.Itoa(int(pid)) + } + if p.ProcessName != "" { + proc.Tags()["process_name"] = p.ProcessName + } + } + } + return nil +} + +// Create and return PIDGatherer lazily +func (p *T128Procstat) getPIDFinder() (PIDFinder, error) { + if p.finder == nil { + f, err := p.createPIDFinder() + if err != nil { + return nil, err + } + p.finder = f + } + return p.finder, nil +} + +// Get matching PIDs and their initial tags +func (p *T128Procstat) findPids() []PidsTags { + var pidTags []PidsTags + + if p.SystemdUnit != "" { + groups := p.systemdUnitPIDs() + return groups + } else if p.CGroup != "" { + groups := p.cgroupPIDs() + return groups + } else { + f, err := p.getPIDFinder() + if err != nil { + pidTags = append(pidTags, PidsTags{nil, nil, err}) + return pidTags + } + pids, tags, err := p.SimpleFindPids(f) + pidTags = append(pidTags, PidsTags{pids, tags, err}) + } + + return pidTags +} + +// Get matching PIDs and their initial tags +func (p *T128Procstat) SimpleFindPids(f PIDFinder) ([]PID, map[string]string, error) { + var pids []PID + tags := make(map[string]string) + var err error + + if p.PidFile != "" { + pids, err = f.PidFile(p.PidFile) + tags = map[string]string{"pidfile": p.PidFile} + } else if p.Exe != "" { + pids, err = f.Pattern(p.Exe) + tags = map[string]string{"exe": p.Exe} + } else if p.Pattern != "" { + pids, err = f.FullPattern(p.Pattern) + tags = map[string]string{"pattern": p.Pattern} + } else if p.User != "" { + pids, err = f.UID(p.User) + tags = map[string]string{"user": p.User} + } else if p.WinService != "" { + pids, err = p.winServicePIDs() + tags = map[string]string{"win_service": p.WinService} + } else { + err = fmt.Errorf("either exe, pid_file, user, pattern, systemd_unit, cgroup, or win_service must be specified") + } + + return pids, tags, err +} + +// execCommand is so tests can mock out exec.Command usage. +var t128execCommand = exec.Command + +func (p *T128Procstat) systemdUnitPIDs() []PidsTags { + if p.IncludeSystemdChildren { + p.CGroup = fmt.Sprintf("systemd/system.slice/%s", p.SystemdUnit) + return p.cgroupPIDs() + } + + var pidTags []PidsTags + + pids, err := p.simpleSystemdUnitPIDs() + tags := map[string]string{"systemd_unit": p.SystemdUnit} + pidTags = append(pidTags, PidsTags{pids, tags, err}) + return pidTags +} + +func (p *T128Procstat) simpleSystemdUnitPIDs() ([]PID, error) { + var pids []PID + + cmd := t128execCommand("systemctl", "show", p.SystemdUnit) + out, err := cmd.Output() + if err != nil { + return nil, err + } + for _, line := range bytes.Split(out, []byte{'\n'}) { + kv := bytes.SplitN(line, []byte{'='}, 2) + if len(kv) != 2 { + continue + } + if !bytes.Equal(kv[0], []byte("MainPID")) { + continue + } + if len(kv[1]) == 0 || bytes.Equal(kv[1], []byte("0")) { + return nil, nil + } + pid, err := strconv.ParseInt(string(kv[1]), 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid pid '%s'", kv[1]) + } + pids = append(pids, PID(pid)) + } + + return pids, nil +} + +func (p *T128Procstat) cgroupPIDs() []PidsTags { + var pidTags []PidsTags + + procsPath := p.CGroup + if procsPath[0] != '/' { + procsPath = "/sys/fs/cgroup/" + procsPath + } + items, err := filepath.Glob(procsPath) + if err != nil { + pidTags = append(pidTags, PidsTags{nil, nil, fmt.Errorf("glob failed '%s'", err)}) + return pidTags + } + for _, item := range items { + pids, err := p.singleCgroupPIDs(item) + tags := map[string]string{"cgroup": p.CGroup, "cgroup_full": item} + pidTags = append(pidTags, PidsTags{pids, tags, err}) + } + + return pidTags +} + +func (p *T128Procstat) singleCgroupPIDs(path string) ([]PID, error) { + var pids []PID + + ok, err := isDir(path) + if err != nil { + return nil, err + } + if !ok { + return nil, fmt.Errorf("not a directory %s", path) + } + procsPath := filepath.Join(path, "cgroup.procs") + out, err := os.ReadFile(procsPath) + if err != nil { + return nil, err + } + for _, pidBS := range bytes.Split(out, []byte{'\n'}) { + if len(pidBS) == 0 { + continue + } + pid, err := strconv.ParseInt(string(pidBS), 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid pid '%s'", pidBS) + } + pids = append(pids, PID(pid)) + } + + return pids, nil +} + +func (p *T128Procstat) winServicePIDs() ([]PID, error) { + var pids []PID + + pid, err := queryPidWithWinServiceName(p.WinService) + if err != nil { + return pids, err + } + + pids = append(pids, PID(pid)) + + return pids, nil +} + +func (p *T128Procstat) Init() error { + if strings.ToLower(p.Mode) == "solaris" { + p.solarisMode = true + } + + return nil +} + +func init() { + inputs.Add("procstat", func() telegraf.Input { + return &Procstat{} + }) +} diff --git a/plugins/inputs/procstat/t128_procstat_test.go b/plugins/inputs/procstat/t128_procstat_test.go new file mode 100644 index 0000000000000..86204f35aaf38 --- /dev/null +++ b/plugins/inputs/procstat/t128_procstat_test.go @@ -0,0 +1,275 @@ +package procstat + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/influxdata/telegraf/testutil" +) + +func init() { + execCommand = mockExecCommand +} + +func TestT128Gather_CreateProcessErrorOk(t *testing.T) { + var acc testutil.Accumulator + + p := T128Procstat{ + Exe: exe, + createPIDFinder: pidFinder([]PID{pid}), + createProcess: func(PID) (Process, error) { + return nil, fmt.Errorf("createProcess error") + }, + } + require.NoError(t, acc.GatherError(p.Gather)) +} + +// func TestGather_CreatePIDFinderError(t *testing.T) { +// var acc testutil.Accumulator + +// p := Procstat{ +// createPIDFinder: func() (PIDFinder, error) { +// return nil, fmt.Errorf("createPIDFinder error") +// }, +// createProcess: newTestProc, +// } +// require.Error(t, acc.GatherError(p.Gather)) +// } + +// func TestGather_ProcessName(t *testing.T) { +// var acc testutil.Accumulator + +// p := Procstat{ +// Exe: exe, +// ProcessName: "custom_name", +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.Equal(t, "custom_name", acc.TagValue("procstat", "process_name")) +// } + +// func TestGather_NoProcessNameUsesReal(t *testing.T) { +// var acc testutil.Accumulator +// pid := PID(os.Getpid()) + +// p := Procstat{ +// Exe: exe, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.True(t, acc.HasTag("procstat", "process_name")) +// } + +func TestT128Gather_NoPidTag(t *testing.T) { + var acc testutil.Accumulator + + p := T128Procstat{ + Exe: exe, + createPIDFinder: pidFinder([]PID{pid}), + createProcess: newTestProc, + } + require.NoError(t, acc.GatherError(p.Gather)) + require.True(t, acc.HasInt32Field("procstat", "pid")) + require.False(t, acc.HasTag("procstat", "pid")) +} + +func TestT128Gather_PidTag(t *testing.T) { + var acc testutil.Accumulator + + p := T128Procstat{ + Exe: exe, + PidTag: true, + createPIDFinder: pidFinder([]PID{pid}), + createProcess: newTestProc, + } + require.NoError(t, acc.GatherError(p.Gather)) + require.Equal(t, "42", acc.TagValue("procstat", "pid")) + require.False(t, acc.HasInt32Field("procstat", "pid")) +} + +// func TestGather_Prefix(t *testing.T) { +// var acc testutil.Accumulator + +// p := Procstat{ +// Exe: exe, +// Prefix: "custom_prefix", +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) +// require.True(t, acc.HasInt32Field("procstat", "custom_prefix_num_fds")) +// } + +// func TestGather_Exe(t *testing.T) { +// var acc testutil.Accumulator + +// p := Procstat{ +// Exe: exe, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.Equal(t, exe, acc.TagValue("procstat", "exe")) +// } + +// func TestGather_User(t *testing.T) { +// var acc testutil.Accumulator +// user := "ada" + +// p := Procstat{ +// User: user, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.Equal(t, user, acc.TagValue("procstat", "user")) +// } + +// func TestGather_Pattern(t *testing.T) { +// var acc testutil.Accumulator +// pattern := "foo" + +// p := Procstat{ +// Pattern: pattern, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.Equal(t, pattern, acc.TagValue("procstat", "pattern")) +// } + +// func TestGather_MissingPidMethod(t *testing.T) { +// var acc testutil.Accumulator + +// p := Procstat{ +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.Error(t, acc.GatherError(p.Gather)) +// } + +// func TestGather_PidFile(t *testing.T) { +// var acc testutil.Accumulator +// pidfile := "/path/to/pidfile" + +// p := Procstat{ +// PidFile: pidfile, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.Equal(t, pidfile, acc.TagValue("procstat", "pidfile")) +// } + +// func TestGather_PercentFirstPass(t *testing.T) { +// var acc testutil.Accumulator +// pid := PID(os.Getpid()) + +// p := Procstat{ +// Pattern: "foo", +// PidTag: true, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: NewProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.True(t, acc.HasFloatField("procstat", "cpu_time_user")) +// require.False(t, acc.HasFloatField("procstat", "cpu_usage")) +// } + +// func TestGather_PercentSecondPass(t *testing.T) { +// var acc testutil.Accumulator +// pid := PID(os.Getpid()) + +// p := Procstat{ +// Pattern: "foo", +// PidTag: true, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: NewProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) +// require.NoError(t, acc.GatherError(p.Gather)) + +// require.True(t, acc.HasFloatField("procstat", "cpu_time_user")) +// require.True(t, acc.HasFloatField("procstat", "cpu_usage")) +// } + +// func TestGather_systemdUnitPIDs(t *testing.T) { +// p := Procstat{ +// createPIDFinder: pidFinder([]PID{}), +// SystemdUnit: "TestGather_systemdUnitPIDs", +// } +// pidsTags := p.findPids() +// for _, pidsTag := range pidsTags { +// pids := pidsTag.PIDS +// tags := pidsTag.Tags +// err := pidsTag.Err +// require.NoError(t, err) +// require.Equal(t, []PID{11408}, pids) +// require.Equal(t, "TestGather_systemdUnitPIDs", tags["systemd_unit"]) +// } +// } + +// func TestGather_cgroupPIDs(t *testing.T) { +// //no cgroups in windows +// if runtime.GOOS == "windows" { +// t.Skip("no cgroups in windows") +// } +// td, err := os.MkdirTemp("", "") +// require.NoError(t, err) +// defer os.RemoveAll(td) +// err = os.WriteFile(filepath.Join(td, "cgroup.procs"), []byte("1234\n5678\n"), 0644) +// require.NoError(t, err) + +// p := Procstat{ +// createPIDFinder: pidFinder([]PID{}), +// CGroup: td, +// } +// pidsTags := p.findPids() +// for _, pidsTag := range pidsTags { +// pids := pidsTag.PIDS +// tags := pidsTag.Tags +// err := pidsTag.Err +// require.NoError(t, err) +// require.Equal(t, []PID{1234, 5678}, pids) +// require.Equal(t, td, tags["cgroup"]) +// } +// } + +// func TestProcstatLookupMetric(t *testing.T) { +// p := Procstat{ +// createPIDFinder: pidFinder([]PID{543}), +// 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)) +// } + +// func TestGather_SameTimestamps(t *testing.T) { +// var acc testutil.Accumulator +// pidfile := "/path/to/pidfile" + +// p := Procstat{ +// PidFile: pidfile, +// createPIDFinder: pidFinder([]PID{pid}), +// createProcess: newTestProc, +// } +// require.NoError(t, acc.GatherError(p.Gather)) + +// procstat, _ := acc.Get("procstat") +// procstatLookup, _ := acc.Get("procstat_lookup") + +// require.Equal(t, procstat.Time, procstatLookup.Time) +// } From 12a7459dbcf2a314acc5b37b3689a1562a43c7b5 Mon Sep 17 00:00:00 2001 From: Sunan Jiang Date: Fri, 6 Jan 2023 16:23:10 -0500 Subject: [PATCH 2/3] add more test cases and fix setup I95-48669 #time 1h --- plugins/inputs/procstat/t128_procstat_test.go | 325 ++++++------------ 1 file changed, 111 insertions(+), 214 deletions(-) diff --git a/plugins/inputs/procstat/t128_procstat_test.go b/plugins/inputs/procstat/t128_procstat_test.go index 86204f35aaf38..25472b0b6e504 100644 --- a/plugins/inputs/procstat/t128_procstat_test.go +++ b/plugins/inputs/procstat/t128_procstat_test.go @@ -2,6 +2,9 @@ package procstat import ( "fmt" + "os" + "path/filepath" + "runtime" "testing" "github.com/stretchr/testify/require" @@ -10,12 +13,11 @@ import ( ) func init() { - execCommand = mockExecCommand + t128execCommand = mockExecCommand } func TestT128Gather_CreateProcessErrorOk(t *testing.T) { var acc testutil.Accumulator - p := T128Procstat{ Exe: exe, createPIDFinder: pidFinder([]PID{pid}), @@ -26,250 +28,145 @@ func TestT128Gather_CreateProcessErrorOk(t *testing.T) { require.NoError(t, acc.GatherError(p.Gather)) } -// func TestGather_CreatePIDFinderError(t *testing.T) { -// var acc testutil.Accumulator - -// p := Procstat{ -// createPIDFinder: func() (PIDFinder, error) { -// return nil, fmt.Errorf("createPIDFinder error") -// }, -// createProcess: newTestProc, -// } -// require.Error(t, acc.GatherError(p.Gather)) -// } - -// func TestGather_ProcessName(t *testing.T) { -// var acc testutil.Accumulator - -// p := Procstat{ -// Exe: exe, -// ProcessName: "custom_name", -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) - -// require.Equal(t, "custom_name", acc.TagValue("procstat", "process_name")) -// } - -// func TestGather_NoProcessNameUsesReal(t *testing.T) { -// var acc testutil.Accumulator -// pid := PID(os.Getpid()) - -// p := Procstat{ -// Exe: exe, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) +func TestT128Gather_CreatePIDFinderError(t *testing.T) { + var acc testutil.Accumulator -// require.True(t, acc.HasTag("procstat", "process_name")) -// } + p := T128Procstat{ + createPIDFinder: func() (PIDFinder, error) { + return nil, fmt.Errorf("createPIDFinder error") + }, + createProcess: newTestProc, + } + require.Error(t, acc.GatherError(p.Gather)) +} -func TestT128Gather_NoPidTag(t *testing.T) { +func TestT128Gather_ProcessName(t *testing.T) { var acc testutil.Accumulator p := T128Procstat{ Exe: exe, + ProcessName: "custom_name", createPIDFinder: pidFinder([]PID{pid}), createProcess: newTestProc, } require.NoError(t, acc.GatherError(p.Gather)) - require.True(t, acc.HasInt32Field("procstat", "pid")) - require.False(t, acc.HasTag("procstat", "pid")) + + require.Equal(t, "custom_name", acc.TagValue("procstat", "process_name")) } -func TestT128Gather_PidTag(t *testing.T) { +func TestT128Gather_NoProcessNameUsesReal(t *testing.T) { var acc testutil.Accumulator + pid := PID(os.Getpid()) p := T128Procstat{ Exe: exe, - PidTag: true, createPIDFinder: pidFinder([]PID{pid}), createProcess: newTestProc, } require.NoError(t, acc.GatherError(p.Gather)) - require.Equal(t, "42", acc.TagValue("procstat", "pid")) - require.False(t, acc.HasInt32Field("procstat", "pid")) -} - -// func TestGather_Prefix(t *testing.T) { -// var acc testutil.Accumulator - -// p := Procstat{ -// Exe: exe, -// Prefix: "custom_prefix", -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) -// require.True(t, acc.HasInt32Field("procstat", "custom_prefix_num_fds")) -// } -// func TestGather_Exe(t *testing.T) { -// var acc testutil.Accumulator - -// p := Procstat{ -// Exe: exe, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) - -// require.Equal(t, exe, acc.TagValue("procstat", "exe")) -// } - -// func TestGather_User(t *testing.T) { -// var acc testutil.Accumulator -// user := "ada" - -// p := Procstat{ -// User: user, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) - -// require.Equal(t, user, acc.TagValue("procstat", "user")) -// } - -// func TestGather_Pattern(t *testing.T) { -// var acc testutil.Accumulator -// pattern := "foo" - -// p := Procstat{ -// Pattern: pattern, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) - -// require.Equal(t, pattern, acc.TagValue("procstat", "pattern")) -// } - -// func TestGather_MissingPidMethod(t *testing.T) { -// var acc testutil.Accumulator - -// p := Procstat{ -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.Error(t, acc.GatherError(p.Gather)) -// } - -// func TestGather_PidFile(t *testing.T) { -// var acc testutil.Accumulator -// pidfile := "/path/to/pidfile" - -// p := Procstat{ -// PidFile: pidfile, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) - -// require.Equal(t, pidfile, acc.TagValue("procstat", "pidfile")) -// } + require.True(t, acc.HasTag("procstat", "process_name")) +} -// func TestGather_PercentFirstPass(t *testing.T) { -// var acc testutil.Accumulator -// pid := PID(os.Getpid()) +func TestT128Gather_PercentFirstPass(t *testing.T) { + var acc testutil.Accumulator + pid := PID(os.Getpid()) -// p := Procstat{ -// Pattern: "foo", -// PidTag: true, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: NewProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) + p := T128Procstat{ + Pattern: "foo", + PidTag: true, + createPIDFinder: pidFinder([]PID{pid}), + createProcess: NewProc, + } + require.NoError(t, acc.GatherError(p.Gather)) -// require.True(t, acc.HasFloatField("procstat", "cpu_time_user")) -// require.False(t, acc.HasFloatField("procstat", "cpu_usage")) -// } + require.True(t, acc.HasFloatField("procstat", "cpu_time_user")) + require.False(t, acc.HasFloatField("procstat", "cpu_usage")) +} -// func TestGather_PercentSecondPass(t *testing.T) { -// var acc testutil.Accumulator -// pid := PID(os.Getpid()) +func TestT128Gather_PercentSecondPass(t *testing.T) { + var acc testutil.Accumulator + pid := PID(os.Getpid()) -// p := Procstat{ -// Pattern: "foo", -// PidTag: true, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: NewProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) -// require.NoError(t, acc.GatherError(p.Gather)) + p := T128Procstat{ + Pattern: "foo", + PidTag: true, + createPIDFinder: pidFinder([]PID{pid}), + createProcess: NewProc, + } + require.NoError(t, acc.GatherError(p.Gather)) + require.NoError(t, acc.GatherError(p.Gather)) -// require.True(t, acc.HasFloatField("procstat", "cpu_time_user")) -// require.True(t, acc.HasFloatField("procstat", "cpu_usage")) -// } + require.True(t, acc.HasFloatField("procstat", "cpu_time_user")) + require.True(t, acc.HasFloatField("procstat", "cpu_usage")) +} -// func TestGather_systemdUnitPIDs(t *testing.T) { -// p := Procstat{ -// createPIDFinder: pidFinder([]PID{}), -// SystemdUnit: "TestGather_systemdUnitPIDs", -// } -// pidsTags := p.findPids() -// for _, pidsTag := range pidsTags { -// pids := pidsTag.PIDS -// tags := pidsTag.Tags -// err := pidsTag.Err -// require.NoError(t, err) -// require.Equal(t, []PID{11408}, pids) -// require.Equal(t, "TestGather_systemdUnitPIDs", tags["systemd_unit"]) -// } -// } +func TestT128Gather_systemdUnitPIDs(t *testing.T) { + p := T128Procstat{ + createPIDFinder: pidFinder([]PID{}), + SystemdUnit: "TestGather_systemdUnitPIDs", + } + pidsTags := p.findPids() + for _, pidsTag := range pidsTags { + pids := pidsTag.PIDS + tags := pidsTag.Tags + err := pidsTag.Err + require.NoError(t, err) + require.Equal(t, []PID{11408}, pids) + require.Equal(t, "TestGather_systemdUnitPIDs", tags["systemd_unit"]) + } +} -// func TestGather_cgroupPIDs(t *testing.T) { -// //no cgroups in windows -// if runtime.GOOS == "windows" { -// t.Skip("no cgroups in windows") -// } -// td, err := os.MkdirTemp("", "") -// require.NoError(t, err) -// defer os.RemoveAll(td) -// err = os.WriteFile(filepath.Join(td, "cgroup.procs"), []byte("1234\n5678\n"), 0644) -// require.NoError(t, err) +func TestT128Gather_cgroupPIDs(t *testing.T) { + //no cgroups in windows + if runtime.GOOS == "windows" { + t.Skip("no cgroups in windows") + } + td, err := os.MkdirTemp("", "") + require.NoError(t, err) + defer os.RemoveAll(td) + err = os.WriteFile(filepath.Join(td, "cgroup.procs"), []byte("1234\n5678\n"), 0644) + require.NoError(t, err) -// p := Procstat{ -// createPIDFinder: pidFinder([]PID{}), -// CGroup: td, -// } -// pidsTags := p.findPids() -// for _, pidsTag := range pidsTags { -// pids := pidsTag.PIDS -// tags := pidsTag.Tags -// err := pidsTag.Err -// require.NoError(t, err) -// require.Equal(t, []PID{1234, 5678}, pids) -// require.Equal(t, td, tags["cgroup"]) -// } -// } + p := T128Procstat{ + createPIDFinder: pidFinder([]PID{}), + CGroup: td, + } + pidsTags := p.findPids() + for _, pidsTag := range pidsTags { + pids := pidsTag.PIDS + tags := pidsTag.Tags + err := pidsTag.Err + require.NoError(t, err) + require.Equal(t, []PID{1234, 5678}, pids) + require.Equal(t, td, tags["cgroup"]) + } +} -// func TestProcstatLookupMetric(t *testing.T) { -// p := Procstat{ -// createPIDFinder: pidFinder([]PID{543}), -// 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)) -// } +func TestT128ProcstatLookupMetric(t *testing.T) { + p := Procstat{ + createPIDFinder: pidFinder([]PID{543}), + 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)) +} -// func TestGather_SameTimestamps(t *testing.T) { -// var acc testutil.Accumulator -// pidfile := "/path/to/pidfile" +func TestT128Gather_SameTimestamps(t *testing.T) { + var acc testutil.Accumulator + pidfile := "/path/to/pidfile" -// p := Procstat{ -// PidFile: pidfile, -// createPIDFinder: pidFinder([]PID{pid}), -// createProcess: newTestProc, -// } -// require.NoError(t, acc.GatherError(p.Gather)) + p := T128Procstat{ + PidFile: pidfile, + createPIDFinder: pidFinder([]PID{pid}), + createProcess: newTestProc, + } + require.NoError(t, acc.GatherError(p.Gather)) -// procstat, _ := acc.Get("procstat") -// procstatLookup, _ := acc.Get("procstat_lookup") + procstat, _ := acc.Get("procstat") + procstatLookup, _ := acc.Get("procstat_lookup") -// require.Equal(t, procstat.Time, procstatLookup.Time) -// } + require.Equal(t, procstat.Time, procstatLookup.Time) +} From 3f6e6f254206d195179894baf7ad991df9de8ba9 Mon Sep 17 00:00:00 2001 From: Sunan Jiang Date: Mon, 9 Jan 2023 09:41:17 -0500 Subject: [PATCH 3/3] fix prefix convention I95-48669 #time 2m --- plugins/inputs/procstat/procstat.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/procstat/procstat.go b/plugins/inputs/procstat/procstat.go index c7ca10ede3bd2..69883f88f5ec4 100644 --- a/plugins/inputs/procstat/procstat.go +++ b/plugins/inputs/procstat/procstat.go @@ -572,7 +572,7 @@ func init() { inputs.Add("procstat", func() telegraf.Input { return &Procstat{} }) - inputs.Add("t128-procstat", func() telegraf.Input { + inputs.Add("t128_procstat", func() telegraf.Input { return &T128Procstat{} }) }