@cryptotaxi247 / netdata-1 / commits / e54b6164d

go.d systemdunits add "skip_transient" (#17725)

Ilya Mashchenko committed May 21, 2024 at 22:28 UTC e54b6164dd9f9c897e99ed17f802f014275f7578
8 files changed +109 -2
src/go/collectors/go.d.plugin/modules/systemdunits/client.go
+1
@@ -17,6 +17,7 @@ type systemdClient interface {
17 type systemdConnection interface {
18 Close()
19 GetManagerProperty(string) (string, error)
20 + GetUnitPropertyContext(ctx context.Context, unit string, propertyName string) (*dbus.Property, error)
21 ListUnitsContext(ctx context.Context) ([]dbus.UnitStatus, error)
22 ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]dbus.UnitStatus, error)
23 ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]dbus.UnitFile, error)
src/go/collectors/go.d.plugin/modules/systemdunits/collect_units.go
+36
@@ -14,6 +14,8 @@ import (
14 "github.com/coreos/go-systemd/v22/dbus"
15 )
16
17 +const transientProperty = "Transient"
18 +
19 const (
20 // https://www.freedesktop.org/software/systemd/man/systemd.html
21 unitStateActive = "active"
@@ -55,6 +57,20 @@ func (s *SystemdUnits) collectUnits(mx map[string]int64, conn systemdConnection)
57
58 seen[unit.Name] = true
59
60 + if s.SkipTransient {
61 + if _, ok := s.unitTransient[unit.Name]; !ok {
62 + prop, err := s.getUnitTransientProperty(conn, unit.Name)
63 + if err != nil {
64 + return err
65 + }
66 + prop = strings.Trim(prop, "\"")
67 + s.unitTransient[unit.Name] = prop == "true"
68 + }
69 + if s.unitTransient[unit.Name] {
70 + continue
71 + }
72 + }
73 +
74 if !s.seenUnits[unit.Name] {
75 s.seenUnits[unit.Name] = true
76 s.addUnitCharts(name, typ)
@@ -75,6 +91,12 @@ func (s *SystemdUnits) collectUnits(mx map[string]int64, conn systemdConnection)
91 }
92 }
93
94 + for k := range s.unitTransient {
95 + if !seen[k] {
96 + delete(s.unitTransient, k)
97 + }
98 + }
99 +
100 return nil
101 }
102
@@ -130,6 +152,20 @@ func (s *SystemdUnits) getLoadedUnitsByPatterns(conn systemdConnection) ([]dbus.
152 return loaded, nil
153 }
154
155 +func (s *SystemdUnits) getUnitTransientProperty(conn systemdConnection, unit string) (string, error) {
156 + ctx, cancel := context.WithTimeout(context.Background(), s.Timeout.Duration())
157 + defer cancel()
158 +
159 + s.Debugf("calling function 'GetUnitProperty' for unit '%s'", unit)
160 +
161 + prop, err := conn.GetUnitPropertyContext(ctx, unit, transientProperty)
162 + if err != nil {
163 + return "", fmt.Errorf("error on GetUnitProperty: %v", err)
164 + }
165 +
166 + return prop.Value.String(), nil
167 +}
168 +
169 func extractUnitNameType(name string) (string, string, bool) {
170 idx := strings.LastIndexByte(name, '.')
171 if idx <= 0 {
src/go/collectors/go.d.plugin/modules/systemdunits/config_schema.json
+10
@@ -18,6 +18,12 @@
18 "minimum": 0.5,
19 "default": 2
20 },
21 + "skip_transient": {
22 + "title": "Skip transient units",
23 + "description": "If set, skip data collection for systemd transient units.",
24 + "type": "boolean",
25 + "default": false
26 + },
27 "include": {
28 "title": "Include",
29 "description": "Configuration for monitoring specific systemd units. Include systemd units whose names match any of the specified [patterns](https://golang.org/pkg/path/filepath/#Match).",
@@ -86,6 +92,7 @@
92 "fields": [
93 "update_every",
94 "timeout",
95 + "skip_transient",
96 "include"
97 ]
98 },
@@ -102,6 +109,9 @@
109 "timeout": {
110 "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
111 },
112 + "skip_transient": {
113 + "ui:help": "A systemd transient unit is a temporary unit created on-the-fly, typically used for ad-hoc tasks or testing purposes. They are created using the `systemd-run` command, which allows you to specify unit properties directly on the command line."
114 + },
115 "include": {
116 "ui:listFlavour": "list"
117 },
src/go/collectors/go.d.plugin/modules/systemdunits/metadata.yaml
+4
@@ -77,6 +77,10 @@ modules:
77 - pattern1
78 - pattern2
79 ```
80 + - name: skip_transient
81 + description: If set, skip data collection for systemd transient units.
82 + default_value: "false"
83 + required: false
84 - name: collect_unit_files
85 description: If set to true, collect the state of installed unit files. Enabling this may increase system overhead.
86 default_value: "false"
src/go/collectors/go.d.plugin/modules/systemdunits/systemdunits.go
+6 -2
@@ -36,6 +36,7 @@ func New() *SystemdUnits {
36 Config: Config{
37 Timeout: web.Duration(time.Second * 2),
38 Include: []string{"*.service"},
39 + SkipTransient: false,
40 CollectUnitFiles: false,
41 IncludeUnitFiles: []string{"*.service"},
42 CollectUnitFilesEvery: web.Duration(time.Minute * 5),
@@ -43,6 +44,7 @@ func New() *SystemdUnits {
44 charts: &module.Charts{},
45 client: newSystemdDBusClient(),
46 seenUnits: make(map[string]bool),
47 + unitTransient: make(map[string]bool),
48 seenUnitFiles: make(map[string]bool),
49 }
50 }
@@ -51,6 +53,7 @@ type Config struct {
53 UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
54 Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"`
55 Include []string `yaml:"include,omitempty" json:"include"`
56 + SkipTransient bool `yaml:"skip_transient" json:"skip_transient"`
57 CollectUnitFiles bool `yaml:"collect_unit_files,omitempty" json:"collect_unit_files"`
58 IncludeUnitFiles []string `yaml:"include_unit_files,omitempty" json:"include_unit_files"`
59 CollectUnitFilesEvery web.Duration `yaml:"collect_unit_files_every,omitempty" json:"collect_unit_files_every"`
@@ -65,8 +68,9 @@ type SystemdUnits struct {
68
69 systemdVersion int
70
68 - seenUnits map[string]bool
69 - unitSr matcher.Matcher
71 + seenUnits map[string]bool
72 + unitTransient map[string]bool
73 + unitSr matcher.Matcher
74
75 lastListUnitFilesTime time.Time
76 cachedUnitFiles []dbus.UnitFile
src/go/collectors/go.d.plugin/modules/systemdunits/systemdunits_test.go
+50
@@ -12,6 +12,7 @@ import (
12 "os"
13 "path/filepath"
14 "slices"
15 + "strings"
16 "testing"
17
18 "github.com/netdata/netdata/go/go.d.plugin/agent/module"
@@ -384,6 +385,37 @@ func TestSystemdUnits_Collect(t *testing.T) {
385 "unit_var-lib-nfs-rpc_pipefs_mount_state_inactive": 1,
386 },
387 },
388 + "success v230+ on collecting all unit type with skip transient": {
389 + prepare: func() *SystemdUnits {
390 + systemd := New()
391 + systemd.Include = []string{"*"}
392 + systemd.SkipTransient = true
393 + systemd.client = prepareOKClient(230)
394 + return systemd
395 + },
396 + wantCollected: map[string]int64{
397 + "unit_systemd-ask-password-wall_service_state_activating": 0,
398 + "unit_systemd-ask-password-wall_service_state_active": 0,
399 + "unit_systemd-ask-password-wall_service_state_deactivating": 0,
400 + "unit_systemd-ask-password-wall_service_state_failed": 0,
401 + "unit_systemd-ask-password-wall_service_state_inactive": 1,
402 + "unit_systemd-fsck-root_service_state_activating": 0,
403 + "unit_systemd-fsck-root_service_state_active": 0,
404 + "unit_systemd-fsck-root_service_state_deactivating": 0,
405 + "unit_systemd-fsck-root_service_state_failed": 0,
406 + "unit_systemd-fsck-root_service_state_inactive": 1,
407 + "unit_user-runtime-dir@1000_service_state_activating": 0,
408 + "unit_user-runtime-dir@1000_service_state_active": 1,
409 + "unit_user-runtime-dir@1000_service_state_deactivating": 0,
410 + "unit_user-runtime-dir@1000_service_state_failed": 0,
411 + "unit_user-runtime-dir@1000_service_state_inactive": 0,
412 + "unit_user@1000_service_state_activating": 0,
413 + "unit_user@1000_service_state_active": 1,
414 + "unit_user@1000_service_state_deactivating": 0,
415 + "unit_user@1000_service_state_failed": 0,
416 + "unit_user@1000_service_state_inactive": 0,
417 + },
418 + },
419 "success v230- on collecting all unit types": {
420 prepare: func() *SystemdUnits {
421 systemd := New()
@@ -946,6 +978,24 @@ func (m *mockConn) GetManagerProperty(prop string) (string, error) {
978 return fmt.Sprintf("%d.6-1-manjaro", m.version), nil
979 }
980
981 +func (m *mockConn) GetUnitPropertyContext(_ context.Context, unit string, propertyName string) (*dbus.Property, error) {
982 + if propertyName != transientProperty {
983 + return nil, fmt.Errorf("'GetUnitProperty' unkown property name: %s", propertyName)
984 + }
985 +
986 + var prop dbus.Property
987 +
988 + if strings.HasSuffix(unit, ".service") {
989 + prop = dbus.PropDescription("false")
990 + } else {
991 + prop = dbus.PropDescription("true")
992 + }
993 +
994 + prop.Name = propertyName
995 +
996 + return &prop, nil
997 +}
998 +
999 func (m *mockConn) ListUnitsContext(_ context.Context) ([]dbus.UnitStatus, error) {
1000 if m.errOnListUnits {
1001 return nil, errors.New("'ListUnits' call error")
src/go/collectors/go.d.plugin/modules/systemdunits/testdata/config.json
+1
@@ -4,6 +4,7 @@
4 "include": [
5 "ok"
6 ],
7 + "skip_transient": true,
8 "collect_unit_files": true,
9 "collect_unit_files_every": 123.123,
10 "include_unit_files": [
src/go/collectors/go.d.plugin/modules/systemdunits/testdata/config.yaml
+1
@@ -2,6 +2,7 @@ update_every: 123
2 timeout: 123.123
3 include:
4 - ok
5 +skip_transient: true
6 collect_unit_files: true
7 collect_unit_files_every: 123.123
8 include_unit_files: