diff --git a/plugins/inputs/procstat/README.md b/plugins/inputs/procstat/README.md index efa71489b53b4..852c109f06ebc 100644 --- a/plugins/inputs/procstat/README.md +++ b/plugins/inputs/procstat/README.md @@ -11,6 +11,7 @@ Processes can be selected for monitoring using one of several methods: - user - systemd_unit - cgroup +- win_service ### Configuration: @@ -30,6 +31,9 @@ Processes can be selected for monitoring using one of several methods: ## CGroup name or path # 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" @@ -75,6 +79,7 @@ implemented as a WMI query. The pattern allows fuzzy matching using only - user (when selected) - systemd_unit (when defined) - cgroup (when defined) + - win_service (when defined) - fields: - cpu_time (int) - cpu_time_guest (float) @@ -139,6 +144,7 @@ implemented as a WMI query. The pattern allows fuzzy matching using only - user (string) - systemd_unit (string) - cgroup (string) + - win_service (string) - fields: - pid_count (int) *NOTE: Resource limit > 2147483647 will be reported as 2147483647.* diff --git a/plugins/inputs/procstat/procstat.go b/plugins/inputs/procstat/procstat.go index 4b253fd1c969b..d9c1ee7b6bd63 100644 --- a/plugins/inputs/procstat/procstat.go +++ b/plugins/inputs/procstat/procstat.go @@ -32,6 +32,7 @@ type Procstat struct { SystemdUnit string CGroup string `toml:"cgroup"` PidTag bool + WinService string `tom:"win_service"` finder PIDFinder @@ -54,6 +55,9 @@ var sampleConfig = ` ## CGroup name or path # 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" @@ -317,8 +321,11 @@ func (p *Procstat) findPids(acc telegraf.Accumulator) ([]PID, map[string]string, } else if p.CGroup != "" { pids, err = p.cgroupPIDs() tags = map[string]string{"cgroup": p.CGroup} + } 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, or cgroup must be specified") + err = fmt.Errorf("Either exe, pid_file, user, pattern, systemd_unit, cgroup, or win_service must be specified") } rTags := make(map[string]string) @@ -391,6 +398,19 @@ func (p *Procstat) cgroupPIDs() ([]PID, error) { return pids, nil } +func (p *Procstat) 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 init() { inputs.Add("procstat", func() telegraf.Input { return &Procstat{} diff --git a/plugins/inputs/procstat/win_service_notwindows.go b/plugins/inputs/procstat/win_service_notwindows.go new file mode 100644 index 0000000000000..3d539d9f9918c --- /dev/null +++ b/plugins/inputs/procstat/win_service_notwindows.go @@ -0,0 +1,11 @@ +// +build !windows + +package procstat + +import ( + "fmt" +) + +func queryPidWithWinServiceName(winServiceName string) (uint32, error) { + return 0, fmt.Errorf("os not support win_service option") +} diff --git a/plugins/inputs/procstat/win_service_windows.go b/plugins/inputs/procstat/win_service_windows.go new file mode 100644 index 0000000000000..70a5422633755 --- /dev/null +++ b/plugins/inputs/procstat/win_service_windows.go @@ -0,0 +1,49 @@ +// +build windows + +package procstat + +import ( + "unsafe" + + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc/mgr" +) + +func getService(name string) (*mgr.Service, error) { + m, err := mgr.Connect() + if err != nil { + return nil, err + } + defer m.Disconnect() + + srv, err := m.OpenService(name) + if err != nil { + return nil, err + } + + return srv, nil +} + +func queryPidWithWinServiceName(winServiceName string) (uint32, error) { + + srv, err := getService(winServiceName) + if err != nil { + return 0, err + } + + var p *windows.SERVICE_STATUS_PROCESS + var bytesNeeded uint32 + var buf []byte + + if err := windows.QueryServiceStatusEx(srv.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded); err != windows.ERROR_INSUFFICIENT_BUFFER { + return 0, err + } + + buf = make([]byte, bytesNeeded) + p = (*windows.SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0])) + if err := windows.QueryServiceStatusEx(srv.Handle, windows.SC_STATUS_PROCESS_INFO, &buf[0], uint32(len(buf)), &bytesNeeded); err != nil { + return 0, err + } + + return p.ProcessId, nil +}