core/varlink-metrics: expose ReloadCount as a metric

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>
This commit is contained in:
Simon Lucido
2026-05-05 11:53:01 +01:00
committed by Luca Boccassi
parent 2d9d62f658
commit 71ebb27686
2 changed files with 46 additions and 5 deletions
+18
View 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",
+28 -5
View File
@@ -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 ))