From c0b64eef37b2d9ab5c74d56c087e4743cfd217b8 Mon Sep 17 00:00:00 2001 From: Yaping Li <202858510+YapingLi04@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:57:46 -0700 Subject: [PATCH] report: add manager-level metrics to varlink Metrics API Added these metrics: - JobsQueued: number of jobs currently queued - SystemState: overall system state (running, degraded, etc.) - UnitsByLoadStateTotal: unit counts broken down by load state - UnitsTotal: total number of units Also bump METRICS_MAX from 1024 to 4096 to accommodate the new per-unit metrics that are now collected. --- src/core/varlink-metrics.c | 109 ++++++++++++++++++++++++++++++++++++- src/report/report.c | 2 +- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/core/varlink-metrics.c b/src/core/varlink-metrics.c index 00af452d77..68560387f3 100644 --- a/src/core/varlink-metrics.c +++ b/src/core/varlink-metrics.c @@ -108,7 +108,7 @@ static int units_by_type_total_build_json(MetricFamilyContext *context, void *us static int units_by_state_total_build_json(MetricFamilyContext *context, void *userdata) { Manager *manager = ASSERT_PTR(userdata); - UnitActiveState counters[_UNIT_ACTIVE_STATE_MAX] = {}; + uint64_t counters[_UNIT_ACTIVE_STATE_MAX] = {}; Unit *unit; char *key; int r; @@ -143,14 +143,109 @@ static int units_by_state_total_build_json(MetricFamilyContext *context, void *u return 0; } +static int jobs_queued_build_json(MetricFamilyContext *context, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + + assert(context); + + return metric_build_send_unsigned( + context, + /* object= */ NULL, + hashmap_size(manager->jobs), + /* fields= */ NULL); +} + +static int system_state_build_json(MetricFamilyContext *context, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + + assert(context); + + return metric_build_send_string( + context, + /* object= */ NULL, + manager_state_to_string(manager_state(manager)), + /* fields= */ NULL); +} + +static int units_by_load_state_total_build_json(MetricFamilyContext *context, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + uint64_t counters[_UNIT_LOAD_STATE_MAX] = {}; + Unit *unit; + char *key; + int r; + + assert(context); + + HASHMAP_FOREACH_KEY(unit, key, manager->units) { + /* ignore aliases */ + if (key != unit->id) + continue; + + counters[unit->load_state]++; + } + + for (UnitLoadState state = 0; state < _UNIT_LOAD_STATE_MAX; state++) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL; + + r = sd_json_buildo(&fields, SD_JSON_BUILD_PAIR_STRING("load_state", unit_load_state_to_string(state))); + if (r < 0) + return r; + + r = metric_build_send_unsigned( + context, + /* object= */ NULL, + counters[state], + fields); + if (r < 0) + return r; + } + + return 0; +} + +static int units_total_build_json(MetricFamilyContext *context, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + uint64_t count = 0; + Unit *unit; + char *key; + + assert(context); + + HASHMAP_FOREACH_KEY(unit, key, manager->units) { + /* ignore aliases */ + if (key != unit->id) + continue; + + count++; + } + + return metric_build_send_unsigned( + context, + /* object= */ NULL, + count, + /* fields= */ NULL); +} + static const MetricFamily metric_family_table[] = { /* Keep metrics ordered alphabetically */ + { + .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "JobsQueued", + .description = "Number of jobs currently queued", + .type = METRIC_FAMILY_TYPE_GAUGE, + .generate = jobs_queued_build_json, + }, { .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "NRestarts", .description = "Per unit metric: number of restarts", .type = METRIC_FAMILY_TYPE_COUNTER, .generate = nrestarts_build_json, }, + { + .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "SystemState", + .description = "Overall system state", + .type = METRIC_FAMILY_TYPE_STRING, + .generate = system_state_build_json, + }, { .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "UnitActiveState", .description = "Per unit metric: active state", @@ -163,6 +258,12 @@ static const MetricFamily metric_family_table[] = { .type = METRIC_FAMILY_TYPE_STRING, .generate = unit_load_state_build_json, }, + { + .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "UnitsByLoadStateTotal", + .description = "Total number of units by load state", + .type = METRIC_FAMILY_TYPE_GAUGE, + .generate = units_by_load_state_total_build_json, + }, { .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "UnitsByStateTotal", .description = "Total number of units of different state", @@ -175,6 +276,12 @@ static const MetricFamily metric_family_table[] = { .type = METRIC_FAMILY_TYPE_GAUGE, .generate = units_by_type_total_build_json, }, + { + .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "UnitsTotal", + .description = "Total number of units", + .type = METRIC_FAMILY_TYPE_GAUGE, + .generate = units_total_build_json, + }, {} }; diff --git a/src/report/report.c b/src/report/report.c index 108b24e470..ca169c94a8 100644 --- a/src/report/report.c +++ b/src/report/report.c @@ -27,7 +27,7 @@ #include "varlink-idl-util.h" #include "verbs.h" -#define METRICS_OR_FACTS_MAX 1024U +#define METRICS_OR_FACTS_MAX 4096U #define METRICS_OR_FACTS_LINKS_MAX 128U #define TIMEOUT_USEC (30 * USEC_PER_SEC) /* 30 seconds */