From de75655c840588935f3f0495c456a301d72817a7 Mon Sep 17 00:00:00 2001 From: Ben House Date: Wed, 30 Apr 2025 16:31:21 -0700 Subject: [PATCH] Add systemd_unit_active_enter_monotonic_seconds Add support for collecting `ActiveEnterTimestampMonotonic` from each systemd unit and exposing it as the `systemd_unit_active_enter_monotonic_seconds` metric. I encountered a bug in dbus or systemd that is reporting the same values for `systemd_boot_monotonic_seconds` and `systemd_boot_time_seconds`, with both being the monotonic value. This prohibits the calculation of the difference with the existing `systemd_unit_active_enter_time_seconds` which is reported as the value from the realtime clock. Example: ``` $ busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager UserspaceTimestamp UserspaceTimestampMonotonic t 10938338 t 10938338 ``` On other systems: ``` $ busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager UserspaceTimestamp UserspaceTimestampMonotonic t 1746046198232969 t 42412983 ``` This change is to only add monotonic seconds for `active_enter` to avoid a major amplification of metrics for each unit by adding the same for `active_exit`, `inactive_enter`, `inactive_exit`. Signed-off-by: Ben House --- systemd/systemd.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/systemd/systemd.go b/systemd/systemd.go index 7c518de..43345d0 100644 --- a/systemd/systemd.go +++ b/systemd/systemd.go @@ -67,6 +67,7 @@ type Collector struct { unitTasksCurrentDesc *prometheus.Desc unitTasksMaxDesc *prometheus.Desc unitActiveEnterTimeDesc *prometheus.Desc + unitActiveEnterMonotonicDesc *prometheus.Desc unitActiveExitTimeDesc *prometheus.Desc unitInactiveEnterTimeDesc *prometheus.Desc unitInactiveExitTimeDesc *prometheus.Desc @@ -140,6 +141,11 @@ func NewCollector(logger *slog.Logger) (*Collector, error) { "Last time the unit transitioned into the active state", []string{"name", "type"}, nil, ) + unitActiveEnterMonotonicDesc := prometheus.NewDesc( + prometheus.BuildFQName(namespace, "", "unit_active_enter_monotonic_seconds"), + "Monotonic time when the unit transitioned into the active state", + []string{"name", "type"}, nil, + ) unitActiveExitTimeDesc := prometheus.NewDesc( prometheus.BuildFQName(namespace, "", "unit_active_exit_time_seconds"), "Last time the unit transitioned out of the active state", @@ -237,6 +243,7 @@ func NewCollector(logger *slog.Logger) (*Collector, error) { unitTasksCurrentDesc: unitTasksCurrentDesc, unitTasksMaxDesc: unitTasksMaxDesc, unitActiveEnterTimeDesc: unitActiveEnterTimeDesc, + unitActiveEnterMonotonicDesc: unitActiveEnterMonotonicDesc, unitActiveExitTimeDesc: unitActiveExitTimeDesc, unitInactiveEnterTimeDesc: unitInactiveEnterTimeDesc, unitInactiveExitTimeDesc: unitInactiveExitTimeDesc, @@ -276,6 +283,11 @@ func (c *Collector) Describe(desc chan<- *prometheus.Desc) { desc <- c.unitStartTimeDesc desc <- c.unitTasksCurrentDesc desc <- c.unitTasksMaxDesc + desc <- c.unitActiveEnterTimeDesc + desc <- c.unitActiveEnterMonotonicDesc + desc <- c.unitActiveExitTimeDesc + desc <- c.unitInactiveEnterTimeDesc + desc <- c.unitInactiveExitTimeDesc desc <- c.nRestartsDesc desc <- c.timerLastTriggerDesc desc <- c.socketAcceptedConnectionsDesc @@ -473,6 +485,10 @@ func (c *Collector) collectUnitTimeMetrics(conn *dbus.Conn, ch chan<- prometheus if err != nil { return err } + err = c.collectUnitTimeMetric(conn, ch, unit, c.unitActiveEnterMonotonicDesc, "ActiveEnterTimestampMonotonic") + if err != nil { + return err + } err = c.collectUnitTimeMetric(conn, ch, unit, c.unitActiveExitTimeDesc, "ActiveExitTimestamp") if err != nil { return err