feat(inputs.systemd_units): Add active_enter_timestamp_us field (#16287)

This commit is contained in:
Sven Rebhan 2024-12-11 22:32:52 +01:00 committed by GitHub
parent 2ccc79ce27
commit e3ce01abf0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 114 additions and 93 deletions

2
go.mod
View File

@ -89,7 +89,6 @@ require (
github.com/go-sql-driver/mysql v1.8.1
github.com/go-stomp/stomp v2.1.4+incompatible
github.com/gobwas/glob v0.2.3
github.com/godbus/dbus/v5 v5.1.0
github.com/gofrs/uuid/v5 v5.3.0
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec
@ -348,6 +347,7 @@ require (
github.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect

View File

@ -94,6 +94,7 @@ The following *additional* metrics are available with `details = true`:
- swap_current (uint, current swap usage)
- swap_peak (uint, peak swap usage)
- mem_avail (uint, available memory for this unit)
- active_enter_timestamp_us (uint, timestamp in us when entered the state)
### Load

View File

@ -123,7 +123,7 @@ type client interface {
ListUnitFilesByPatternsContext(ctx context.Context, states, pattern []string) ([]dbus.UnitFile, error)
ListUnitsByNamesContext(ctx context.Context, units []string) ([]dbus.UnitStatus, error)
GetUnitTypePropertiesContext(ctx context.Context, unit, unitType string) (map[string]interface{}, error)
GetUnitPropertyContext(ctx context.Context, unit, propertyName string) (*dbus.Property, error)
GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error)
ListUnitsContext(ctx context.Context) ([]dbus.UnitStatus, error)
}
@ -134,6 +134,7 @@ type archParams struct {
unitTypeDBus string
scope string
user string
warnUnitProps map[string]bool
}
func (s *SystemdUnits) Init() error {
@ -176,6 +177,8 @@ func (s *SystemdUnits) Init() error {
return fmt.Errorf("invalid 'scope' %q", s.Scope)
}
s.warnUnitProps = make(map[string]bool)
return nil
}
@ -374,26 +377,35 @@ func (s *SystemdUnits) Gather(acc telegraf.Accumulator) error {
}
// Get required unit file properties
var unitFileState string
if v, err := s.client.GetUnitPropertyContext(ctx, state.Name, "UnitFileState"); err == nil {
unitFileState = strings.Trim(v.Value.String(), `'"`)
}
var unitFilePreset string
if v, err := s.client.GetUnitPropertyContext(ctx, state.Name, "UnitFilePreset"); err == nil {
unitFilePreset = strings.Trim(v.Value.String(), `'"`)
unitProperties, err := s.client.GetUnitPropertiesContext(ctx, state.Name)
if err != nil && !s.warnUnitProps[state.Name] {
s.Log.Warnf("Cannot read unit properties for %q: %v", state.Name, err)
s.warnUnitProps[state.Name] = true
}
tags["state"] = unitFileState
tags["preset"] = unitFilePreset
// Set tags
if v, found := unitProperties["UnitFileState"]; found {
tags["state"] = v.(string)
}
if v, found := unitProperties["UnitFilePreset"]; found {
tags["preset"] = v.(string)
}
// Set fields
if v, found := unitProperties["ActiveEnterTimestamp"]; found {
fields["active_enter_timestamp_us"] = v
}
fields["status_errno"] = properties["StatusErrno"]
fields["restarts"] = properties["NRestarts"]
fields["pid"] = properties["MainPID"]
fields["mem_current"] = properties["MemoryCurrent"]
fields["mem_peak"] = properties["MemoryPeak"]
fields["mem_avail"] = properties["MemoryAvailable"]
fields["swap_current"] = properties["MemorySwapCurrent"]
fields["swap_peak"] = properties["MemorySwapPeak"]
fields["mem_avail"] = properties["MemoryAvailable"]
// Sanitize unset memory fields
for k, value := range fields {

View File

@ -4,7 +4,6 @@ package systemd_units
import (
"context"
"errors"
"fmt"
"math"
"os/user"
@ -13,7 +12,6 @@ import (
"time"
sdbus "github.com/coreos/go-systemd/v22/dbus"
"github.com/godbus/dbus/v5"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
@ -30,6 +28,7 @@ type properties struct {
state *sdbus.UnitStatus
ufPreset string
ufState string
ufActiveEnter uint64
properties map[string]interface{}
}
@ -284,6 +283,7 @@ func TestListFiles(t *testing.T) {
}
func TestShow(t *testing.T) {
enter := time.Now().UnixMicro()
tests := []struct {
name string
properties map[string]properties
@ -303,6 +303,7 @@ func TestShow(t *testing.T) {
},
ufPreset: "disabled",
ufState: "enabled",
ufActiveEnter: uint64(enter),
properties: map[string]interface{}{
"Id": "example.service",
"StatusErrno": 0,
@ -339,6 +340,7 @@ func TestShow(t *testing.T) {
"swap_peak": uint64(4000),
"mem_avail": uint64(5000),
"pid": 9999,
"active_enter_timestamp_us": uint64(enter),
},
time.Unix(0, 0),
),
@ -357,6 +359,7 @@ func TestShow(t *testing.T) {
},
ufPreset: "disabled",
ufState: "enabled",
ufActiveEnter: 0,
properties: map[string]interface{}{
"Id": "example.service",
"StatusErrno": 0,
@ -386,6 +389,7 @@ func TestShow(t *testing.T) {
"swap_current": uint64(0),
"swap_peak": uint64(0),
"mem_avail": uint64(0),
"active_enter_timestamp_us": uint64(0),
},
time.Unix(0, 0),
),
@ -404,6 +408,7 @@ func TestShow(t *testing.T) {
},
ufPreset: "disabled",
ufState: "enabled",
ufActiveEnter: uint64(enter),
properties: map[string]interface{}{
"Id": "example.service",
"StatusErrno": 10,
@ -438,6 +443,7 @@ func TestShow(t *testing.T) {
"swap_current": uint64(3000),
"swap_peak": uint64(4000),
"mem_avail": uint64(5000),
"active_enter_timestamp_us": uint64(enter),
},
time.Unix(0, 0),
),
@ -456,6 +462,7 @@ func TestShow(t *testing.T) {
},
ufPreset: "disabled",
ufState: "enabled",
ufActiveEnter: uint64(0),
properties: map[string]interface{}{
"Id": "example.service",
},
@ -481,6 +488,7 @@ func TestShow(t *testing.T) {
"swap_current": uint64(0),
"swap_peak": uint64(0),
"mem_avail": uint64(0),
"active_enter_timestamp_us": uint64(0),
},
time.Unix(0, 0),
),
@ -519,6 +527,7 @@ func TestShow(t *testing.T) {
},
ufPreset: "disabled",
ufState: "disabled",
ufActiveEnter: uint64(0),
properties: map[string]interface{}{
"Id": "example.service",
"StatusErrno": 0,
@ -553,6 +562,7 @@ func TestShow(t *testing.T) {
"swap_current": uint64(0),
"swap_peak": uint64(0),
"mem_avail": uint64(0),
"active_enter_timestamp_us": uint64(0),
},
time.Unix(0, 0),
),
@ -974,19 +984,17 @@ func (c *fakeClient) GetUnitTypePropertiesContext(_ context.Context, unit, unitT
return u.properties, nil
}
func (c *fakeClient) GetUnitPropertyContext(_ context.Context, unit, propertyName string) (*sdbus.Property, error) {
func (c *fakeClient) GetUnitPropertiesContext(_ context.Context, unit string) (map[string]interface{}, error) {
u, found := c.units[unit]
if !found {
return nil, nil
}
switch propertyName {
case "UnitFileState":
return &sdbus.Property{Name: propertyName, Value: dbus.MakeVariant(u.ufState)}, nil
case "UnitFilePreset":
return &sdbus.Property{Name: propertyName, Value: dbus.MakeVariant(u.ufPreset)}, nil
}
return nil, errors.New("unknown property")
return map[string]interface{}{
"UnitFileState": u.ufState,
"UnitFilePreset": u.ufPreset,
"ActiveEnterTimestamp": u.ufActiveEnter,
}, nil
}
func (c *fakeClient) ListUnitsContext(_ context.Context) ([]sdbus.UnitStatus, error) {