]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: apply LogLevelMax to messages about units
authorRyan Hendrickson <ryan.hendrickson@alum.mit.edu>
Fri, 30 Apr 2021 16:47:10 +0000 (12:47 -0400)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 6 May 2021 12:51:08 +0000 (14:51 +0200)
This commit applies the filtering imposed by LogLevelMax on a unit's
processes to messages logged by PID1 about the unit as well.

The target use case for this feature is a service that runs on a timer
many times an hour, where the system administrator decides that writing
a generic success message to the journal every few minutes or seconds
adds no diagnostic value and isn't worth the clutter or disk I/O.

(cherry picked from commit c2503e359a3a03b73acce0a92d27b1b8f54ff92c)

man/systemd.exec.xml
src/core/cgroup.c
src/core/execute.c
src/core/job.c
src/core/service.c
src/core/unit.c
src/core/unit.h
test/testsuite-04.units/silent-success.service [new file with mode: 0644]
test/units/testsuite-04.sh

index 5bb9af3e7da63682a8dd0affde0b04590d7fb6ea..4942d6e990ad9c226f7279cd26e6323fe3885051 100644 (file)
@@ -2651,7 +2651,8 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
         this option to configure the logging system to drop log messages of a specific service above the specified
         level. For example, set <varname>LogLevelMax=</varname><option>info</option> in order to turn off debug logging
         of a particularly chatty unit. Note that the configured level is applied to any log messages written by any
-        of the processes belonging to this unit, sent via any supported logging protocol. The filtering is applied
+        of the processes belonging to this unit, as well as any log messages written by the system manager process
+        (PID 1) in reference to this unit, sent via any supported logging protocol. The filtering is applied
         early in the logging pipeline, before any kind of further processing is done. Moreover, messages which pass
         through this filter successfully might still be dropped by filters applied at a later stage in the logging
         subsystem. For example, <varname>MaxLevelStore=</varname> configured in
index 96073b108b2e7674e88bd4b4936cf64bb0967a3a..3443f0844d6d20b15d0a5e8c381a2cb34f7a566a 100644 (file)
@@ -2786,11 +2786,10 @@ int unit_check_oomd_kill(Unit *u) {
                 return 0;
 
         if (n > 0)
-                log_struct(LOG_NOTICE,
-                           "MESSAGE_ID=" SD_MESSAGE_UNIT_OOMD_KILL_STR,
-                           LOG_UNIT_ID(u),
-                           LOG_UNIT_INVOCATION_ID(u),
-                           LOG_UNIT_MESSAGE(u, "systemd-oomd killed %"PRIu64" process(es) in this unit.", n));
+                log_unit_struct(u, LOG_NOTICE,
+                                "MESSAGE_ID=" SD_MESSAGE_UNIT_OOMD_KILL_STR,
+                                LOG_UNIT_INVOCATION_ID(u),
+                                LOG_UNIT_MESSAGE(u, "systemd-oomd killed %"PRIu64" process(es) in this unit.", n));
 
         return 1;
 }
@@ -2818,11 +2817,10 @@ int unit_check_oom(Unit *u) {
         if (!increased)
                 return 0;
 
-        log_struct(LOG_NOTICE,
-                   "MESSAGE_ID=" SD_MESSAGE_UNIT_OUT_OF_MEMORY_STR,
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   LOG_UNIT_MESSAGE(u, "A process of this unit has been killed by the OOM killer."));
+        log_unit_struct(u, LOG_NOTICE,
+                        "MESSAGE_ID=" SD_MESSAGE_UNIT_OUT_OF_MEMORY_STR,
+                        LOG_UNIT_INVOCATION_ID(u),
+                        LOG_UNIT_MESSAGE(u, "A process of this unit has been killed by the OOM killer."));
 
         if (UNIT_VTABLE(u)->notify_cgroup_oom)
                 UNIT_VTABLE(u)->notify_cgroup_oom(u);
index a016180cbb549a202c723d9be6614b8a42951705..d5954cac07ac6c1e330a788e713b73cb7a5cf5ab 100644 (file)
@@ -4309,24 +4309,23 @@ static int exec_child(
         r = find_executable_full(command->path, false, &executable, &executable_fd);
         if (r < 0) {
                 if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
-                        log_struct_errno(LOG_INFO, r,
-                                         "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
-                                         LOG_UNIT_ID(unit),
-                                         LOG_UNIT_INVOCATION_ID(unit),
-                                         LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",
-                                                          command->path),
-                                         "EXECUTABLE=%s", command->path);
+                        log_unit_struct_errno(unit, LOG_INFO, r,
+                                              "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
+                                              LOG_UNIT_INVOCATION_ID(unit),
+                                              LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",
+                                                               command->path),
+                                              "EXECUTABLE=%s", command->path);
                         return 0;
                 }
 
                 *exit_status = EXIT_EXEC;
-                return log_struct_errno(LOG_INFO, r,
-                                        "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
-                                        LOG_UNIT_ID(unit),
-                                        LOG_UNIT_INVOCATION_ID(unit),
-                                        LOG_UNIT_MESSAGE(unit, "Failed to locate executable %s: %m",
-                                                         command->path),
-                                        "EXECUTABLE=%s", command->path);
+
+                return log_unit_struct_errno(unit, LOG_INFO, r,
+                                             "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
+                                             LOG_UNIT_INVOCATION_ID(unit),
+                                             LOG_UNIT_MESSAGE(unit, "Failed to locate executable %s: %m",
+                                                              command->path),
+                                             "EXECUTABLE=%s", command->path);
         }
 
         r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, executable_fd, &executable_fd);
@@ -4634,11 +4633,10 @@ static int exec_child(
 
                 line = exec_command_line(final_argv);
                 if (line)
-                        log_struct(LOG_DEBUG,
-                                   "EXECUTABLE=%s", executable,
-                                   LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
-                                   LOG_UNIT_ID(unit),
-                                   LOG_UNIT_INVOCATION_ID(unit));
+                        log_unit_struct(unit, LOG_DEBUG,
+                                        "EXECUTABLE=%s", executable,
+                                        LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
+                                        LOG_UNIT_INVOCATION_ID(unit));
         }
 
         if (exec_fd >= 0) {
@@ -4730,14 +4728,13 @@ int exec_spawn(Unit *unit,
            and, until the next SELinux policy changes, we save further reloads in future children. */
         mac_selinux_maybe_reload();
 
-        log_struct(LOG_DEBUG,
-                   LOG_UNIT_MESSAGE(unit, "About to execute %s", line),
-                   "EXECUTABLE=%s", command->path, /* We won't know the real executable path until we create
-                                                      the mount namespace in the child, but we want to log
-                                                      from the parent, so we need to use the (possibly
-                                                      inaccurate) path here. */
-                   LOG_UNIT_ID(unit),
-                   LOG_UNIT_INVOCATION_ID(unit));
+        log_unit_struct(unit, LOG_DEBUG,
+                        LOG_UNIT_MESSAGE(unit, "About to execute %s", line),
+                        "EXECUTABLE=%s", command->path, /* We won't know the real executable path until we create
+                                                           the mount namespace in the child, but we want to log
+                                                           from the parent, so we need to use the (possibly
+                                                           inaccurate) path here. */
+                        LOG_UNIT_INVOCATION_ID(unit));
 
         if (params->cgroup_path) {
                 r = exec_parameters_get_cgroup_path(params, &subcgroup_path);
@@ -4781,13 +4778,12 @@ int exec_spawn(Unit *unit,
                                 exit_status_to_string(exit_status,
                                                       EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
 
-                        log_struct_errno(LOG_ERR, r,
-                                         "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
-                                         LOG_UNIT_ID(unit),
-                                         LOG_UNIT_INVOCATION_ID(unit),
-                                         LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
-                                                          status, command->path),
-                                         "EXECUTABLE=%s", command->path);
+                        log_unit_struct_errno(unit, LOG_ERR, r,
+                                              "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
+                                              LOG_UNIT_INVOCATION_ID(unit),
+                                              LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
+                                                               status, command->path),
+                                              "EXECUTABLE=%s", command->path);
                 }
 
                 _exit(exit_status);
index d313ebdb8ec8e473ae8f8cce442306e2fcb8ee82..cfc120961596fac478700d4d31f5e64364142358 100644 (file)
@@ -557,6 +557,9 @@ static void job_log_begin_status_message(Unit *u, uint32_t job_id, JobType t) {
         if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
                 return;
 
+        if (!unit_log_level_test(u, LOG_INFO))
+                return;
+
         if (log_on_console()) /* Skip this if it would only go on the console anyway */
                 return;
 
@@ -578,13 +581,12 @@ static void job_log_begin_status_message(Unit *u, uint32_t job_id, JobType t) {
          * which is supposed the highest level, friendliest output
          * possible, which means we should avoid the low-level unit
          * name. */
-        log_struct(LOG_INFO,
-                   LOG_MESSAGE("%s", buf),
-                   "JOB_ID=%" PRIu32, job_id,
-                   "JOB_TYPE=%s", job_type_to_string(t),
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   mid);
+        log_unit_struct(u, LOG_INFO,
+                        LOG_MESSAGE("%s", buf),
+                        "JOB_ID=%" PRIu32, job_id,
+                        "JOB_TYPE=%s", job_type_to_string(t),
+                        LOG_UNIT_INVOCATION_ID(u),
+                        mid);
 }
 
 static void job_emit_begin_status_message(Unit *u, uint32_t job_id, JobType t) {
@@ -879,18 +881,20 @@ static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, Job
 
         /* Show condition check message if the job did not actually do anything due to failed condition. */
         if (t == JOB_START && result == JOB_DONE && !u->condition_result) {
-                log_struct(LOG_INFO,
-                           "MESSAGE=Condition check resulted in %s being skipped.", unit_status_string(u),
-                           "JOB_ID=%" PRIu32, job_id,
-                           "JOB_TYPE=%s", job_type_to_string(t),
-                           "JOB_RESULT=%s", job_result_to_string(result),
-                           LOG_UNIT_ID(u),
-                           LOG_UNIT_INVOCATION_ID(u),
-                           "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR);
+                log_unit_struct(u, LOG_INFO,
+                                "MESSAGE=Condition check resulted in %s being skipped.", unit_status_string(u),
+                                "JOB_ID=%" PRIu32, job_id,
+                                "JOB_TYPE=%s", job_type_to_string(t),
+                                "JOB_RESULT=%s", job_result_to_string(result),
+                                LOG_UNIT_INVOCATION_ID(u),
+                                "MESSAGE_ID=" SD_MESSAGE_UNIT_STARTED_STR);
 
                 return;
         }
 
+        if (!unit_log_level_test(u, job_result_log_level[result]))
+                return;
+
         format = job_get_done_status_message_format(u, t, result);
         if (!format)
                 return;
@@ -922,24 +926,22 @@ static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, Job
                 break;
 
         default:
-                log_struct(job_result_log_level[result],
-                           LOG_MESSAGE("%s", buf),
-                           "JOB_ID=%" PRIu32, job_id,
-                           "JOB_TYPE=%s", job_type_to_string(t),
-                           "JOB_RESULT=%s", job_result_to_string(result),
-                           LOG_UNIT_ID(u),
-                           LOG_UNIT_INVOCATION_ID(u));
+                log_unit_struct(u, job_result_log_level[result],
+                                LOG_MESSAGE("%s", buf),
+                                "JOB_ID=%" PRIu32, job_id,
+                                "JOB_TYPE=%s", job_type_to_string(t),
+                                "JOB_RESULT=%s", job_result_to_string(result),
+                                LOG_UNIT_INVOCATION_ID(u));
                 return;
         }
 
-        log_struct(job_result_log_level[result],
-                   LOG_MESSAGE("%s", buf),
-                   "JOB_ID=%" PRIu32, job_id,
-                   "JOB_TYPE=%s", job_type_to_string(t),
-                   "JOB_RESULT=%s", job_result_to_string(result),
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   mid);
+        log_unit_struct(u, job_result_log_level[result],
+                        LOG_MESSAGE("%s", buf),
+                        "JOB_ID=%" PRIu32, job_id,
+                        "JOB_TYPE=%s", job_type_to_string(t),
+                        "JOB_RESULT=%s", job_result_to_string(result),
+                        LOG_UNIT_INVOCATION_ID(u),
+                        mid);
 }
 
 static void job_emit_done_status_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
@@ -1048,14 +1050,13 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
          * this context. And JOB_FAILURE is already handled by the
          * unit itself. */
         if (IN_SET(result, JOB_TIMEOUT, JOB_DEPENDENCY)) {
-                log_struct(LOG_NOTICE,
-                           "JOB_TYPE=%s", job_type_to_string(t),
-                           "JOB_RESULT=%s", job_result_to_string(result),
-                           LOG_UNIT_ID(u),
-                           LOG_UNIT_MESSAGE(u, "Job %s/%s failed with result '%s'.",
-                                            u->id,
-                                            job_type_to_string(t),
-                                            job_result_to_string(result)));
+                log_unit_struct(u, LOG_NOTICE,
+                                "JOB_TYPE=%s", job_type_to_string(t),
+                                "JOB_RESULT=%s", job_result_to_string(result),
+                                LOG_UNIT_MESSAGE(u, "Job %s/%s failed with result '%s'.",
+                                                 u->id,
+                                                 job_type_to_string(t),
+                                                 job_result_to_string(result)));
 
                 unit_start_on_failure(u);
         }
index 7723503dacde7ee30950e8bf13e68448d875b1a2..4c5bfb17fb81efff3539bab0f54b283d4a1dfc25 100644 (file)
@@ -2270,12 +2270,11 @@ static void service_enter_restart(Service *s) {
         s->n_restarts ++;
         s->flush_n_restarts = false;
 
-        log_struct(LOG_INFO,
-                   "MESSAGE_ID=" SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR,
-                   LOG_UNIT_ID(UNIT(s)),
-                   LOG_UNIT_INVOCATION_ID(UNIT(s)),
-                   LOG_UNIT_MESSAGE(UNIT(s), "Scheduled restart job, restart counter is at %u.", s->n_restarts),
-                   "N_RESTARTS=%u", s->n_restarts);
+        log_unit_struct(UNIT(s), LOG_INFO,
+                        "MESSAGE_ID=" SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR,
+                        LOG_UNIT_INVOCATION_ID(UNIT(s)),
+                        LOG_UNIT_MESSAGE(UNIT(s), "Scheduled restart job, restart counter is at %u.", s->n_restarts),
+                        "N_RESTARTS=%u", s->n_restarts);
 
         /* Notify clients about changed restart counter */
         unit_add_to_dbus_queue(UNIT(s));
index a6e28010695e18fea9bb80b76bf370e24a8f03d6..c212f1043d7f5aba65bef854d38b32244f3751d2 100644 (file)
@@ -1449,6 +1449,9 @@ static int log_unit_internal(void *userdata, int level, int error, const char *f
         va_list ap;
         int r;
 
+        if (u && !unit_log_level_test(u, level))
+                return -ERRNO_VALUE(error);
+
         va_start(ap, format);
         if (u)
                 r = log_object_internalv(level, error, file, line, func,
@@ -2152,6 +2155,13 @@ static int unit_log_resources(Unit *u) {
                                                 value > NOTICEWORTHY_IP_BYTES);
         }
 
+        /* This check is here because it is the earliest point following all possible log_level assignments. If
+         * log_level is assigned anywhere after this point, move this check. */
+        if (!unit_log_level_test(u, log_level)) {
+                r = 0;
+                goto finish;
+        }
+
         if (have_ip_accounting) {
                 if (any_traffic) {
                         if (igress)
@@ -2206,7 +2216,7 @@ static int unit_log_resources(Unit *u) {
         t = strjoina(u->manager->invocation_log_field, u->invocation_id_string);
         iovec[n_iovec + 3] = IOVEC_MAKE_STRING(t);
 
-        log_struct_iovec(log_level, iovec, n_iovec + 4);
+        log_unit_struct_iovec(u, log_level, iovec, n_iovec + 4);
         r = 0;
 
 finish:
@@ -3866,7 +3876,7 @@ int unit_patch_contexts(Unit *u) {
         return 0;
 }
 
-ExecContext *unit_get_exec_context(Unit *u) {
+ExecContext *unit_get_exec_context(const Unit *u) {
         size_t offset;
         assert(u);
 
@@ -4478,6 +4488,9 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
         assert(u);
         assert(where);
 
+        if (!unit_log_level_test(u, LOG_NOTICE))
+                return;
+
         r = dir_is_empty(where);
         if (r > 0 || r == -ENOTDIR)
                 return;
@@ -4486,12 +4499,11 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
                 return;
         }
 
-        log_struct(LOG_NOTICE,
-                   "MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where),
-                   "WHERE=%s", where);
+        log_unit_struct(u, LOG_NOTICE,
+                        "MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
+                        LOG_UNIT_INVOCATION_ID(u),
+                        LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where),
+                        "WHERE=%s", where);
 }
 
 int unit_fail_if_noncanonical(Unit *u, const char* where) {
@@ -4512,12 +4524,11 @@ int unit_fail_if_noncanonical(Unit *u, const char* where) {
                 return 0;
 
         /* No need to mention "." or "..", they would already have been rejected by unit_name_from_path() */
-        log_struct(LOG_ERR,
-                   "MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   LOG_UNIT_MESSAGE(u, "Mount path %s is not canonical (contains a symlink).", where),
-                   "WHERE=%s", where);
+        log_unit_struct(u, LOG_ERR,
+                        "MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
+                        LOG_UNIT_INVOCATION_ID(u),
+                        LOG_UNIT_MESSAGE(u, "Mount path %s is not canonical (contains a symlink).", where),
+                        "WHERE=%s", where);
 
         return -ELOOP;
 }
@@ -5296,35 +5307,32 @@ int unit_pid_attachable(Unit *u, pid_t pid, sd_bus_error *error) {
 void unit_log_success(Unit *u) {
         assert(u);
 
-        log_struct(LOG_INFO,
-                   "MESSAGE_ID=" SD_MESSAGE_UNIT_SUCCESS_STR,
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   LOG_UNIT_MESSAGE(u, "Deactivated successfully."));
+        log_unit_struct(u, LOG_INFO,
+                        "MESSAGE_ID=" SD_MESSAGE_UNIT_SUCCESS_STR,
+                        LOG_UNIT_INVOCATION_ID(u),
+                        LOG_UNIT_MESSAGE(u, "Deactivated successfully."));
 }
 
 void unit_log_failure(Unit *u, const char *result) {
         assert(u);
         assert(result);
 
-        log_struct(LOG_WARNING,
-                   "MESSAGE_ID=" SD_MESSAGE_UNIT_FAILURE_RESULT_STR,
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   LOG_UNIT_MESSAGE(u, "Failed with result '%s'.", result),
-                   "UNIT_RESULT=%s", result);
+        log_unit_struct(u, LOG_WARNING,
+                        "MESSAGE_ID=" SD_MESSAGE_UNIT_FAILURE_RESULT_STR,
+                        LOG_UNIT_INVOCATION_ID(u),
+                        LOG_UNIT_MESSAGE(u, "Failed with result '%s'.", result),
+                        "UNIT_RESULT=%s", result);
 }
 
 void unit_log_skip(Unit *u, const char *result) {
         assert(u);
         assert(result);
 
-        log_struct(LOG_INFO,
-                   "MESSAGE_ID=" SD_MESSAGE_UNIT_SKIPPED_STR,
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u),
-                   LOG_UNIT_MESSAGE(u, "Skipped due to '%s'.", result),
-                   "UNIT_RESULT=%s", result);
+        log_unit_struct(u, LOG_INFO,
+                        "MESSAGE_ID=" SD_MESSAGE_UNIT_SKIPPED_STR,
+                        LOG_UNIT_INVOCATION_ID(u),
+                        LOG_UNIT_MESSAGE(u, "Skipped due to '%s'.", result),
+                        "UNIT_RESULT=%s", result);
 }
 
 void unit_log_process_exit(
@@ -5351,19 +5359,18 @@ void unit_log_process_exit(
         else
                 level = LOG_WARNING;
 
-        log_struct(level,
-                   "MESSAGE_ID=" SD_MESSAGE_UNIT_PROCESS_EXIT_STR,
-                   LOG_UNIT_MESSAGE(u, "%s exited, code=%s, status=%i/%s",
-                                    kind,
-                                    sigchld_code_to_string(code), status,
-                                    strna(code == CLD_EXITED
-                                          ? exit_status_to_string(status, EXIT_STATUS_FULL)
-                                          : signal_to_string(status))),
-                   "EXIT_CODE=%s", sigchld_code_to_string(code),
-                   "EXIT_STATUS=%i", status,
-                   "COMMAND=%s", strna(command),
-                   LOG_UNIT_ID(u),
-                   LOG_UNIT_INVOCATION_ID(u));
+        log_unit_struct(u, level,
+                        "MESSAGE_ID=" SD_MESSAGE_UNIT_PROCESS_EXIT_STR,
+                        LOG_UNIT_MESSAGE(u, "%s exited, code=%s, status=%i/%s",
+                                         kind,
+                                         sigchld_code_to_string(code), status,
+                                         strna(code == CLD_EXITED
+                                               ? exit_status_to_string(status, EXIT_STATUS_FULL)
+                                               : signal_to_string(status))),
+                        "EXIT_CODE=%s", sigchld_code_to_string(code),
+                        "EXIT_STATUS=%i", status,
+                        "COMMAND=%s", strna(command),
+                        LOG_UNIT_INVOCATION_ID(u));
 }
 
 int unit_exit_status(Unit *u) {
index 6d38e6668031112855e81e66f88d18549f982758..264431d04d7a5efb68c666944231cdde21d972b3 100644 (file)
@@ -645,7 +645,7 @@ typedef struct UnitVTable {
 
 extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
 
-static inline const UnitVTable* UNIT_VTABLE(Unit *u) {
+static inline const UnitVTable* UNIT_VTABLE(const Unit *u) {
         return unit_vtable[u->type];
 }
 
@@ -808,7 +808,7 @@ void unit_ref_unset(UnitRef *ref);
 
 int unit_patch_contexts(Unit *u);
 
-ExecContext *unit_get_exec_context(Unit *u) _pure_;
+ExecContext *unit_get_exec_context(const Unit *u) _pure_;
 KillContext *unit_get_kill_context(Unit *u) _pure_;
 CGroupContext *unit_get_cgroup_context(Unit *u) _pure_;
 
@@ -879,6 +879,11 @@ static inline bool unit_has_job_type(Unit *u, JobType type) {
         return u && u->job && u->job->type == type;
 }
 
+static inline bool unit_log_level_test(const Unit *u, int level) {
+        ExecContext *ec = unit_get_exec_context(u);
+        return !ec || ec->log_level_max < 0 || ec->log_level_max >= LOG_PRI(level);
+}
+
 /* unit_log_skip is for cases like ExecCondition= where a unit is considered "done"
  * after some execution, rather than succeeded or failed. */
 void unit_log_skip(Unit *u, const char *result);
@@ -918,9 +923,10 @@ int unit_thaw_vtable_common(Unit *u);
 #define log_unit_full_errno(unit, level, error, ...)                    \
         ({                                                              \
                 const Unit *_u = (unit);                                \
-                (log_get_max_level() < LOG_PRI(level)) ? -ERRNO_VALUE(error) : \
-                        _u ? log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, _u->manager->unit_log_field, _u->id, _u->manager->invocation_log_field, _u->invocation_id_string, ##__VA_ARGS__) : \
-                                log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \
+                const int _l = (level);                                 \
+                (log_get_max_level() < LOG_PRI(_l) || (_u && !unit_log_level_test(_u, _l))) ? -ERRNO_VALUE(error) : \
+                        _u ? log_object_internal(_l, error, PROJECT_FILE, __LINE__, __func__, _u->manager->unit_log_field, _u->id, _u->manager->invocation_log_field, _u->invocation_id_string, ##__VA_ARGS__) : \
+                                log_internal(_l, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \
         })
 
 #define log_unit_full(unit, level, ...) (void) log_unit_full_errno(unit, level, 0, __VA_ARGS__)
@@ -937,6 +943,27 @@ int unit_thaw_vtable_common(Unit *u);
 #define log_unit_warning_errno(unit, error, ...) log_unit_full_errno(unit, LOG_WARNING, error, __VA_ARGS__)
 #define log_unit_error_errno(unit, error, ...)   log_unit_full_errno(unit, LOG_ERR, error, __VA_ARGS__)
 
+#define log_unit_struct_errno(unit, level, error, ...)                  \
+        ({                                                              \
+                const Unit *_u = (unit);                                \
+                const int _l = (level);                                 \
+                unit_log_level_test(_u, _l) ?                           \
+                        log_struct_errno(_l, error, __VA_ARGS__, LOG_UNIT_ID(_u)) : \
+                        -ERRNO_VALUE(error);                            \
+        })
+
+#define log_unit_struct(unit, level, ...) log_unit_struct_errno(unit, level, 0, __VA_ARGS__)
+
+#define log_unit_struct_iovec_errno(unit, level, error, iovec, n_iovec) \
+        ({                                                              \
+                const int _l = (level);                                 \
+                unit_log_level_test(unit, _l) ?                         \
+                        log_struct_iovec_errno(_l, error, iovec, n_iovec) : \
+                        -ERRNO_VALUE(error);                            \
+        })
+
+#define log_unit_struct_iovec(unit, level, iovec, n_iovec) log_unit_struct_iovec_errno(unit, level, 0, iovec, n_iovec)
+
 #define LOG_UNIT_MESSAGE(unit, fmt, ...) "MESSAGE=%s: " fmt, (unit)->id, ##__VA_ARGS__
 #define LOG_UNIT_ID(unit) (unit)->manager->unit_log_format_string, (unit)->id
 #define LOG_UNIT_INVOCATION_ID(unit) (unit)->manager->invocation_log_format_string, (unit)->invocation_id_string
diff --git a/test/testsuite-04.units/silent-success.service b/test/testsuite-04.units/silent-success.service
new file mode 100644 (file)
index 0000000..a9f7137
--- /dev/null
@@ -0,0 +1,6 @@
+[Unit]
+Description=Silent successful service
+
+[Service]
+LogLevelMax=notice
+ExecStart=/bin/true
index 3dce73b778250854dbde499123242101931540c5..b9354c15578f0de529225982205133ab5d1b0baa 100755 (executable)
@@ -99,6 +99,11 @@ cmp /expected /output
 [[ $(journalctl -b -o cat -t "$ID" --output-fields=_PID | sort -u | grep -c "^.*$") -eq 3 ]]
 [[ $(journalctl -b -o cat -t "$ID" --output-fields=MESSAGE | grep -Pc "^(This will|usually fail|and be truncated)$") -eq 3 ]]
 
+# test that LogLevelMax can also suppress logging about services, not only by services
+systemctl start silent-success
+journalctl --sync
+[[ -z `journalctl -b -q -u silent-success.service` ]]
+
 # Add new tests before here, the journald restarts below
 # may make tests flappy.