<title>Introduction</title>
<para><interfacename>org.freedesktop.LogControl1</interfacename> 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
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> suite.</para>
<para>It is assumed that those settings are global for the whole program, so a fixed object path is
It is a short string that identifies the program that is the source of log messages that is passed to
the <citerefentry project="man-pages"><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry> call.
</para>
-
- <para>Note: <command>journalctl</command> option <option>-p</option>/<option>--priority=</option> may
- be used to filter log messages by log level, option <option>-t</option>/<option>--identifier=</option>
- may be used to by the syslog identifier, and filters like <literal>_TRANSPORT=syslog</literal>,
- <literal>_TRANSPORT=journal</literal>, and <literal>_TRANSPORT=kernel</literal> may be used to filter
- messages by the mechanism through which they reached <command>systemd-journald</command>.</para>
</refsect2>
</refsect1>
+
+ <refsect1>
+ <title>Tools</title>
+
+ <para><command>journalctl</command> option <option>-p</option>/<option>--priority=</option> may be used
+ to filter log messages by log level, option <option>-t</option>/<option>--identifier=</option> may be
+ used to by the syslog identifier, and filters like <literal>_TRANSPORT=syslog</literal>,
+ <literal>_TRANSPORT=journal</literal>, and <literal>_TRANSPORT=kernel</literal> may be used to filter
+ messages by the mechanism through which they reached <command>systemd-journald</command>.</para>
+
+ <para><command>systemctl log-level</command> and <command>systemctl log-target</command> verbs may be
+ used to query and set the <varname>LogLevel</varname> and <varname>LogTarget</varname> properties of the
+ service manager. <command>systemctl service-log-level</command> and <command>systemctl
+ service-log-target</command> may similarly be used for individual services. (Services must have the
+ <varname>BusName=</varname> property set and must implement the interface described here. See
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details about <varname>BusName=</varname>.)</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
</refentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>service-log-level</command> <replaceable>SERVICE</replaceable> [<replaceable>LEVEL</replaceable>]</term>
+
+ <listitem><para>If the <replaceable>LEVEL</replaceable> argument is not given, print the current
+ log level as reported by service <replaceable>SERVICE</replaceable>.</para>
+
+ <para>If the optional argument <replaceable>LEVEL</replaceable> is provided, then change the
+ current log level of the service to <replaceable>LEVEL</replaceable>. The log level should be a
+ typical syslog log level, i.e. a value in the range 0…7 or one of the strings
+ <constant>emerg</constant>, <constant>alert</constant>, <constant>crit</constant>,
+ <constant>err</constant>, <constant>warning</constant>, <constant>notice</constant>,
+ <constant>info</constant>, <constant>debug</constant>; see <citerefentry
+ project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ for details.</para>
+
+ <para>The service must have the appropriate
+ <varname>BusName=<replaceable>destination</replaceable></varname> property and also implement the
+ generic
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ interface. (<filename>systemctl</filename> will use the generic D-Bus protocol to access the
+ <interfacename>org.freedesktop.LogControl1.LogLevel</interfacename> interface for the D-Bus name
+ <replaceable>destination</replaceable>.)</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>service-log-target</command> <replaceable>SERVICE</replaceable> [<replaceable>TARGET</replaceable>]</term>
+
+ <listitem><para>If the <replaceable>TARGET</replaceable> argument is not given, print the current
+ log target as reported by service <replaceable>SERVICE</replaceable>.</para>
+
+ <para>If the optional argument <replaceable>TARGET</replaceable> is provided, then change the
+ current log target of the service to <replaceable>TARGET</replaceable>. The log target should be
+ one of the strings <constant>console</constant> (for log output to the service's standard error
+ stream), <constant>kmsg</constant> (for log output to the kernel log buffer),
+ <constant>journal</constant> (for log output to
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ using the native journal protocol), <constant>syslog</constant> (for log output to the classic
+ syslog socket <filename>/dev/log</filename>), <constant>null</constant> (for no log output
+ whatsoever) or <constant>auto</constant> (for an automatically determined choice, typically
+ equivalent to <constant>console</constant> if the service is invoked interactively, and
+ <constant>journal</constant> or <constant>syslog</constant> otherwise).</para>
+
+ <para>For most services, only a small subset of log targets make sense. In particular, most
+ "normal" services should only implement <constant>console</constant>, <constant>journal</constant>,
+ and <constant>null</constant>. Anything else is only appropriate for low-level services that
+ are active in very early boot before proper logging is established.</para>
+
+ <para>The service must have the appropriate
+ <varname>BusName=<replaceable>destination</replaceable></varname> property and also implement the
+ generic
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ interface. (<filename>systemctl</filename> will use the generic D-Bus protocol to access the
+ <interfacename>org.freedesktop.LogControl1.LogLevel</interfacename> interface for the D-Bus name
+ <replaceable>destination</replaceable>.)</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><command>reset-failed [<replaceable>PATTERN</replaceable>…]</command></term>
<varlistentry>
<term><varname>BusName=</varname></term>
- <listitem><para>Takes a D-Bus bus name that this service is
- reachable as. This option is mandatory for services where
- <varname>Type=</varname> is set to
- <option>dbus</option>.</para>
+ <listitem><para>Takes a D-Bus destination name that this service shall use. This option is mandatory
+ for services where <varname>Type=</varname> is set to <option>dbus</option>. 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, <command>systemctl service-log-level/service-log-target</command> verbs make use of
+ this.</para>
</listitem>
</varlistentry>
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;
" 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"
{ "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 },