Introductionorg.freedesktop.LogControl1 is a generic interface that is intended
- to be used by any daemon which should allow setting the log level and target over D-Bus. It is implemented
- by various daemons that are part of the
+ to be used by any daemon which allows the log level and target to be set over D-Bus. It is implemented by
+ various daemons that are part of the
systemd1 suite.It is assumed that those settings are global for the whole program, so a fixed object path is
@@ -95,12 +95,35 @@ node /org/freedesktop/LogControl1 {
It is a short string that identifies the program that is the source of log messages that is passed to
the syslog3 call.
-
- Note: journalctl option / may
- be used to filter log messages by log level, option /
- may be used to by the syslog identifier, and filters like _TRANSPORT=syslog,
- _TRANSPORT=journal, and _TRANSPORT=kernel may be used to filter
- messages by the mechanism through which they reached systemd-journald.
+
+
+ Tools
+
+ journalctl option / may be used
+ to filter log messages by log level, option / may be
+ used to by the syslog identifier, and filters like _TRANSPORT=syslog,
+ _TRANSPORT=journal, and _TRANSPORT=kernel may be used to filter
+ messages by the mechanism through which they reached systemd-journald.
+
+ systemctl log-level and systemctl log-target verbs may be
+ used to query and set the LogLevel and LogTarget properties of the
+ service manager. systemctl service-log-level and systemctl
+ service-log-target may similarly be used for individual services. (Services must have the
+ BusName= property set and must implement the interface described here. See
+ systemd.service5
+ for details about BusName=.)
+
+
+
+ See Also
+
+ systemd1,
+ journalctl1,
+ systemctl1,
+ systemd.service5,
+ syslog3
+
+
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 802824d438..dc02fdcb86 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -550,6 +550,62 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
+
+ service-log-levelSERVICE [LEVEL]
+
+ If the LEVEL argument is not given, print the current
+ log level as reported by service SERVICE.
+
+ If the optional argument LEVEL is provided, then change the
+ current log level of the service to LEVEL. The log level should be a
+ typical syslog log level, i.e. a value in the range 0…7 or one of the strings
+ emerg, alert, crit,
+ err, warning, notice,
+ info, debug; see syslog3
+ for details.
+
+ The service must have the appropriate
+ BusName=destination property and also implement the
+ generic
+ org.freedesktop.LogControl15
+ interface. (systemctl will use the generic D-Bus protocol to access the
+ org.freedesktop.LogControl1.LogLevel interface for the D-Bus name
+ destination.)
+
+
+
+ service-log-targetSERVICE [TARGET]
+
+ If the TARGET argument is not given, print the current
+ log target as reported by service SERVICE.
+
+ If the optional argument TARGET is provided, then change the
+ current log target of the service to TARGET. The log target should be
+ one of the strings console (for log output to the service's standard error
+ stream), kmsg (for log output to the kernel log buffer),
+ journal (for log output to
+ systemd-journald.service8
+ using the native journal protocol), syslog (for log output to the classic
+ syslog socket /dev/log), null (for no log output
+ whatsoever) or auto (for an automatically determined choice, typically
+ equivalent to console if the service is invoked interactively, and
+ journal or syslog otherwise).
+
+ For most services, only a small subset of log targets make sense. In particular, most
+ "normal" services should only implement console, journal,
+ and null. Anything else is only appropriate for low-level services that
+ are active in very early boot before proper logging is established.
+
+ The service must have the appropriate
+ BusName=destination property and also implement the
+ generic
+ org.freedesktop.LogControl15
+ interface. (systemctl will use the generic D-Bus protocol to access the
+ org.freedesktop.LogControl1.LogLevel interface for the D-Bus name
+ destination.)
+
+
reset-failed [PATTERN…]
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 124fa383ab..d11e37da84 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -292,10 +292,11 @@
BusName=
- Takes a D-Bus bus name that this service is
- reachable as. This option is mandatory for services where
- Type= is set to
- .
+ Takes a D-Bus destination name that this service shall use. This option is mandatory
+ for services where Type= is set to . It is recommended to
+ always set this property if known to make it easy to map the service name to the D-Bus destination.
+ In particular, systemctl service-log-level/service-log-target verbs make use of
+ this.
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 7057049c60..5f540eabb8 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -6327,6 +6327,98 @@ static int log_level(int argc, char *argv[], void *userdata) {
return 0;
}
+static int service_name_to_dbus(sd_bus *bus, const char *name, char **ret_dbus_name) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *bus_name = NULL;
+ int r;
+
+ /* First, look for the BusName= property */
+ _cleanup_free_ char *dbus_path = unit_dbus_path_from_name(name);
+ if (!dbus_path)
+ return log_oom();
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ dbus_path,
+ "org.freedesktop.systemd1.Service",
+ "BusName",
+ &error,
+ &bus_name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to obtain BusName= property of %s: %s",
+ name, bus_error_message(&error, r));
+
+ if (isempty(bus_name))
+ return log_error_errno(SYNTHETIC_ERRNO(ENOLINK),
+ "Unit %s doesn't declare BusName=.", name);
+
+ *ret_dbus_name = TAKE_PTR(bus_name);
+ return 0;
+}
+
+static int service_log_setting(int argc, char *argv[], void *userdata) {
+ sd_bus *bus;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *unit = NULL, *dbus_name = NULL;
+ int r;
+
+ assert(STR_IN_SET(argv[0], "service-log-level", "service-log-target"));
+ bool level = streq(argv[0], "service-log-level");
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ r = unit_name_mangle_with_suffix(argv[1], argv[0],
+ arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+ ".service", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
+
+ r = service_name_to_dbus(bus, unit, &dbus_name);
+ if (r < 0)
+ return r;
+
+ if (argc == 2) {
+ _cleanup_free_ char *value = NULL;
+
+ r = sd_bus_get_property_string(
+ bus,
+ dbus_name,
+ "/org/freedesktop/LogControl1",
+ "org.freedesktop.LogControl1",
+ level ? "LogLevel" : "LogTarget",
+ &error,
+ &value);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get log %s of service %s: %s",
+ level ? "level" : "target",
+ dbus_name, bus_error_message(&error, r));
+
+ puts(value);
+
+ } else {
+ assert(argc == 3);
+
+ r = sd_bus_set_property(
+ bus,
+ dbus_name,
+ "/org/freedesktop/LogControl1",
+ "org.freedesktop.LogControl1",
+ level ? "LogLevel" : "LogTarget",
+ &error,
+ "s",
+ argv[2]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set log %s of service %s to %s: %s",
+ level ? "level" : "target",
+ dbus_name, argv[2], bus_error_message(&error, r));
+ }
+
+ return 0;
+}
+
static int log_target(int argc, char *argv[], void *userdata) {
sd_bus *bus;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -7734,6 +7826,8 @@ static int systemctl_help(void) {
" freeze PATTERN... Freeze execution of unit processes\n"
" thaw PATTERN... Resume execution of a frozen unit\n"
" set-property UNIT PROPERTY=VALUE... Sets one or more properties of a unit\n"
+ " service-log-level SERVICE [LEVEL] Get/set logging threshold for service\n"
+ " service-log-target SERVICE [TARGET] Get/set logging target for service\n"
" reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
" units"
"\n%3$sUnit File Commands:%4$s\n"
@@ -9034,6 +9128,8 @@ static int systemctl_main(int argc, char *argv[]) {
{ "daemon-reexec", VERB_ANY, 1, VERB_ONLINE_ONLY, daemon_reload },
{ "log-level", VERB_ANY, 2, VERB_ONLINE_ONLY, log_level },
{ "log-target", VERB_ANY, 2, VERB_ONLINE_ONLY, log_target },
+ { "service-log-level", 2, 3, VERB_ONLINE_ONLY, service_log_setting },
+ { "service-log-target", 2, 3, VERB_ONLINE_ONLY, service_log_setting },
{ "service-watchdogs", VERB_ANY, 2, VERB_ONLINE_ONLY, service_watchdogs },
{ "show-environment", VERB_ANY, 1, VERB_ONLINE_ONLY, show_environment },
{ "set-environment", 2, VERB_ANY, VERB_ONLINE_ONLY, set_environment },