Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2397,6 +2397,7 @@ subdir('src/quotacheck')
subdir('src/random-seed')
subdir('src/remount-fs')
subdir('src/repart')
subdir('src/report')
subdir('src/reply-password')
subdir('src/resolve')
subdir('src/rfkill')
Expand Down
2 changes: 2 additions & 0 deletions src/core/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,8 @@ typedef struct Manager {
* systemd-oomd to report changes in ManagedOOM settings (systemd client - oomd server). */
sd_varlink *managed_oom_varlink;

sd_varlink_server *metrics_varlink_server;

/* Reference to RestrictFileSystems= BPF program */
struct restrict_fs_bpf *restrict_fs;

Expand Down
1 change: 1 addition & 0 deletions src/core/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ libcore_sources = files(
'varlink-dynamic-user.c',
'varlink-execute.c',
'varlink-manager.c',
'varlink-metrics.c',
'varlink-unit.c',
)

Expand Down
173 changes: 173 additions & 0 deletions src/core/varlink-metrics.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */

#include "hashmap.h"
#include "manager.h"
#include "metrics.h"
#include "service.h"
#include "unit-def.h"
#include "unit.h"
#include "varlink-metrics.h"

static int unit_active_state_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_string(
context,
unit->id,
unit_active_state_to_string(unit_active_state(unit)),
/* field_pairs= */ NULL);
if (r < 0)
return r;
}

return 0;
}

static int unit_load_state_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_string(
context,
unit->id,
unit_load_state_to_string(unit->load_state),
/* field_pairs= */ NULL);
if (r < 0)
return r;
}

return 0;
}

static int nrestarts_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, SERVICE(unit)->n_restarts, /* field_pairs= */ NULL);
if (r < 0)
return r;
}

return 0;
}

static int units_by_type_total_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
int r;

assert(context);

for (UnitType type = 0; type < _UNIT_TYPE_MAX; type++) {
uint64_t counter = 0;

LIST_FOREACH(units_by_type, _u, manager->units_by_type[type])
counter++;

r = metric_build_send_unsigned(
context,
/* object= */ NULL,
counter,
STRV_MAKE("type", unit_type_to_string(type)));
if (r < 0)
return r;
}

return 0;
}

static int units_by_state_total_build_json(MetricFamilyContext *context, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
UnitActiveState counters[_UNIT_ACTIVE_STATE_MAX] = {};
Unit *unit;
char *key;
int r;

assert(context);

/* TODO need a rework probably with state counter */
HASHMAP_FOREACH_KEY(unit, key, manager->units) {
/* ignore aliases */
if (key != unit->id)
continue;

counters[unit_active_state(unit)]++;
}

for (UnitActiveState state = 0; state < _UNIT_ACTIVE_STATE_MAX; state++) {
r = metric_build_send_unsigned(
context,
/* object= */ NULL,
counters[state],
STRV_MAKE("state", unit_active_state_to_string(state)));
if (r < 0)
return r;
}

return 0;
}

const MetricFamily metric_family_table[] = {
// Keep metrics ordered alphabetically
{
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "nrestarts",
.description = "Per unit metric: number of restarts",
.type = METRIC_FAMILY_TYPE_COUNTER,
.generate_cb = nrestarts_build_json,
},
{
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unit_active_state",
.description = "Per unit metric: active state",
.type = METRIC_FAMILY_TYPE_STRING,
.generate_cb = unit_active_state_build_json,
},
{
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unit_load_state",
.description = "Per unit metric: load state",
.type = METRIC_FAMILY_TYPE_STRING,
.generate_cb = unit_load_state_build_json,
},
{
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "units_by_state_total",
.description = "Total number of units of different state",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate_cb = units_by_state_total_build_json,
},
{
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "units_by_type_total",
.description = "Total number of units of different types",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate_cb = units_by_type_total_build_json,
},
{}
};

int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return metrics_method_describe(metric_family_table, link, parameters, flags, userdata);
}

int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return metrics_method_list(metric_family_table, link, parameters, flags, userdata);
}
10 changes: 10 additions & 0 deletions src/core/varlink-metrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include "sd-varlink.h"
#include "sd-json.h"

#define METRIC_IO_SYSTEMD_MANAGER_PREFIX "io.systemd.Manager."

int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
44 changes: 41 additions & 3 deletions src/core/varlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "constants.h"
#include "errno-util.h"
#include "manager.h"
#include "metrics.h"
#include "path-util.h"
#include "pidref.h"
#include "string-util.h"
Expand All @@ -18,6 +19,7 @@
#include "varlink-io.systemd.UserDatabase.h"
#include "varlink-io.systemd.service.h"
#include "varlink-manager.h"
#include "varlink-metrics.h"
#include "varlink-serialize.h"
#include "varlink-unit.h"
#include "varlink-util.h"
Expand Down Expand Up @@ -423,8 +425,26 @@ int manager_setup_varlink_server(Manager *m) {
return 1;
}

static int manager_setup_varlink_metrics_server(Manager *m) {
sd_varlink_server_flags_t flags = SD_VARLINK_SERVER_INHERIT_USERDATA;
int r;

assert(m);

if (MANAGER_IS_SYSTEM(m))
flags |= SD_VARLINK_SERVER_ACCOUNT_UID;

r = metrics_setup_varlink_server(
&m->metrics_varlink_server, flags, m->event, vl_method_list, vl_method_describe, m);
if (r < 0)
return r;

return 0;
}

static int manager_varlink_init_system(Manager *m) {
int r;
_cleanup_free_ char *metrics_address = NULL;

assert(m);

Expand All @@ -433,16 +453,29 @@ static int manager_varlink_init_system(Manager *m) {
return log_error_errno(r, "Failed to set up varlink server: %m");
bool fresh = r > 0;

r = manager_setup_varlink_metrics_server(m);
if (r < 0)
return log_error_errno(r, "Failed to set up metrics varlink server: %m");
bool metrics_fresh = r > 0;

r = runtime_directory_generic(m->runtime_scope, "systemd/report/io.systemd.Manager", &metrics_address);
if (r < 0)
return r;

if (!MANAGER_IS_TEST_RUN(m)) {
FOREACH_STRING(address,
"/run/systemd/userdb/io.systemd.DynamicUser",
VARLINK_PATH_MANAGED_OOM_SYSTEM,
"/run/systemd/io.systemd.Manager") {
"/run/systemd/io.systemd.Manager",
metrics_address) {

sd_varlink_server *server = streq(address, metrics_address) ? m->metrics_varlink_server : m->varlink_server;
fresh = streq(address, metrics_address) ? metrics_fresh : fresh;
/* We might have got sockets through deserialization. Do not bind to them twice. */
if (!fresh && varlink_server_contains_socket(m->varlink_server, address))
if (!fresh && varlink_server_contains_socket(server, address))
continue;

r = sd_varlink_server_listen_address(m->varlink_server, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
r = sd_varlink_server_listen_address(server, address, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
if (r < 0)
return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address);
}
Expand Down Expand Up @@ -479,6 +512,10 @@ static int manager_varlink_init_user(Manager *m) {
return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address);
}

r = manager_setup_varlink_metrics_server(m);
if (r < 0)
return log_error_errno(r, "Failed to set up metrics varlink server: %m");

return manager_varlink_managed_oom_connect(m);
}

Expand All @@ -497,6 +534,7 @@ void manager_varlink_done(Manager *m) {

m->varlink_server = sd_varlink_server_unref(m->varlink_server);
m->managed_oom_varlink = sd_varlink_close_unref(m->managed_oom_varlink);
m->metrics_varlink_server = sd_varlink_server_unref(m->metrics_varlink_server);
}

void manager_varlink_send_pending_reload_message(Manager *m) {
Expand Down
9 changes: 9 additions & 0 deletions src/report/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later

executables += [
executable_template + {
'name' : 'systemd-report',
'public' : true,
'sources' : files('report.c'),
},
]
Loading
Loading