diff --git a/man/org.freedesktop.LogControl1.xml b/man/org.freedesktop.LogControl1.xml index 5944061f99..a51b7b01e1 100644 --- a/man/org.freedesktop.LogControl1.xml +++ b/man/org.freedesktop.LogControl1.xml @@ -24,8 +24,8 @@ Introduction org.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-level SERVICE [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-target SERVICE [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 },