]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/varlink-metrics: expose ReloadCount as a metric
authorSimon Lucido <simonlucido@meta.com>
Mon, 4 May 2026 09:40:41 +0000 (11:40 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 5 May 2026 10:53:01 +0000 (11:53 +0100)
Add ReloadCount to the io.systemd.Metrics family table so it can be
queried alongside other manager-level metrics via systemd-report.

Also extend the existing integration test to cross-check the value
returned by systemd-report against the D-Bus and Varlink transports
on every assertion.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Simon Lucido <simonlucido@meta.com>
src/core/varlink-metrics.c
test/units/TEST-07-PID1.reload-count.sh

index 82bc3cf4cba15e40ff3f59165e23fe83770e6c92..f1ac0791bc914d8399fb1d68f5edcb0d5e2b85d9 100644 (file)
@@ -189,6 +189,18 @@ static int nrestarts_build_json(MetricFamilyContext *context, void *userdata) {
         return 0;
 }
 
+static int reload_count_build_json(MetricFamilyContext *context, void *userdata) {
+        Manager *manager = ASSERT_PTR(userdata);
+
+        assert(context);
+
+        return metric_build_send_unsigned(
+                        context,
+                        /* object= */ NULL,
+                        manager->reload_count,
+                        /* fields= */ NULL);
+}
+
 static int units_by_type_total_build_json(MetricFamilyContext *context, void *userdata) {
         Manager *manager = ASSERT_PTR(userdata);
         int r;
@@ -364,6 +376,12 @@ static const MetricFamily metric_family_table[] = {
                 .type = METRIC_FAMILY_TYPE_COUNTER,
                 .generate = nrestarts_build_json,
         },
+        {
+                .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "ReloadCount",
+                .description = "Number of successful manager reloads since startup; resets across daemon-reexec",
+                .type = METRIC_FAMILY_TYPE_COUNTER,
+                .generate = reload_count_build_json,
+        },
         {
                 .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "StateChangeTimestamp",
                 .description = "Per unit metric: timestamp of the last state change in microseconds; 0 indicates no state change has occurred",
index 7c31b65c5fc75ce1e589a71eec8157093a8f8bb5..a41a4e467d23329a8919904203bdf3ffb5c6de85 100755 (executable)
@@ -5,7 +5,13 @@ set -o pipefail
 
 # Verify that the manager exposes a ReloadCount property that increments on
 # every daemon-reload, resets to zero across daemon-reexec (since the count
-# is not serialized), and is reachable over both D-Bus and Varlink.
+# is not serialized), and is reachable over D-Bus, Varlink Describe, and the
+# io.systemd.Metrics interface (queried via systemd-report).
+
+# systemd-report silently returns empty if the metrics source is missing,
+# which would falsely pass the cross-checks below. Assert the socket exists
+# so any failure points at the real problem.
+test -S /run/systemd/report/io.systemd.Manager
 
 read_count_dbus() {
     busctl -j get-property org.freedesktop.systemd1 \
@@ -19,10 +25,23 @@ read_count_varlink() {
                     io.systemd.Manager.Describe '{}' | jq -r '.runtime.ReloadCount'
 }
 
-# Sanity: both transports must agree.
+read_count_report() {
+    local out
+    # Strip the RS separator that jq --seq re-emits on output.
+    out=$(/usr/lib/systemd/systemd-report metrics --json=short \
+              io.systemd.Manager.ReloadCount \
+          | jq --seq -r 'select(.name == "io.systemd.Manager.ReloadCount") | .value' \
+          | tr -d '\036')
+    [[ -n "$out" ]] || { echo "ReloadCount metric missing from systemd-report output" >&2; return 1; }
+    echo "$out"
+}
+
+# Sanity: all three transports must agree.
 dbus_count=$(read_count_dbus)
 varlink_count=$(read_count_varlink)
+report_count=$(read_count_report)
 (( dbus_count == varlink_count ))
+(( dbus_count == report_count ))
 
 # A single reload bumps the counter by one.
 before=$(read_count_dbus)
@@ -34,18 +53,22 @@ systemctl daemon-reload
 systemctl daemon-reload
 (( $(read_count_dbus) == before + 3 ))
 
-# And both transports still agree after the reload.
+# And all three transports still agree after the reload.
 dbus_count=$(read_count_dbus)
 varlink_count=$(read_count_varlink)
+report_count=$(read_count_report)
 (( dbus_count == varlink_count ))
+(( dbus_count == report_count ))
 
-# A daemon-reexec resets the counter back to zero on both transports, since
-# reload_count lives only in memory and is not carried across the reexec.
+# A daemon-reexec resets the counter back to zero on all three transports,
+# since the counter lives only in memory and is not carried across the reexec.
 # `systemctl daemon-reexec` returns as soon as the old PID 1 closes its bus
 # connection, which is before the new PID 1 has rebound /run/systemd/private.
 # Use --watch-bind=yes to block on inotify until the new socket is live.
 systemctl daemon-reexec
 busctl --watch-bind=yes call org.freedesktop.systemd1 /org/freedesktop/systemd1 \
                            org.freedesktop.DBus.Peer Ping >/dev/null
+
 (( $(read_count_dbus) == 0 ))
 (( $(read_count_varlink) == 0 ))
+(( $(read_count_report) == 0 ))