]> 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)
committerLennart Poettering <lennart@poettering.net>
Mon, 3 May 2021 15:48:41 +0000 (17:48 +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.

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 2aefb4eb2552c859159bfc57ae52d3e0d2418d8a..b2fbb3b64417f42a8edc71b03e4d50ff6c45af31 100644 (file)
@@ -2653,7 +2653,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 d541c16f5fe56668b785dc015d50a172f4cb209a..9fbf64b7bee5097eff2bcfc074286dd3a0d63144 100644 (file)
@@ -2923,11 +2923,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;
 }
@@ -2955,11 +2954,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 9f54ad424b141cdac2fb4e3728a02ff2c527d2e8..482ae4875b12db1bad545d80a9d488b8112c6343 100644 (file)
@@ -4318,24 +4318,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);
@@ -4643,11 +4642,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) {
@@ -4739,14 +4737,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);
@@ -4790,13 +4787,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 ffa301980fb91322ae4604c15c717a872bbdb38a..1cce15eb76626884dd692d06c42e2e2f9922ab92 100644 (file)
@@ -2277,12 +2277,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 6ef90eea0e41d5dcb8e1663b7f0eeeea51498862..67d811d7dd9d8dbaf610b96fcf8703e8d24966ef 100644 (file)
@@ -1463,6 +1463,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,
@@ -2166,6 +2169,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)
@@ -2220,7 +2230,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:
@@ -3880,7 +3890,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);
 
@@ -4492,6 +4502,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;
@@ -4500,12 +4513,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) {
@@ -4526,12 +4538,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;
 }
@@ -5310,35 +5321,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(
@@ -5365,19 +5373,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 5bc1237ce075585427234a078b5f601d2cf7609e..abd8aecc1a05a6d4469684d8bdd25cb0d088559a 100644 (file)
@@ -658,7 +658,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];
 }
 
@@ -821,7 +821,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_;
 
@@ -892,6 +892,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);
@@ -931,9 +936,10 @@ int unit_thaw_vtable_common(Unit *u);
 #define log_unit_full_errno_zerook(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_errno(unit, level, error, ...) \
@@ -957,6 +963,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 da5f9ee2af15c03e647e7857e8da12793edf21ed..7a17e086114d441bcc79ddac2242b05c396b7595 100755 (executable)
@@ -98,6 +98,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.