From: Daan De Meyer Date: Mon, 7 Apr 2025 18:06:54 +0000 (+0200) Subject: unit: Make sure individual unit maximum log level always takes priority X-Git-Tag: v258-rc1~753^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba77798bbab2665fd9cb56bf5d32276ad39d3b4a;p=thirdparty%2Fsystemd.git unit: Make sure individual unit maximum log level always takes priority Currently LogLevelMax= can only be used to decrease the maximum log level for a unit but not to increase it. Let's make sure the latter works as well, so LogLevelMax=debug can be used to enable debug logging for specific units without enabling debug logging globally. --- diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index bf4f223a431..ce76fb793b2 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -3268,23 +3268,30 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX LogLevelMax= - Configures filtering by log level of log messages generated by this unit. Takes a - syslog log level, one of (lowest log level, only highest priority - messages), , , , , - , , (highest log level, also lowest priority - messages). See Sets the maximum log level for log messages generated by this unit. Takes a + syslog log level, one of (lowest log level, only highest + priority messages), , , , + , , , + (highest log level, also lowest priority messages). See syslog3 for - details. By default, no filtering is applied (i.e. the default maximum log level is ). Use - this option to configure the logging system to drop log messages of a specific service above the specified - level. For example, set LogLevelMax= 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, 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, MaxLevelStore= configured in - journald.conf5 might - prohibit messages of higher log levels to be stored on disk, even though the per-unit + details. By default, the maximum log level is not overridden. + + This option can be used to configure the logging system to drop log messages of a specific + service above the specified level. For example, set + LogLevelMax= in order to turn off debug logging of a + particularly chatty unit. Alternatively, this option can be used to enable extra logging about a + specific unit by the system or user manager processes without changing the global log level for the + system or user manager processes by setting LogLevelMax=. + + + Note that the configured level is applied to any log messages written by any of the processes + belonging to this unit, as well as any log messages written by the system or user manager processes + in reference to this unit, sent via any supported logging protocol. The override 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, MaxLevelStore= configured in + journald.conf5 + might prohibit messages of higher log levels to be stored on disk, even though the per-unit LogLevelMax= permitted it to be processed. diff --git a/src/core/unit.h b/src/core/unit.h index 5bf52f5f6d2..d1a0e20a435 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -1018,10 +1018,22 @@ static inline bool unit_has_job_type(Unit *u, JobType type) { return u && u->job && u->job->type == type; } +static inline int unit_get_log_level_max(const Unit *u) { + if (u) { + if (u->debug_invocation) + return LOG_DEBUG; + + ExecContext *ec = unit_get_exec_context(u); + if (ec && ec->log_level_max >= 0) + return ec->log_level_max; + } + + return log_get_max_level(); +} + static inline bool unit_log_level_test(const Unit *u, int level) { assert(u); - ExecContext *ec = unit_get_exec_context(u); - return !ec || ec->log_level_max < 0 || ec->log_level_max >= LOG_PRI(level) || u->debug_invocation; + return LOG_PRI(level) <= unit_get_log_level_max(u); } /* unit_log_skip is for cases like ExecCondition= where a unit is considered "done" @@ -1085,15 +1097,12 @@ OOMPolicy oom_policy_from_string(const char *s) _pure_; ({ \ const Unit *_u = (unit); \ const int _l = (level); \ - bool _do_log = !(log_get_max_level() < LOG_PRI(_l) || \ - (_u && !unit_log_level_test(_u, _l))); \ - const ExecContext *_c = _do_log && _u ? \ - unit_get_exec_context(_u) : NULL; \ + LOG_CONTEXT_SET_LOG_LEVEL(unit_get_log_level_max(_u)); \ + const ExecContext *_c = _u ? unit_get_exec_context(_u) : NULL; \ LOG_CONTEXT_PUSH_IOV(_c ? _c->log_extra_fields : NULL, \ _c ? _c->n_log_extra_fields : 0); \ - !_do_log ? -ERRNO_VALUE(error) : \ - _u ? log_object_internal(_l, error, PROJECT_FILE, __LINE__, __func__, unit_log_field(_u), _u->id, unit_invocation_log_field(_u), _u->invocation_id_string, ##__VA_ARGS__) : \ - log_internal(_l, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \ + _u ? log_object_internal(_l, error, PROJECT_FILE, __LINE__, __func__, unit_log_field(_u), _u->id, unit_invocation_log_field(_u), _u->invocation_id_string, ##__VA_ARGS__) : \ + log_internal(_l, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \ }) #define log_unit_full_errno(unit, level, error, ...) \ @@ -1129,14 +1138,11 @@ OOMPolicy oom_policy_from_string(const char *s) _pure_; ({ \ const Unit *_u = (unit); \ const int _l = (level); \ - bool _do_log = unit_log_level_test(_u, _l); \ - const ExecContext *_c = _do_log && _u ? \ - unit_get_exec_context(_u) : NULL; \ + LOG_CONTEXT_SET_LOG_LEVEL(unit_get_log_level_max(_u)); \ + const ExecContext *_c = _u ? unit_get_exec_context(_u) : NULL; \ LOG_CONTEXT_PUSH_IOV(_c ? _c->log_extra_fields : NULL, \ _c ? _c->n_log_extra_fields : 0); \ - _do_log ? \ - log_struct_errno(_l, error, __VA_ARGS__, LOG_UNIT_ID(_u)) : \ - -ERRNO_VALUE(error); \ + log_struct_errno(_l, error, __VA_ARGS__, LOG_UNIT_ID(_u)); \ }) #define log_unit_struct(unit, level, ...) log_unit_struct_errno(unit, level, 0, __VA_ARGS__) @@ -1145,14 +1151,11 @@ OOMPolicy oom_policy_from_string(const char *s) _pure_; ({ \ const Unit *_u = (unit); \ const int _l = (level); \ - bool _do_log = unit_log_level_test(_u, _l); \ - const ExecContext *_c = _do_log && _u ? \ - unit_get_exec_context(_u) : NULL; \ + LOG_CONTEXT_SET_LOG_LEVEL(unit_get_log_level_max(_u)); \ + const ExecContext *_c = _u ? unit_get_exec_context(_u) : NULL; \ LOG_CONTEXT_PUSH_IOV(_c ? _c->log_extra_fields : NULL, \ _c ? _c->n_log_extra_fields : 0); \ - _do_log ? \ - log_struct_iovec_errno(_l, error, iovec, n_iovec) : \ - -ERRNO_VALUE(error); \ + log_struct_iovec_errno(_l, error, iovec, n_iovec); \ }) #define log_unit_struct_iovec(unit, level, iovec, n_iovec) log_unit_struct_iovec_errno(unit, level, 0, iovec, n_iovec) @@ -1222,7 +1225,7 @@ typedef struct UnitForEachDependencyData { LOG_CONTEXT_PUSH_KEY_VALUE(unit_log_field(u), u->id); \ LOG_CONTEXT_PUSH_KEY_VALUE(unit_invocation_log_field(u), u->invocation_id_string); \ LOG_CONTEXT_PUSH_IOV(c ? c->log_extra_fields : NULL, c ? c->n_log_extra_fields : 0); \ - LOG_CONTEXT_SET_LOG_LEVEL(c->log_level_max >= 0 ? c->log_level_max : log_get_max_level()) + LOG_CONTEXT_SET_LOG_LEVEL(unit_get_log_level_max(u)) #define LOG_CONTEXT_PUSH_UNIT(unit) \ _LOG_CONTEXT_PUSH_UNIT(unit, UNIQ_T(u, UNIQ), UNIQ_T(c, UNIQ))