report: add more metrics to the Varlink metrics API (#41078)

This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-04-03 19:55:24 +02:00
committed by GitHub
3 changed files with 302 additions and 2 deletions
+244 -1
View File
@@ -11,6 +11,118 @@
#include "unit.h"
#include "varlink-metrics.h"
static int active_timestamp_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
Unit *unit;
char *key;
int r;
assert(context);
_cleanup_(sd_json_variant_unrefp) sd_json_variant *enter_fields = NULL;
r = sd_json_buildo(&enter_fields, SD_JSON_BUILD_PAIR_STRING("event", "enter"));
if (r < 0)
return r;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *exit_fields = NULL;
r = sd_json_buildo(&exit_fields, SD_JSON_BUILD_PAIR_STRING("event", "exit"));
if (r < 0)
return r;
HASHMAP_FOREACH_KEY(unit, key, manager->units) {
/* ignore aliases */
if (key != unit->id)
continue;
r = metric_build_send_unsigned(
context,
unit->id,
unit->active_enter_timestamp.realtime,
enter_fields);
if (r < 0)
return r;
r = metric_build_send_unsigned(
context,
unit->id,
unit->active_exit_timestamp.realtime,
exit_fields);
if (r < 0)
return r;
}
return 0;
}
static int inactive_exit_timestamp_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
Unit *unit;
char *key;
int r;
assert(context);
HASHMAP_FOREACH_KEY(unit, key, manager->units) {
/* ignore aliases */
if (key != unit->id)
continue;
r = metric_build_send_unsigned(
context,
unit->id,
unit->inactive_exit_timestamp.realtime,
/* fields= */ NULL);
if (r < 0)
return r;
}
return 0;
}
static int state_change_timestamp_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
Unit *unit;
char *key;
int r;
assert(context);
HASHMAP_FOREACH_KEY(unit, key, manager->units) {
/* ignore aliases */
if (key != unit->id)
continue;
r = metric_build_send_unsigned(
context,
unit->id,
unit->state_change_timestamp.realtime,
/* fields= */ NULL);
if (r < 0)
return r;
}
return 0;
}
static int status_errno_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
int r;
assert(context);
LIST_FOREACH(units_by_type, unit, manager->units_by_type[UNIT_SERVICE]) {
r = metric_build_send_unsigned(
context,
unit->id,
(uint64_t) SERVICE(unit)->status_errno,
/* fields= */ NULL);
if (r < 0)
return r;
}
return 0;
}
static int unit_active_state_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
Unit *unit;
@@ -108,7 +220,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 +255,133 @@ 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 "ActiveTimestamp",
.description = "Per unit metric: timestamp of active state transitions in microseconds; 0 indicates the transition has not occurred",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate = active_timestamp_build_json,
},
{
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "InactiveExitTimestamp",
.description = "Per unit metric: timestamp when the unit last exited the inactive state in microseconds; 0 indicates the transition has not occurred",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate = inactive_exit_timestamp_build_json,
},
{
.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 "StateChangeTimestamp",
.description = "Per unit metric: timestamp of the last state change in microseconds; 0 indicates no state change has occurred",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate = state_change_timestamp_build_json,
},
{
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "StatusErrno",
.description = "Per service metric: errno status of the service",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate = status_errno_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 +394,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 +412,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,
},
{}
};
+57
View File
@@ -1,7 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "argv-util.h"
#include "errno-util.h"
#include "fd-util.h"
@@ -99,6 +101,55 @@ static int managed_interfaces_build_json(MetricFamilyContext *context, void *use
return metric_build_send_unsigned(context, /* object= */ NULL, count, /* fields= */ NULL);
}
static int required_for_online_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
Link *link;
int r;
assert(context);
HASHMAP_FOREACH(link, manager->links_by_index) {
if (!link->network)
continue;
if (link->network->required_for_online == 0) {
r = metric_build_send_string(
context,
link->ifname,
"no",
/* fields= */ NULL);
} else {
LinkOperationalStateRange range;
link_required_operstate_for_online(link, &range);
const char *min_str = link_operstate_to_string(range.min);
const char *max_str = link_operstate_to_string(range.max);
if (range.min == range.max)
r = metric_build_send_string(
context,
link->ifname,
min_str,
/* fields= */ NULL);
else {
_cleanup_free_ char *value = NULL;
if (asprintf(&value, "%s:%s", min_str, max_str) < 0)
return -ENOMEM;
r = metric_build_send_string(
context,
link->ifname,
value,
/* fields= */ NULL);
}
}
if (r < 0)
return r;
}
return 0;
}
/* Keep metrics ordered alphabetically */
static const MetricFamily network_metric_family_table[] = {
{
@@ -143,6 +194,12 @@ static const MetricFamily network_metric_family_table[] = {
.type = METRIC_FAMILY_TYPE_STRING,
.generate = link_oper_state_build_json,
},
{
.name = METRIC_IO_SYSTEMD_NETWORK_PREFIX "RequiredForOnline",
.description = "Per interface metric: required operational state for online, or 'no' if not required",
.type = METRIC_FAMILY_TYPE_STRING,
.generate = required_for_online_build_json,
},
{}
};
+1 -1
View File
@@ -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 */