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;
.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",
# 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 \
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)
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 ))