core: add kernel/userspace/finish boot timestamps to io.systemd.Manager metrics
This commit adds the boot timeline (MANAGER_TIMESTAMP_KERNEL/USERSPACE/FINISH) as metrics. The kernel CLOCK_MONOTONIC value is 0 by definition, so only its .Realtime is reported. For userspace and finish report both .Realtime and .Monotonic. The naming follows D-Bus.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "manager.h"
|
||||
#include "metrics.h"
|
||||
#include "service.h"
|
||||
#include "string-util.h"
|
||||
#include "unit-def.h"
|
||||
#include "unit.h"
|
||||
#include "varlink-metrics.h"
|
||||
@@ -97,6 +98,59 @@ static int version_build_json(const MetricFamily *mf, sd_varlink *vl, void *user
|
||||
/* fields= */ NULL);
|
||||
}
|
||||
|
||||
static int boot_timestamp_build_json(
|
||||
const MetricFamily *mf,
|
||||
sd_varlink *vl,
|
||||
const dual_timestamp *t,
|
||||
bool with_monotonic) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(mf && mf->name);
|
||||
assert(vl);
|
||||
assert(t);
|
||||
|
||||
if (timestamp_is_set(t->realtime)) {
|
||||
r = metric_build_send_unsigned(
|
||||
mf, /* the .Realtime metric family entry */
|
||||
vl,
|
||||
/* object= */ NULL,
|
||||
t->realtime,
|
||||
/* fields= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (with_monotonic && timestamp_is_set(t->monotonic)) {
|
||||
assert(endswith(mf[1].name, ".Monotonic"));
|
||||
r = metric_build_send_unsigned(
|
||||
mf + 1, /* the .Monotonic sibling is the next entry */
|
||||
vl,
|
||||
/* object= */ NULL,
|
||||
t->monotonic,
|
||||
/* fields= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kernel_timestamp_build_json(const MetricFamily *mf, sd_varlink *vl, void *userdata) {
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
return boot_timestamp_build_json(mf, vl, &manager->timestamps[MANAGER_TIMESTAMP_KERNEL], /* with_monotonic= */ false);
|
||||
}
|
||||
|
||||
static int userspace_timestamp_build_json(const MetricFamily *mf, sd_varlink *vl, void *userdata) {
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
return boot_timestamp_build_json(mf, vl, &manager->timestamps[MANAGER_TIMESTAMP_USERSPACE], /* with_monotonic= */ true);
|
||||
}
|
||||
|
||||
static int finish_timestamp_build_json(const MetricFamily *mf, sd_varlink *vl, void *userdata) {
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
return boot_timestamp_build_json(mf, vl, &manager->timestamps[MANAGER_TIMESTAMP_FINISH], /* with_monotonic= */ true);
|
||||
}
|
||||
|
||||
static int state_change_timestamp_build_json(const MetricFamily *mf, sd_varlink *vl, void *userdata) {
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
Unit *unit;
|
||||
@@ -403,6 +457,19 @@ static const MetricFamily metric_family_table[] = {
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = active_timestamp_build_json,
|
||||
},
|
||||
{
|
||||
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "FinishTimestamp.Realtime",
|
||||
.description = "CLOCK_REALTIME microseconds at which userspace finished booting",
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = finish_timestamp_build_json,
|
||||
},
|
||||
{
|
||||
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "FinishTimestamp.Monotonic",
|
||||
.description = "CLOCK_MONOTONIC microseconds at which userspace finished booting",
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = NULL,
|
||||
},
|
||||
/* Keep those ↑ in sync with finish_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",
|
||||
@@ -415,6 +482,12 @@ static const MetricFamily metric_family_table[] = {
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = jobs_queued_build_json,
|
||||
},
|
||||
{
|
||||
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "KernelTimestamp.Realtime",
|
||||
.description = "CLOCK_REALTIME microseconds at which the kernel started (CLOCK_MONOTONIC == 0)",
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = kernel_timestamp_build_json,
|
||||
},
|
||||
{
|
||||
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "NRestarts",
|
||||
.description = "Per unit metric: number of restarts",
|
||||
@@ -481,6 +554,19 @@ static const MetricFamily metric_family_table[] = {
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = units_total_build_json,
|
||||
},
|
||||
{
|
||||
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "UserspaceTimestamp.Realtime",
|
||||
.description = "CLOCK_REALTIME microseconds at which userspace was reached",
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = userspace_timestamp_build_json,
|
||||
},
|
||||
{
|
||||
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "UserspaceTimestamp.Monotonic",
|
||||
.description = "CLOCK_MONOTONIC microseconds at which userspace was reached",
|
||||
.type = METRIC_FAMILY_TYPE_GAUGE,
|
||||
.generate = NULL,
|
||||
},
|
||||
/* Keep those ↑ in sync with userspace_timestamp_build_json(). */
|
||||
{
|
||||
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "Version",
|
||||
.description = "Version of systemd",
|
||||
|
||||
@@ -85,6 +85,19 @@ metrics_version="$(varlinkctl call --more /run/systemd/report/io.systemd.Manager
|
||||
[ -n "$metrics_version" ]
|
||||
systemctl --version | grep -F "($metrics_version)" >/dev/null
|
||||
|
||||
# Boot timeline timestamps. The kernel CLOCK_MONOTONIC is 0 by definition, so only its realtime is
|
||||
# reported; userspace reports both realtime and monotonic. We don't check FinishTimestamp here:
|
||||
# the test runs as a service, so manager_check_finished() typically hasn't fired yet and the
|
||||
# timestamp is unset (the metric is then suppressed). Likewise KernelTimestamp is cleared when
|
||||
# systemd runs inside a container (see main.c), so the metric is suppressed there too.
|
||||
manager_metrics="$(varlinkctl call --more /run/systemd/report/io.systemd.Manager io.systemd.Metrics.List {})"
|
||||
metric_value() { echo "$manager_metrics" | jq --seq -r "select(.name == \"io.systemd.Manager.$1\") | .value | tostring"; }
|
||||
if ! systemd-detect-virt --quiet --container; then
|
||||
[ "$(metric_value KernelTimestamp.Realtime)" -gt 0 ]
|
||||
fi
|
||||
[ "$(metric_value UserspaceTimestamp.Realtime)" -gt 0 ]
|
||||
[ "$(metric_value UserspaceTimestamp.Monotonic)" -gt 0 ]
|
||||
|
||||
# test io.systemd.Basic.MachineInfo.* metrics, sourced from /etc/machine-info
|
||||
if [ -e /etc/machine-info ]; then
|
||||
MACHINE_INFO_BACKUP="$(mktemp)"
|
||||
|
||||
Reference in New Issue
Block a user