feat(plugins/inputs/systemd_units): add pattern support (#9665)

This commit is contained in:
David B 2021-08-26 22:34:52 +02:00 committed by GitHub
parent 1a59157b91
commit 4dc2967e34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 10 deletions

View File

@ -1,7 +1,7 @@
# systemd Units Input Plugin # systemd Units Input Plugin
The systemd_units plugin gathers systemd unit status on Linux. It relies on The systemd_units plugin gathers systemd unit status on Linux. It relies on
`systemctl list-units --all --plain --type=service` to collect data on service status. `systemctl list-units [PATTERN] --all --plain --type=service` to collect data on service status.
The results are tagged with the unit name and provide enumerated fields for The results are tagged with the unit name and provide enumerated fields for
loaded, active and running fields, indicating the unit health. loaded, active and running fields, indicating the unit health.
@ -22,6 +22,13 @@ see `systemctl list-units --all --type help` for possible options.
## values are "socket", "target", "device", "mount", "automount", "swap", ## values are "socket", "target", "device", "mount", "automount", "swap",
## "timer", "path", "slice" and "scope ": ## "timer", "path", "slice" and "scope ":
# unittype = "service" # unittype = "service"
#
## Filter for a specific pattern, default is "" (i.e. all), other possible
## values are valid pattern for systemctl, e.g. "a*" for all units with
## names starting with "a"
# pattern = ""
## pattern = "telegraf* influxdb*"
## pattern = "a*"
``` ```
### Metrics ### Metrics

View File

@ -18,10 +18,11 @@ import (
type SystemdUnits struct { type SystemdUnits struct {
Timeout config.Duration Timeout config.Duration
UnitType string `toml:"unittype"` UnitType string `toml:"unittype"`
Pattern string `toml:"pattern"`
systemctl systemctl systemctl systemctl
} }
type systemctl func(timeout config.Duration, unitType string) (*bytes.Buffer, error) type systemctl func(timeout config.Duration, unitType string, pattern string) (*bytes.Buffer, error)
const measurement = "systemd_units" const measurement = "systemd_units"
@ -115,6 +116,7 @@ var subMap = map[string]int{
var ( var (
defaultTimeout = config.Duration(time.Second) defaultTimeout = config.Duration(time.Second)
defaultUnitType = "service" defaultUnitType = "service"
defaultPattern = ""
) )
// Description returns a short description of the plugin // Description returns a short description of the plugin
@ -132,12 +134,19 @@ func (s *SystemdUnits) SampleConfig() string {
## values are "socket", "target", "device", "mount", "automount", "swap", ## values are "socket", "target", "device", "mount", "automount", "swap",
## "timer", "path", "slice" and "scope ": ## "timer", "path", "slice" and "scope ":
# unittype = "service" # unittype = "service"
#
## Filter for a specific pattern, default is "" (i.e. all), other possible
## values are valid pattern for systemctl, e.g. "a*" for all units with
## names starting with "a"
# pattern = ""
## pattern = "telegraf* influxdb*"
## pattern = "a*"
` `
} }
// Gather parses systemctl outputs and adds counters to the Accumulator // Gather parses systemctl outputs and adds counters to the Accumulator
func (s *SystemdUnits) Gather(acc telegraf.Accumulator) error { func (s *SystemdUnits) Gather(acc telegraf.Accumulator) error {
out, err := s.systemctl(s.Timeout, s.UnitType) out, err := s.systemctl(s.Timeout, s.UnitType, s.Pattern)
if err != nil { if err != nil {
return err return err
} }
@ -192,22 +201,32 @@ func (s *SystemdUnits) Gather(acc telegraf.Accumulator) error {
return nil return nil
} }
func setSystemctl(timeout config.Duration, unitType string) (*bytes.Buffer, error) { func setSystemctl(timeout config.Duration, unitType string, pattern string) (*bytes.Buffer, error) {
// is systemctl available ? // is systemctl available ?
systemctlPath, err := exec.LookPath("systemctl") systemctlPath, err := exec.LookPath("systemctl")
if err != nil { if err != nil {
return nil, err return nil, err
} }
// build parameters for systemctl call
cmd := exec.Command(systemctlPath, "list-units", "--all", "--plain", fmt.Sprintf("--type=%s", unitType), "--no-legend") params := []string{"list-units"}
// create patterns parameters if provided in config
if pattern != "" {
psplit := strings.SplitN(pattern, " ", -1)
for v := range psplit {
params = append(params, psplit[v])
}
}
params = append(params, "--all", "--plain")
// add type as configured in config
params = append(params, fmt.Sprintf("--type=%s", unitType))
params = append(params, "--no-legend")
cmd := exec.Command(systemctlPath, params...)
var out bytes.Buffer var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
err = internal.RunTimeout(cmd, time.Duration(timeout)) err = internal.RunTimeout(cmd, time.Duration(timeout))
if err != nil { if err != nil {
return &out, fmt.Errorf("error running systemctl list-units --all --plain --type=%s --no-legend: %s", unitType, err) return &out, fmt.Errorf("error running systemctl %s: %s", strings.Join(params, " "), err)
} }
return &out, nil return &out, nil
} }
@ -217,6 +236,7 @@ func init() {
systemctl: setSystemctl, systemctl: setSystemctl,
Timeout: defaultTimeout, Timeout: defaultTimeout,
UnitType: defaultUnitType, UnitType: defaultUnitType,
Pattern: defaultPattern,
} }
}) })
} }

View File

@ -74,7 +74,7 @@ func TestSystemdUnits(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
systemdUnits := &SystemdUnits{ systemdUnits := &SystemdUnits{
systemctl: func(timeout config.Duration, unitType string) (*bytes.Buffer, error) { systemctl: func(timeout config.Duration, unitType string, pattern string) (*bytes.Buffer, error) {
return bytes.NewBufferString(tt.line), nil return bytes.NewBufferString(tt.line), nil
}, },
} }