feat(inputs.systemd_units): Support user scoped units (#15458)
This commit is contained in:
parent
32a5b44d7b
commit
4a9eba6abd
|
|
@ -31,6 +31,10 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
## automount, swap, timer, path, slice and scope
|
## automount, swap, timer, path, slice and scope
|
||||||
# unittype = "service"
|
# unittype = "service"
|
||||||
|
|
||||||
|
## Collect system or user scoped units
|
||||||
|
## ex: scope = "user"
|
||||||
|
# scope = "system"
|
||||||
|
|
||||||
## Collect also units not loaded by systemd, i.e. disabled or static units
|
## Collect also units not loaded by systemd, i.e. disabled or static units
|
||||||
## Enabling this feature might introduce significant load when used with
|
## Enabling this feature might introduce significant load when used with
|
||||||
## unspecific patterns (such as '*') as systemd will need to load all
|
## unspecific patterns (such as '*') as systemd will need to load all
|
||||||
|
|
@ -69,6 +73,7 @@ These metrics are available in both modes:
|
||||||
- load (string, load state)
|
- load (string, load state)
|
||||||
- active (string, active state)
|
- active (string, active state)
|
||||||
- sub (string, sub state)
|
- sub (string, sub state)
|
||||||
|
- user (string, username only for user scope)
|
||||||
- fields:
|
- fields:
|
||||||
- load_code (int, see below)
|
- load_code (int, see below)
|
||||||
- active_code (int, see below)
|
- active_code (int, see below)
|
||||||
|
|
@ -198,15 +203,15 @@ were removed, tables are hex aligned to keep some space for future values
|
||||||
### Output in non-detailed mode
|
### Output in non-detailed mode
|
||||||
|
|
||||||
```text
|
```text
|
||||||
systemd_units,host=host1.example.com,name=dbus.service,load=loaded,active=active,sub=running load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
|
systemd_units,host=host1.example.com,name=dbus.service,load=loaded,active=active,sub=running,user=telegraf load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
|
||||||
systemd_units,host=host1.example.com,name=networking.service,load=loaded,active=failed,sub=failed load_code=0i,active_code=3i,sub_code=12i 1533730725000000000
|
systemd_units,host=host1.example.com,name=networking.service,load=loaded,active=failed,sub=failed,user=telegraf load_code=0i,active_code=3i,sub_code=12i 1533730725000000000
|
||||||
systemd_units,host=host1.example.com,name=ssh.service,load=loaded,active=active,sub=running load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
|
systemd_units,host=host1.example.com,name=ssh.service,load=loaded,active=active,sub=running,user=telegraf load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
|
||||||
```
|
```
|
||||||
|
|
||||||
### Output in detailed mode
|
### Output in detailed mode
|
||||||
|
|
||||||
```text
|
```text
|
||||||
systemd_units,active=active,host=host1.example.com,load=loaded,name=dbus.service,sub=running,preset=disabled,state=static active_code=0i,load_code=0i,mem_avail=6470856704i,mem_current=2691072i,mem_peak=3895296i,pid=481i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=794624i,swap_peak=884736i 1533730725000000000
|
systemd_units,active=active,host=host1.example.com,load=loaded,name=dbus.service,sub=running,preset=disabled,state=static,user=telegraf active_code=0i,load_code=0i,mem_avail=6470856704i,mem_current=2691072i,mem_peak=3895296i,pid=481i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=794624i,swap_peak=884736i 1533730725000000000
|
||||||
systemd_units,active=inactive,host=host1.example.com,load=not-found,name=networking.service,sub=dead active_code=2i,load_code=2i,pid=0i,restarts=0i,status_errno=0i,sub_code=1i 1533730725000000000
|
systemd_units,active=inactive,host=host1.example.com,load=not-found,name=networking.service,sub=dead,user=telegraf active_code=2i,load_code=2i,pid=0i,restarts=0i,status_errno=0i,sub_code=1i 1533730725000000000
|
||||||
systemd_units,active=active,host=host1.example.com,load=loaded,name=pcscd.service,sub=running,preset=disabled,state=indirect active_code=0i,load_code=0i,mem_avail=6370541568i,mem_current=512000i,mem_peak=4399104i,pid=1673i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=3149824i,swap_peak=3149824i 1533730725000000000
|
systemd_units,active=active,host=host1.example.com,load=loaded,name=pcscd.service,sub=running,preset=disabled,state=indirect,user=telegraf active_code=0i,load_code=0i,mem_avail=6370541568i,mem_current=512000i,mem_peak=4399104i,pid=1673i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=3149824i,swap_peak=3149824i 1533730725000000000
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
## automount, swap, timer, path, slice and scope
|
## automount, swap, timer, path, slice and scope
|
||||||
# unittype = "service"
|
# unittype = "service"
|
||||||
|
|
||||||
|
## Collect system or user scoped units
|
||||||
|
## ex: scope = "user"
|
||||||
|
# scope = "system"
|
||||||
|
|
||||||
## Collect also units not loaded by systemd, i.e. disabled or static units
|
## Collect also units not loaded by systemd, i.e. disabled or static units
|
||||||
## Enabling this feature might introduce significant load when used with
|
## Enabling this feature might introduce significant load when used with
|
||||||
## unspecific patterns (such as '*') as systemd will need to load all
|
## unspecific patterns (such as '*') as systemd will need to load all
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ var sampleConfig string
|
||||||
type SystemdUnits struct {
|
type SystemdUnits struct {
|
||||||
Pattern string `toml:"pattern"`
|
Pattern string `toml:"pattern"`
|
||||||
UnitType string `toml:"unittype"`
|
UnitType string `toml:"unittype"`
|
||||||
|
Scope string `toml:"scope"`
|
||||||
Details bool `toml:"details"`
|
Details bool `toml:"details"`
|
||||||
CollectDisabled bool `toml:"collect_disabled_units"`
|
CollectDisabled bool `toml:"collect_disabled_units"`
|
||||||
Timeout config.Duration `toml:"timeout"`
|
Timeout config.Duration `toml:"timeout"`
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -131,6 +132,8 @@ type archParams struct {
|
||||||
pattern []string
|
pattern []string
|
||||||
filter filter.Filter
|
filter filter.Filter
|
||||||
unitTypeDBus string
|
unitTypeDBus string
|
||||||
|
scope string
|
||||||
|
user string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SystemdUnits) Init() error {
|
func (s *SystemdUnits) Init() error {
|
||||||
|
|
@ -158,15 +161,38 @@ func (s *SystemdUnits) Init() error {
|
||||||
}
|
}
|
||||||
s.filter = f
|
s.filter = f
|
||||||
|
|
||||||
|
switch s.Scope {
|
||||||
|
case "", "system":
|
||||||
|
s.scope = "system"
|
||||||
|
case "user":
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to determine user: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.scope = "user"
|
||||||
|
s.user = u.Username
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid 'scope' %q", s.Scope)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SystemdUnits) Start(telegraf.Accumulator) error {
|
func (s *SystemdUnits) Start(telegraf.Accumulator) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client, err := dbus.NewSystemConnectionContext(ctx)
|
|
||||||
|
var client *dbus.Conn
|
||||||
|
var err error
|
||||||
|
if s.scope == "user" {
|
||||||
|
client, err = dbus.NewUserConnectionContext(ctx)
|
||||||
|
} else {
|
||||||
|
client, err = dbus.NewSystemConnectionContext(ctx)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.client = client
|
s.client = client
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -321,6 +347,9 @@ func (s *SystemdUnits) Gather(acc telegraf.Accumulator) error {
|
||||||
"active": state.ActiveState,
|
"active": state.ActiveState,
|
||||||
"sub": state.SubState,
|
"sub": state.SubState,
|
||||||
}
|
}
|
||||||
|
if s.scope == "user" {
|
||||||
|
tags["user"] = s.user
|
||||||
|
}
|
||||||
|
|
||||||
fields := map[string]interface{}{
|
fields := map[string]interface{}{
|
||||||
"load_code": load,
|
"load_code": load,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"os/user"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -38,6 +39,50 @@ func TestDefaultPattern(t *testing.T) {
|
||||||
require.Equal(t, "*", plugin.Pattern)
|
require.Equal(t, "*", plugin.Pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDefaultScope(t *testing.T) {
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
scope string
|
||||||
|
expectedScope string
|
||||||
|
expectedUser string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "default scope",
|
||||||
|
scope: "",
|
||||||
|
expectedScope: "system",
|
||||||
|
expectedUser: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "system scope",
|
||||||
|
scope: "system",
|
||||||
|
expectedScope: "system",
|
||||||
|
expectedUser: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user scope",
|
||||||
|
scope: "user",
|
||||||
|
expectedScope: "user",
|
||||||
|
expectedUser: u.Username,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
plugin := &SystemdUnits{
|
||||||
|
Scope: tt.scope,
|
||||||
|
}
|
||||||
|
require.NoError(t, plugin.Init())
|
||||||
|
require.Equal(t, tt.expectedScope, plugin.scope)
|
||||||
|
require.Equal(t, tt.expectedUser, plugin.user)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestListFiles(t *testing.T) {
|
func TestListFiles(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue