logind: expose session and suspend metrics

logind now implements io.systemd.Metrics on
/run/systemd/report/io.systemd.Login, via the new
systemd-logind-metrics.socket, and reports:

- io.systemd.Login.SessionsStarted: counter of sessions started since
  boot, by session class (field class=)
- io.systemd.Login.CurrentSessions: gauge of current sessions, including
  those in closing state, by session class (field class=)
- io.systemd.Login.SuspendCounter: counter of suspend cycles, as reported
  by the kernel in /sys/power/suspend_stats/ (field result=success|fail)
This commit is contained in:
Lennart Poettering committed 2026-10-10 10:40:03 +02:00
1 parent 8242f08ecb
commit 5d7cb3878c
10 files changed
+312 -13

No files matched your search

+4 -1
View File
@@ -1128,7 +1128,10 @@ manpages = [
''],
['systemd-keyutil', '1', [], ''],
['systemd-localed.service', '8', ['systemd-localed'], 'ENABLE_LOCALED'],
['systemd-logind.service', '8', ['systemd-logind'], 'ENABLE_LOGIND'],
['systemd-logind.service',
'8',
['systemd-logind', 'systemd-logind-metrics.socket'],
'ENABLE_LOGIND'],
['systemd-loop@.service', '8', [], ''],
['systemd-machine-id-commit.service', '8', [], ''],
['systemd-machine-id-setup', '1', [], ''],
+41 -1
View File
@@ -3,7 +3,8 @@
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-logind.service" conditional='ENABLE_LOGIND'>
<refentry id="systemd-logind.service" conditional='ENABLE_LOGIND'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-logind.service</title>
@@ -17,12 +18,14 @@
<refnamediv>
<refname>systemd-logind.service</refname>
<refname>systemd-logind-metrics.socket</refname>
<refname>systemd-logind</refname>
<refpurpose>Login manager</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-logind.service</filename></para>
<para><filename>systemd-logind-metrics.socket</filename></para>
<para><filename>/usr/lib/systemd/systemd-logind</filename></para>
</refsynopsisdiv>
@@ -104,6 +107,43 @@
Desktop Environments</ulink>.</para>
</refsect1>
<refsect1>
<title>Metrics</title>
<para><command>systemd-logind</command> is a metrics source for
<citerefentry><refentrytitle>systemd-report</refentrytitle><manvolnum>1</manvolnum></citerefentry> and
reports the following metrics:</para>
<variablelist>
<varlistentry>
<term><literal>io.systemd.Login.CurrentSessions</literal></term>
<listitem><para>A gauge metric with the number of current sessions. The metric field
<varname>class</varname> is set to the session class, see <varname>$XDG_SESSION_CLASS</varname> in
<citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
<varlistentry>
<term><literal>io.systemd.Login.SessionsStarted</literal></term>
<listitem><para>A counter metric with the number of sessions started since boot, by session class.
Sessions are counted under the class they have been created with. The metric field
<varname>class</varname> is set as above. This counter is kept across restarts of the service, but
reset on reboot.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
<varlistentry>
<term><literal>io.systemd.Login.SuspendCounter</literal></term>
<listitem><para>A counter metric with the number of suspend cycles since boot. The metric field
<varname>result</varname> is set to <literal>success</literal> or <literal>fail</literal>.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Signal</title>
<variablelist>
+1
View File
@@ -28,6 +28,7 @@ enable systemd-homed-activate.service
enable systemd-journalctl-metrics.socket
enable systemd-journald-audit.socket
enable systemd-journald-metrics.socket
enable systemd-logind-metrics.socket
enable systemd-mountfsd.socket
enable systemd-network-generator.service
enable systemd-networkd.service
+207
View File
@@ -0,0 +1,207 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-event.h"
#include "sd-json.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "argv-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hashmap.h"
#include "log.h"
#include "logind.h"
#include "logind-counters.h"
#include "logind-metrics.h"
#include "logind-session.h"
#include "metrics.h"
#include "parse-util.h"
#include "string-util.h"
#include "strv.h"
#include "virt.h"
#define METRIC_IO_SYSTEMD_LOGIN_PREFIX "io.systemd.Login."
static int send_per_class(const MetricFamily *mf, sd_varlink *link, SessionClass class, uint64_t value) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL;
int r;
r = sd_json_buildo(&fields, SD_JSON_BUILD_PAIR_STRING("class", session_class_to_string(class)));
if (r < 0)
return r;
return metric_build_send_unsigned(mf, link, /* object= */ NULL, value, fields);
}
static int current_sessions_generate(const MetricFamily *mf, sd_varlink *link, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
uint64_t n[_SESSION_CLASS_MAX] = {};
Session *s;
int r;
assert(mf);
assert(link);
/* Sessions in closing state are included */
HASHMAP_FOREACH(s, m->sessions)
if (s->started && s->class >= 0)
n[s->class]++;
for (SessionClass c = 0; c < _SESSION_CLASS_MAX; c++) {
if (c == SESSION_NONE)
continue;
r = send_per_class(mf, link, c, n[c]);
if (r < 0)
return r;
}
return 0;
}
static int sessions_started_generate(const MetricFamily *mf, sd_varlink *link, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
int r;
assert(mf);
assert(link);
if (!m->counters)
return 0;
for (SessionClass c = 0; c < _SESSION_CLASS_MAX; c++) {
if (c == SESSION_NONE)
continue;
r = send_per_class(mf, link, c, m->counters->n_sessions_started[c]);
if (r < 0)
return r;
}
return 0;
}
static int suspend_counter_generate(const MetricFamily *mf, sd_varlink *link, void *userdata) {
int r;
assert(mf);
assert(link);
if (detect_container() > 0)
return 0;
FOREACH_STRING(result, "success", "fail") {
_cleanup_free_ char *p = NULL, *s = NULL;
uint64_t v;
p = strjoin("/sys/power/suspend_stats/", result);
if (!p)
return -ENOMEM;
r = read_one_line_file(p, &s);
if (r == -ENOENT) {
log_debug_errno(r, "%s does not exist, not reporting suspend counters.", p);
return 0;
}
if (r < 0)
return log_debug_errno(r, "Failed to read %s: %m", p);
r = safe_atou64(s, &v);
if (r < 0)
return log_debug_errno(r, "Failed to parse %s: %m", p);
_cleanup_(sd_json_variant_unrefp) sd_json_variant *fields = NULL;
r = sd_json_buildo(&fields, SD_JSON_BUILD_PAIR_STRING("result", result));
if (r < 0)
return r;
r = metric_build_send_unsigned(mf, link, /* object= */ NULL, v, fields);
if (r < 0)
return r;
}
return 0;
}
static const MetricFamily login_metric_family_table[] = {
/* Keep metrics ordered alphabetically */
{
.name = METRIC_IO_SYSTEMD_LOGIN_PREFIX "CurrentSessions",
.description = "Number of current sessions, including closing ones, by session class",
.type = METRIC_FAMILY_TYPE_GAUGE,
.generate = current_sessions_generate,
},
{
.name = METRIC_IO_SYSTEMD_LOGIN_PREFIX "SessionsStarted",
.description = "Number of sessions started since boot, by session class",
.type = METRIC_FAMILY_TYPE_COUNTER,
.generate = sessions_started_generate,
},
{
.name = METRIC_IO_SYSTEMD_LOGIN_PREFIX "SuspendCounter",
.description = "Number of suspend cycles since boot, by result (result=success|fail)",
.type = METRIC_FAMILY_TYPE_COUNTER,
.generate = suspend_counter_generate,
},
{}
};
static int vl_method_metrics_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return metrics_method_describe(login_metric_family_table, link, parameters, flags, userdata);
}
static int vl_method_metrics_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return metrics_method_list(login_metric_family_table, link, parameters, flags, userdata);
}
int manager_metrics_init(Manager *m, int fd) {
_unused_ _cleanup_close_ int fd_close = fd; /* take possession */
int r;
assert(m);
if (m->metrics_varlink_server)
return 0;
if (fd < 0 && invoked_by_systemd()) {
log_debug("systemd-logind-metrics.socket seems to be disabled, not installing metrics varlink server.");
return 0;
}
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
r = metrics_setup_varlink_server(
&s,
SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA,
m->event,
SD_EVENT_PRIORITY_NORMAL,
vl_method_metrics_list,
vl_method_metrics_describe,
m);
if (r < 0)
return log_error_errno(r, "Failed to set up metrics varlink server: %m");
if (fd < 0) {
r = sd_varlink_server_listen_address(
s,
"/run/systemd/report/io.systemd.Login",
0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
if (ERRNO_IS_NEG_PRIVILEGE(r)) {
log_warning_errno(r, "Failed to bind to metrics varlink socket, ignoring: %m");
return 0;
}
} else
r = sd_varlink_server_listen_fd(s, fd);
if (r < 0)
return log_error_errno(r, "Failed to bind to metrics varlink socket: %m");
TAKE_FD(fd_close);
m->metrics_varlink_server = TAKE_PTR(s);
return 0;
}
void manager_metrics_done(Manager *m) {
assert(m);
m->metrics_varlink_server = sd_varlink_server_unref(m->metrics_varlink_server);
}
+7
View File
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "logind-forward.h"
int manager_metrics_init(Manager *m, int fd);
void manager_metrics_done(Manager *m);
+23 -11
View File
@@ -31,6 +31,7 @@
#include "logind-counters.h"
#include "logind-dbus.h"
#include "logind-device.h"
#include "logind-metrics.h"
#include "logind-seat.h"
#include "logind-session-device.h"
#include "logind-user.h"
@@ -174,6 +175,7 @@ static Manager* manager_free(Manager *m) {
hashmap_free(m->polkit_registry);
manager_varlink_done(m);
manager_metrics_done(m);
m->counters = munmap_safe(m->counters, sizeof(*m->counters));
@@ -530,8 +532,8 @@ static int manager_attach_session_fd_one_consume(Manager *m, const char *fdname,
s = hashmap_get(m->sessions, id);
if (!s) {
/* If the session doesn't exist anymore, let's simply close this fd. */
r = log_debug_errno(SYNTHETIC_ERRNO(ENXIO),
"Cannot attach fd '%s' to unknown session '%s', ignoring.", fdname, id);
log_debug("Cannot attach fd '%s' to unknown session '%s', ignoring.", fdname, id);
r = 0;
goto fail_close;
}
@@ -588,12 +590,13 @@ static int manager_enumerate_sessions(Manager *m) {
return r;
}
static int manager_enumerate_fds(Manager *m, int *ret_varlink_fd) {
static int manager_enumerate_fds(Manager *m, int *ret_varlink_fd, int *ret_metrics_fd) {
_cleanup_strv_free_ char **fdnames = NULL;
int varlink_fd = -EBADF, n, r = 0;
int varlink_fd = -EBADF, metrics_fd = -EBADF, n;
assert(m);
assert(ret_varlink_fd);
assert(ret_metrics_fd);
n = sd_listen_fds_with_names(/* unset_environment= */ true, &fdnames);
if (n < 0)
@@ -608,13 +611,18 @@ static int manager_enumerate_fds(Manager *m, int *ret_varlink_fd) {
continue;
}
RET_GATHER(r, manager_attach_session_fd_one_consume(m, fdnames[i], fd));
if (streq(fdnames[i], "varlink-metrics")) {
assert(metrics_fd < 0);
metrics_fd = fd;
continue;
}
(void) manager_attach_session_fd_one_consume(m, fdnames[i], fd);
}
if (r >= 0)
*ret_varlink_fd = varlink_fd;
return r;
*ret_varlink_fd = varlink_fd;
*ret_metrics_fd = metrics_fd;
return 0;
}
static int manager_enumerate_inhibitors(Manager *m) {
@@ -1219,7 +1227,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
}
static int manager_startup(Manager *m) {
_cleanup_close_ int varlink_fd = -EBADF;
_cleanup_close_ int varlink_fd = -EBADF, metrics_fd = -EBADF;
int r;
Seat *seat;
Session *session;
@@ -1279,7 +1287,7 @@ static int manager_startup(Manager *m) {
if (r < 0)
log_warning_errno(r, "Session enumeration failed: %m");
r = manager_enumerate_fds(m, &varlink_fd);
r = manager_enumerate_fds(m, &varlink_fd, &metrics_fd);
if (r < 0)
log_warning_errno(r, "File descriptor enumeration failed: %m");
@@ -1295,6 +1303,10 @@ static int manager_startup(Manager *m) {
if (r < 0)
return r;
r = manager_metrics_init(m, TAKE_FD(metrics_fd));
if (r < 0)
return r;
manager_load_scheduled_shutdown(m);
/* Remove stale objects before we start them */
+1
View File
@@ -140,6 +140,7 @@ typedef struct Manager {
dual_timestamp init_ts;
sd_varlink_server *varlink_server;
sd_varlink_server *metrics_varlink_server;
LoginCounters *counters;
} Manager;
+1
View File
@@ -16,6 +16,7 @@ systemd_logind_export_sources = files(
'logind-dbus.c',
'logind-device.c',
'logind-inhibit.c',
'logind-metrics.c',
'logind-polkit.c',
'logind-seat-dbus.c',
'logind-seat.c',
+4
View File
@@ -538,6 +538,10 @@ units = [
'conditions' : ['ENABLE_LOCALED'],
'symlinks' : ['dbus-org.freedesktop.locale1.service'],
},
{
'file': 'systemd-logind-metrics.socket',
'conditions': ['ENABLE_LOGIND'],
},
{
'file': 'systemd-logind-varlink.socket',
'conditions': ['ENABLE_LOGIND'],
+23
View File
@@ -0,0 +1,23 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=User Login Management Metrics Varlink Socket
Documentation=man:systemd-logind.service(8)
[Socket]
ListenStream=/run/systemd/report/io.systemd.Login
FileDescriptorName=varlink-metrics
SocketMode=0666
Service=systemd-logind.service
XAttrEntryPoint=user.varlink=entrypoint
XAttrListen=user.varlink=listen
[Install]
WantedBy=sockets.target