mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #26794 from bluca/log_extra_fields
core: append LogExtraFields= values to log_unit* messages
This commit is contained in:
@@ -2909,8 +2909,8 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
|
||||
<term><varname>LogExtraFields=</varname></term>
|
||||
|
||||
<listitem><para>Configures additional log metadata fields to include in all log records generated by
|
||||
processes associated with this unit. This setting takes one or more journal field assignments in the
|
||||
format <literal>FIELD=VALUE</literal> separated by whitespace. See
|
||||
processes associated with this unit, including systemd. This setting takes one or more journal field
|
||||
assignments in the format <literal>FIELD=VALUE</literal> separated by whitespace. See
|
||||
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
for details on the journal field concept. Even though the underlying journal implementation permits
|
||||
binary field values, this setting accepts only valid UTF-8 values. To include space characters in a
|
||||
|
||||
@@ -76,6 +76,8 @@ typedef struct LogContext {
|
||||
/* Depending on which destructor is used (log_context_free() or log_context_detach()) the memory
|
||||
* referenced by this is freed or not */
|
||||
char **fields;
|
||||
struct iovec *input_iovec;
|
||||
size_t n_input_iovec;
|
||||
bool owned;
|
||||
LIST_FIELDS(struct LogContext, ll);
|
||||
} LogContext;
|
||||
@@ -613,7 +615,7 @@ static void log_do_context(struct iovec *iovec, size_t iovec_len, size_t *n) {
|
||||
assert(iovec);
|
||||
assert(n);
|
||||
|
||||
LIST_FOREACH(ll, c, _log_context)
|
||||
LIST_FOREACH(ll, c, _log_context) {
|
||||
STRV_FOREACH(s, c->fields) {
|
||||
if (*n + 2 >= iovec_len)
|
||||
return;
|
||||
@@ -621,6 +623,15 @@ static void log_do_context(struct iovec *iovec, size_t iovec_len, size_t *n) {
|
||||
iovec[(*n)++] = IOVEC_MAKE_STRING(*s);
|
||||
iovec[(*n)++] = IOVEC_MAKE_STRING("\n");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < c->n_input_iovec; i++) {
|
||||
if (*n + 2 >= iovec_len)
|
||||
return;
|
||||
|
||||
iovec[(*n)++] = c->input_iovec[i];
|
||||
iovec[(*n)++] = IOVEC_MAKE_STRING("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int write_to_journal(
|
||||
@@ -1555,6 +1566,7 @@ LogContext* log_context_attach(LogContext *c) {
|
||||
assert(c);
|
||||
|
||||
_log_context_num_fields += strv_length(c->fields);
|
||||
_log_context_num_fields += c->n_input_iovec;
|
||||
|
||||
return LIST_PREPEND(ll, _log_context, c);
|
||||
}
|
||||
@@ -1563,8 +1575,9 @@ LogContext* log_context_detach(LogContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
assert(_log_context_num_fields >= strv_length(c->fields));
|
||||
assert(_log_context_num_fields >= strv_length(c->fields) + c->n_input_iovec);
|
||||
_log_context_num_fields -= strv_length(c->fields);
|
||||
_log_context_num_fields -= c->n_input_iovec;
|
||||
|
||||
LIST_REMOVE(ll, _log_context, c);
|
||||
return NULL;
|
||||
@@ -1583,14 +1596,33 @@ LogContext* log_context_new(char **fields, bool owned) {
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
LogContext* log_context_newv(struct iovec *input_iovec, size_t n_input_iovec, bool owned) {
|
||||
if (!input_iovec || n_input_iovec == 0)
|
||||
return NULL; /* Nothing to do */
|
||||
|
||||
LogContext *c = new(LogContext, 1);
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
*c = (LogContext) {
|
||||
.input_iovec = input_iovec,
|
||||
.n_input_iovec = n_input_iovec,
|
||||
.owned = owned,
|
||||
};
|
||||
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
LogContext* log_context_free(LogContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
log_context_detach(c);
|
||||
|
||||
if (c->owned)
|
||||
if (c->owned) {
|
||||
strv_free(c->fields);
|
||||
iovec_array_free(c->input_iovec, c->n_input_iovec);
|
||||
}
|
||||
|
||||
return mfree(c);
|
||||
}
|
||||
@@ -1603,6 +1635,14 @@ LogContext* log_context_new_consume(char **fields) {
|
||||
return c;
|
||||
}
|
||||
|
||||
LogContext* log_context_new_consumev(struct iovec *input_iovec, size_t n_input_iovec) {
|
||||
LogContext *c = log_context_newv(input_iovec, n_input_iovec, /*owned=*/ true);
|
||||
if (!c)
|
||||
iovec_array_free(input_iovec, n_input_iovec);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
size_t log_context_num_contexts(void) {
|
||||
size_t n = 0;
|
||||
|
||||
|
||||
@@ -461,10 +461,12 @@ LogContext* log_context_attach(LogContext *c);
|
||||
LogContext* log_context_detach(LogContext *c);
|
||||
|
||||
LogContext* log_context_new(char **fields, bool owned);
|
||||
LogContext* log_context_newv(struct iovec *input_iovec, size_t n_input_iovec, bool owned);
|
||||
LogContext* log_context_free(LogContext *c);
|
||||
|
||||
/* Same as log_context_new(), but frees the given fields strv on failure. */
|
||||
/* Same as log_context_new(), but frees the given fields strv/iovec on failure. */
|
||||
LogContext* log_context_new_consume(char **fields);
|
||||
LogContext* log_context_new_consumev(struct iovec *input_iovec, size_t n_input_iovec);
|
||||
|
||||
/* Returns the number of attached log context objects. */
|
||||
size_t log_context_num_contexts(void);
|
||||
@@ -486,8 +488,15 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_free);
|
||||
#define LOG_CONTEXT_PUSH_STRV(strv) \
|
||||
_LOG_CONTEXT_PUSH_STRV(strv, UNIQ_T(c, UNIQ))
|
||||
|
||||
/* LOG_CONTEXT_CONSUME_STR()/LOG_CONTEXT_CONSUME_STRV() are identical to
|
||||
* LOG_CONTEXT_PUSH_STR()/LOG_CONTEXT_PUSH_STRV() except they take ownership of the given str/strv argument.
|
||||
#define _LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, c) \
|
||||
_unused_ _cleanup_(log_context_freep) LogContext *c = log_context_newv(input_iovec, n_input_iovec, /*owned=*/ false);
|
||||
|
||||
#define LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec) \
|
||||
_LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, UNIQ_T(c, UNIQ))
|
||||
|
||||
/* LOG_CONTEXT_CONSUME_STR()/LOG_CONTEXT_CONSUME_STRV()/LOG_CONTEXT_CONSUME_IOV() are identical to
|
||||
* LOG_CONTEXT_PUSH_STR()/LOG_CONTEXT_PUSH_STRV()/LOG_CONTEXT_PUSH_IOV() except they take ownership of the
|
||||
* given str/strv argument.
|
||||
*/
|
||||
|
||||
#define _LOG_CONTEXT_CONSUME_STR(s, c, strv) \
|
||||
@@ -504,3 +513,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_free);
|
||||
|
||||
#define LOG_CONTEXT_CONSUME_STRV(strv) \
|
||||
_LOG_CONTEXT_CONSUME_STRV(strv, UNIQ_T(c, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec, c) \
|
||||
_unused_ _cleanup_(log_context_freep) LogContext *c = log_context_new_consumev(input_iovec, n_input_iovec);
|
||||
|
||||
#define LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec) \
|
||||
_LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec, UNIQ_T(c, UNIQ))
|
||||
|
||||
@@ -1078,7 +1078,13 @@ Condition *unit_find_failed_condition(Unit *u);
|
||||
({ \
|
||||
const Unit *_u = (unit); \
|
||||
const int _l = (level); \
|
||||
(log_get_max_level() < LOG_PRI(_l) || (_u && !unit_log_level_test(_u, _l))) ? -ERRNO_VALUE(error) : \
|
||||
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_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__, _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__); \
|
||||
})
|
||||
@@ -1116,7 +1122,12 @@ Condition *unit_find_failed_condition(Unit *u);
|
||||
({ \
|
||||
const Unit *_u = (unit); \
|
||||
const int _l = (level); \
|
||||
unit_log_level_test(_u, _l) ? \
|
||||
bool _do_log = unit_log_level_test(_u, _l); \
|
||||
const ExecContext *_c = _do_log && _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); \
|
||||
})
|
||||
@@ -1125,8 +1136,14 @@ Condition *unit_find_failed_condition(Unit *u);
|
||||
|
||||
#define log_unit_struct_iovec_errno(unit, level, error, iovec, n_iovec) \
|
||||
({ \
|
||||
const Unit *_u = (unit); \
|
||||
const int _l = (level); \
|
||||
unit_log_level_test(unit, _l) ? \
|
||||
bool _do_log = unit_log_level_test(_u, _l); \
|
||||
const ExecContext *_c = _do_log && _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); \
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "format-util.h"
|
||||
#include "io-util.h"
|
||||
#include "log.h"
|
||||
#include "process-util.h"
|
||||
#include "string-util.h"
|
||||
@@ -135,6 +136,28 @@ static void test_log_context(void) {
|
||||
assert_se(log_context_num_fields() == 2);
|
||||
}
|
||||
|
||||
{
|
||||
/* Test that everything still works with a mixed strv and iov. */
|
||||
struct iovec iov[] = {
|
||||
IOVEC_MAKE_STRING("ABC=def"),
|
||||
IOVEC_MAKE_STRING("GHI=jkl"),
|
||||
};
|
||||
_cleanup_free_ struct iovec_wrapper *iovw = iovw_new();
|
||||
assert_se(iovw);
|
||||
assert_se(iovw_consume(iovw, strdup("MNO=pqr"), STRLEN("MNO=pqr") + 1) == 0);
|
||||
|
||||
LOG_CONTEXT_PUSH_IOV(iov, ELEMENTSOF(iov));
|
||||
LOG_CONTEXT_CONSUME_IOV(iovw->iovec, iovw->count);
|
||||
LOG_CONTEXT_PUSH("STU=vwx");
|
||||
|
||||
assert_se(log_context_num_contexts() == 3);
|
||||
assert_se(log_context_num_fields() == 4);
|
||||
|
||||
test_log_struct();
|
||||
test_long_lines();
|
||||
test_log_syntax();
|
||||
}
|
||||
|
||||
assert_se(log_context_num_contexts() == 0);
|
||||
assert_se(log_context_num_fields() == 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user