]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: add service-log-{level,target} verbs
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 7 Sep 2020 19:25:24 +0000 (21:25 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 12 Sep 2020 08:22:51 +0000 (10:22 +0200)
Heavily inspired by #15622. This adds:
  systemctl service-log-level systemd-resolved
  systemctl service-log-level systemd-resolved info
  systemctl service-log-target systemd-resolved
  systemctl service-log-target systemd-resolved console

We already have systemctl verbs log-level, log-target, and service-watchdogs.
Those two new verbs tie nicely into this scheme.

man/org.freedesktop.LogControl1.xml
man/systemctl.xml
man/systemd.service.xml
src/systemctl/systemctl.c

index 5944061f99393fa3e5468043071c55ddc566c093..a51b7b01e1f25de133972fff5296c93980731279 100644 (file)
@@ -24,8 +24,8 @@
     <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
@@ -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 <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>
index 802824d43817a130dbde2eb0b470cb7bf43ab135..dc02fdcb86ec256ef31df79d408bfebbfe10559b 100644 (file)
@@ -550,6 +550,62 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
           </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>
 
index 124fa383aba5e9f52bbdebe2e07ae55900fb390b..d11e37da840bac2783ffa69deb5e10e326e0565d 100644 (file)
       <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>
 
index 7057049c60f689eb20558072f7e7d8371122aacf..5f540eabb8c7c73368f13d5720ed88123c678ee7 100644 (file)
@@ -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         },