basic: Move log context functions to log-context.h
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <threads.h>
|
||||
|
||||
#include "env-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "log.h"
|
||||
#include "log-context.h"
|
||||
#include "strv.h"
|
||||
|
||||
static int saved_log_context_enabled = -1;
|
||||
thread_local LIST_HEAD(LogContext, _log_context) = NULL;
|
||||
thread_local size_t _log_context_num_fields = 0;
|
||||
|
||||
bool log_context_enabled(void) {
|
||||
int r;
|
||||
|
||||
if (log_get_max_level() == LOG_DEBUG)
|
||||
return true;
|
||||
|
||||
if (saved_log_context_enabled >= 0)
|
||||
return saved_log_context_enabled;
|
||||
|
||||
r = secure_getenv_bool("SYSTEMD_ENABLE_LOG_CONTEXT");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_ENABLE_LOG_CONTEXT, ignoring: %m");
|
||||
|
||||
saved_log_context_enabled = r > 0;
|
||||
|
||||
return saved_log_context_enabled;
|
||||
}
|
||||
|
||||
static LogContext* log_context_attach(LogContext *c) {
|
||||
assert(c);
|
||||
|
||||
_log_context_num_fields += strv_length(c->fields);
|
||||
_log_context_num_fields += c->n_input_iovec;
|
||||
_log_context_num_fields += !!c->key;
|
||||
|
||||
return LIST_PREPEND(ll, _log_context, c);
|
||||
}
|
||||
|
||||
static LogContext* log_context_detach(LogContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
assert(_log_context_num_fields >= strv_length(c->fields) + c->n_input_iovec +!!c->key);
|
||||
_log_context_num_fields -= strv_length(c->fields);
|
||||
_log_context_num_fields -= c->n_input_iovec;
|
||||
_log_context_num_fields -= !!c->key;
|
||||
|
||||
LIST_REMOVE(ll, _log_context, c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LogContext* log_context_new(const char *key, const char *value) {
|
||||
assert(key);
|
||||
assert(endswith(key, "="));
|
||||
assert(value);
|
||||
|
||||
LIST_FOREACH(ll, i, _log_context)
|
||||
if (i->key == key && i->value == value)
|
||||
return log_context_ref(i);
|
||||
|
||||
LogContext *c = new(LogContext, 1);
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
*c = (LogContext) {
|
||||
.n_ref = 1,
|
||||
.key = (char *) key,
|
||||
.value = (char *) value,
|
||||
};
|
||||
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
LogContext* log_context_new_strv(char **fields, bool owned) {
|
||||
if (!fields)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(ll, i, _log_context)
|
||||
if (i->fields == fields) {
|
||||
assert(!owned);
|
||||
return log_context_ref(i);
|
||||
}
|
||||
|
||||
LogContext *c = new(LogContext, 1);
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
*c = (LogContext) {
|
||||
.n_ref = 1,
|
||||
.fields = fields,
|
||||
.owned = owned,
|
||||
};
|
||||
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
LogContext* log_context_new_iov(struct iovec *input_iovec, size_t n_input_iovec, bool owned) {
|
||||
if (!input_iovec || n_input_iovec == 0)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(ll, i, _log_context)
|
||||
if (i->input_iovec == input_iovec && i->n_input_iovec == n_input_iovec) {
|
||||
assert(!owned);
|
||||
return log_context_ref(i);
|
||||
}
|
||||
|
||||
LogContext *c = new(LogContext, 1);
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
*c = (LogContext) {
|
||||
.n_ref = 1,
|
||||
.input_iovec = input_iovec,
|
||||
.n_input_iovec = n_input_iovec,
|
||||
.owned = owned,
|
||||
};
|
||||
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
static LogContext* log_context_free(LogContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
log_context_detach(c);
|
||||
|
||||
if (c->owned) {
|
||||
strv_free(c->fields);
|
||||
iovec_array_free(c->input_iovec, c->n_input_iovec);
|
||||
free(c->key);
|
||||
free(c->value);
|
||||
}
|
||||
|
||||
return mfree(c);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(LogContext, log_context, log_context_free);
|
||||
|
||||
LogContext* log_context_new_strv_consume(char **fields) {
|
||||
LogContext *c = log_context_new_strv(fields, /*owned=*/ true);
|
||||
if (!c)
|
||||
strv_free(fields);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
LogContext* log_context_new_iov_consume(struct iovec *input_iovec, size_t n_input_iovec) {
|
||||
LogContext *c = log_context_new_iov(input_iovec, n_input_iovec, /*owned=*/ true);
|
||||
if (!c)
|
||||
iovec_array_free(input_iovec, n_input_iovec);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
LogContext* log_context_head(void) {
|
||||
return _log_context;
|
||||
}
|
||||
|
||||
size_t log_context_num_contexts(void) {
|
||||
size_t n = 0;
|
||||
|
||||
LIST_FOREACH(ll, c, _log_context)
|
||||
n++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t log_context_num_fields(void) {
|
||||
return _log_context_num_fields;
|
||||
}
|
||||
|
||||
void _reset_log_level(int *saved_log_level) {
|
||||
assert(saved_log_level);
|
||||
|
||||
log_set_max_level(*saved_log_level);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
/*
|
||||
* The log context allows attaching extra metadata to log messages written to the journal via log.h. We keep
|
||||
* track of a thread local log context onto which we can push extra metadata fields that should be logged.
|
||||
*
|
||||
* LOG_CONTEXT_PUSH() will add the provided field to the log context and will remove it again when the
|
||||
* current block ends. LOG_CONTEXT_PUSH_STRV() will do the same but for all fields in the given strv.
|
||||
* LOG_CONTEXT_PUSHF() is like LOG_CONTEXT_PUSH() but takes a format string and arguments.
|
||||
*
|
||||
* Using the macros is as simple as putting them anywhere inside a block to add a field to all following log
|
||||
* messages logged from inside that block.
|
||||
*
|
||||
* void myfunction(...) {
|
||||
* ...
|
||||
*
|
||||
* LOG_CONTEXT_PUSHF("MYMETADATA=%s", "abc");
|
||||
*
|
||||
* // Every journal message logged will now have the MYMETADATA=abc
|
||||
* // field included.
|
||||
* }
|
||||
*
|
||||
* One special case to note is async code, where we use callbacks that are invoked to continue processing
|
||||
* when some event occurs. For async code, there's usually an associated "userdata" struct containing all the
|
||||
* information associated with the async operation. In this "userdata" struct, we can store a log context
|
||||
* allocated with log_context_new() and freed with log_context_free(). We can then add and remove fields to
|
||||
* the `fields` member of the log context object and all those fields will be logged along with each log
|
||||
* message.
|
||||
*/
|
||||
|
||||
struct iovec;
|
||||
|
||||
typedef struct LogContext {
|
||||
unsigned n_ref;
|
||||
/* 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;
|
||||
char *key;
|
||||
char *value;
|
||||
bool owned;
|
||||
LIST_FIELDS(struct LogContext, ll);
|
||||
} LogContext;
|
||||
|
||||
bool log_context_enabled(void);
|
||||
|
||||
LogContext* log_context_new(const char *key, const char *value);
|
||||
LogContext* log_context_new_strv(char **fields, bool owned);
|
||||
LogContext* log_context_new_iov(struct iovec *input_iovec, size_t n_input_iovec, bool owned);
|
||||
|
||||
/* Same as log_context_new(), but frees the given fields strv/iovec on failure. */
|
||||
LogContext* log_context_new_strv_consume(char **fields);
|
||||
LogContext* log_context_new_iov_consume(struct iovec *input_iovec, size_t n_input_iovec);
|
||||
|
||||
LogContext *log_context_ref(LogContext *c);
|
||||
LogContext *log_context_unref(LogContext *c);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_unref);
|
||||
|
||||
/* Returns the head of the log context list. */
|
||||
LogContext* log_context_head(void);
|
||||
/* Returns the number of attached log context objects. */
|
||||
size_t log_context_num_contexts(void);
|
||||
/* Returns the number of fields in all attached log contexts. */
|
||||
size_t log_context_num_fields(void);
|
||||
|
||||
void _reset_log_level(int *saved_log_level);
|
||||
|
||||
#define LOG_CONTEXT_SET_LOG_LEVEL(level) \
|
||||
_cleanup_(_reset_log_level) _unused_ int _saved_log_level_ = log_set_max_level(level);
|
||||
|
||||
#define LOG_CONTEXT_PUSH(...) \
|
||||
LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__))
|
||||
|
||||
#define LOG_CONTEXT_PUSHF(...) \
|
||||
LOG_CONTEXT_PUSH(snprintf_ok((char[LINE_MAX]) {}, LINE_MAX, __VA_ARGS__))
|
||||
|
||||
#define _LOG_CONTEXT_PUSH_KEY_VALUE(key, value, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new(key, value);
|
||||
|
||||
#define LOG_CONTEXT_PUSH_KEY_VALUE(key, value) \
|
||||
_LOG_CONTEXT_PUSH_KEY_VALUE(key, value, UNIQ_T(c, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_PUSH_STRV(strv, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv(strv, /*owned=*/ false);
|
||||
|
||||
#define LOG_CONTEXT_PUSH_STRV(strv) \
|
||||
_LOG_CONTEXT_PUSH_STRV(strv, UNIQ_T(c, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_iov(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) \
|
||||
_unused_ _cleanup_strv_free_ strv = strv_new(s); \
|
||||
if (!strv) \
|
||||
free(s); \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(TAKE_PTR(strv))
|
||||
|
||||
#define LOG_CONTEXT_CONSUME_STR(s) \
|
||||
_LOG_CONTEXT_CONSUME_STR(s, UNIQ_T(c, UNIQ), UNIQ_T(sv, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_CONSUME_STRV(strv, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(strv);
|
||||
|
||||
#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_unrefp) LogContext *c = log_context_new_iov_consume(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))
|
||||
+5
-179
@@ -25,6 +25,7 @@
|
||||
#include "format-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "log.h"
|
||||
#include "log-context.h"
|
||||
#include "macro.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "parse-util.h"
|
||||
@@ -82,22 +83,6 @@ static bool assert_return_is_critical = BUILD_MODE_DEVELOPER;
|
||||
* use here. */
|
||||
static char *log_abort_msg = NULL;
|
||||
|
||||
typedef struct LogContext {
|
||||
unsigned n_ref;
|
||||
/* 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;
|
||||
char *key;
|
||||
char *value;
|
||||
bool owned;
|
||||
LIST_FIELDS(struct LogContext, ll);
|
||||
} LogContext;
|
||||
|
||||
static thread_local LIST_HEAD(LogContext, _log_context) = NULL;
|
||||
static thread_local size_t _log_context_num_fields = 0;
|
||||
|
||||
static thread_local const char *log_prefix = NULL;
|
||||
|
||||
#if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__)
|
||||
@@ -697,7 +682,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_head()) {
|
||||
STRV_FOREACH(s, c->fields) {
|
||||
if (*n + 2 >= iovec_len)
|
||||
return;
|
||||
@@ -747,7 +732,7 @@ static int write_to_journal(
|
||||
if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_JOURNAL])
|
||||
return 0;
|
||||
|
||||
iovec_len = MIN(6 + _log_context_num_fields * 3, IOVEC_MAX);
|
||||
iovec_len = MIN(6 + log_context_num_fields() * 3, IOVEC_MAX);
|
||||
iovec = newa(struct iovec, iovec_len);
|
||||
|
||||
log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
|
||||
@@ -1099,7 +1084,7 @@ int log_struct_internal(
|
||||
int r;
|
||||
bool fallback = false;
|
||||
|
||||
iovec_len = MIN(17 + _log_context_num_fields * 3, IOVEC_MAX);
|
||||
iovec_len = MIN(17 + log_context_num_fields() * 3, IOVEC_MAX);
|
||||
iovec = newa(struct iovec, iovec_len);
|
||||
|
||||
/* If the journal is available do structured logging.
|
||||
@@ -1200,7 +1185,7 @@ int log_struct_iovec_internal(
|
||||
struct iovec *iovec;
|
||||
size_t n = 0, iovec_len;
|
||||
|
||||
iovec_len = MIN(1 + n_input_iovec * 2 + _log_context_num_fields * 3, IOVEC_MAX);
|
||||
iovec_len = MIN(1 + n_input_iovec * 2 + log_context_num_fields() * 3, IOVEC_MAX);
|
||||
iovec = newa(struct iovec, iovec_len);
|
||||
|
||||
log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
|
||||
@@ -1811,162 +1796,3 @@ const char* _log_set_prefix(const char *prefix, bool force) {
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
static int saved_log_context_enabled = -1;
|
||||
|
||||
bool log_context_enabled(void) {
|
||||
int r;
|
||||
|
||||
if (log_get_max_level() == LOG_DEBUG)
|
||||
return true;
|
||||
|
||||
if (saved_log_context_enabled >= 0)
|
||||
return saved_log_context_enabled;
|
||||
|
||||
r = secure_getenv_bool("SYSTEMD_ENABLE_LOG_CONTEXT");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_ENABLE_LOG_CONTEXT, ignoring: %m");
|
||||
|
||||
saved_log_context_enabled = r > 0;
|
||||
|
||||
return saved_log_context_enabled;
|
||||
}
|
||||
|
||||
static LogContext* log_context_attach(LogContext *c) {
|
||||
assert(c);
|
||||
|
||||
_log_context_num_fields += strv_length(c->fields);
|
||||
_log_context_num_fields += c->n_input_iovec;
|
||||
_log_context_num_fields += !!c->key;
|
||||
|
||||
return LIST_PREPEND(ll, _log_context, c);
|
||||
}
|
||||
|
||||
static LogContext* log_context_detach(LogContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
assert(_log_context_num_fields >= strv_length(c->fields) + c->n_input_iovec +!!c->key);
|
||||
_log_context_num_fields -= strv_length(c->fields);
|
||||
_log_context_num_fields -= c->n_input_iovec;
|
||||
_log_context_num_fields -= !!c->key;
|
||||
|
||||
LIST_REMOVE(ll, _log_context, c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LogContext* log_context_new(const char *key, const char *value) {
|
||||
assert(key);
|
||||
assert(endswith(key, "="));
|
||||
assert(value);
|
||||
|
||||
LIST_FOREACH(ll, i, _log_context)
|
||||
if (i->key == key && i->value == value)
|
||||
return log_context_ref(i);
|
||||
|
||||
LogContext *c = new(LogContext, 1);
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
*c = (LogContext) {
|
||||
.n_ref = 1,
|
||||
.key = (char *) key,
|
||||
.value = (char *) value,
|
||||
};
|
||||
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
LogContext* log_context_new_strv(char **fields, bool owned) {
|
||||
if (!fields)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(ll, i, _log_context)
|
||||
if (i->fields == fields) {
|
||||
assert(!owned);
|
||||
return log_context_ref(i);
|
||||
}
|
||||
|
||||
LogContext *c = new(LogContext, 1);
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
*c = (LogContext) {
|
||||
.n_ref = 1,
|
||||
.fields = fields,
|
||||
.owned = owned,
|
||||
};
|
||||
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
LogContext* log_context_new_iov(struct iovec *input_iovec, size_t n_input_iovec, bool owned) {
|
||||
if (!input_iovec || n_input_iovec == 0)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(ll, i, _log_context)
|
||||
if (i->input_iovec == input_iovec && i->n_input_iovec == n_input_iovec) {
|
||||
assert(!owned);
|
||||
return log_context_ref(i);
|
||||
}
|
||||
|
||||
LogContext *c = new(LogContext, 1);
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
*c = (LogContext) {
|
||||
.n_ref = 1,
|
||||
.input_iovec = input_iovec,
|
||||
.n_input_iovec = n_input_iovec,
|
||||
.owned = owned,
|
||||
};
|
||||
|
||||
return log_context_attach(c);
|
||||
}
|
||||
|
||||
static LogContext* log_context_free(LogContext *c) {
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
log_context_detach(c);
|
||||
|
||||
if (c->owned) {
|
||||
strv_free(c->fields);
|
||||
iovec_array_free(c->input_iovec, c->n_input_iovec);
|
||||
free(c->key);
|
||||
free(c->value);
|
||||
}
|
||||
|
||||
return mfree(c);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(LogContext, log_context, log_context_free);
|
||||
|
||||
LogContext* log_context_new_strv_consume(char **fields) {
|
||||
LogContext *c = log_context_new_strv(fields, /*owned=*/ true);
|
||||
if (!c)
|
||||
strv_free(fields);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
LogContext* log_context_new_iov_consume(struct iovec *input_iovec, size_t n_input_iovec) {
|
||||
LogContext *c = log_context_new_iov(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;
|
||||
|
||||
LIST_FOREACH(ll, c, _log_context)
|
||||
n++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t log_context_num_fields(void) {
|
||||
return _log_context_num_fields;
|
||||
}
|
||||
|
||||
-109
@@ -411,112 +411,3 @@ static inline const char* _log_unset_prefixp(const char **p) {
|
||||
|
||||
#define LOG_SET_PREFIX(prefix) \
|
||||
_cleanup_(_log_unset_prefixp) _unused_ const char *CONCATENATE(_cleanup_log_unset_prefix_, UNIQ) = _log_set_prefix(prefix, false);
|
||||
|
||||
/*
|
||||
* The log context allows attaching extra metadata to log messages written to the journal via log.h. We keep
|
||||
* track of a thread local log context onto which we can push extra metadata fields that should be logged.
|
||||
*
|
||||
* LOG_CONTEXT_PUSH() will add the provided field to the log context and will remove it again when the
|
||||
* current block ends. LOG_CONTEXT_PUSH_STRV() will do the same but for all fields in the given strv.
|
||||
* LOG_CONTEXT_PUSHF() is like LOG_CONTEXT_PUSH() but takes a format string and arguments.
|
||||
*
|
||||
* Using the macros is as simple as putting them anywhere inside a block to add a field to all following log
|
||||
* messages logged from inside that block.
|
||||
*
|
||||
* void myfunction(...) {
|
||||
* ...
|
||||
*
|
||||
* LOG_CONTEXT_PUSHF("MYMETADATA=%s", "abc");
|
||||
*
|
||||
* // Every journal message logged will now have the MYMETADATA=abc
|
||||
* // field included.
|
||||
* }
|
||||
*
|
||||
* One special case to note is async code, where we use callbacks that are invoked to continue processing
|
||||
* when some event occurs. For async code, there's usually an associated "userdata" struct containing all the
|
||||
* information associated with the async operation. In this "userdata" struct, we can store a log context
|
||||
* allocated with log_context_new() and freed with log_context_free(). We can then add and remove fields to
|
||||
* the `fields` member of the log context object and all those fields will be logged along with each log
|
||||
* message.
|
||||
*/
|
||||
|
||||
typedef struct LogContext LogContext;
|
||||
|
||||
bool log_context_enabled(void);
|
||||
|
||||
LogContext* log_context_new(const char *key, const char *value);
|
||||
LogContext* log_context_new_strv(char **fields, bool owned);
|
||||
LogContext* log_context_new_iov(struct iovec *input_iovec, size_t n_input_iovec, bool owned);
|
||||
|
||||
/* Same as log_context_new(), but frees the given fields strv/iovec on failure. */
|
||||
LogContext* log_context_new_strv_consume(char **fields);
|
||||
LogContext* log_context_new_iov_consume(struct iovec *input_iovec, size_t n_input_iovec);
|
||||
|
||||
LogContext *log_context_ref(LogContext *c);
|
||||
LogContext *log_context_unref(LogContext *c);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_unref);
|
||||
|
||||
/* Returns the number of attached log context objects. */
|
||||
size_t log_context_num_contexts(void);
|
||||
/* Returns the number of fields in all attached log contexts. */
|
||||
size_t log_context_num_fields(void);
|
||||
|
||||
static inline void _reset_log_level(int *saved_log_level) {
|
||||
assert(saved_log_level);
|
||||
|
||||
log_set_max_level(*saved_log_level);
|
||||
}
|
||||
|
||||
#define LOG_CONTEXT_SET_LOG_LEVEL(level) \
|
||||
_cleanup_(_reset_log_level) _unused_ int _saved_log_level_ = log_set_max_level(level);
|
||||
|
||||
#define LOG_CONTEXT_PUSH(...) \
|
||||
LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__))
|
||||
|
||||
#define LOG_CONTEXT_PUSHF(...) \
|
||||
LOG_CONTEXT_PUSH(snprintf_ok((char[LINE_MAX]) {}, LINE_MAX, __VA_ARGS__))
|
||||
|
||||
#define _LOG_CONTEXT_PUSH_KEY_VALUE(key, value, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new(key, value);
|
||||
|
||||
#define LOG_CONTEXT_PUSH_KEY_VALUE(key, value) \
|
||||
_LOG_CONTEXT_PUSH_KEY_VALUE(key, value, UNIQ_T(c, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_PUSH_STRV(strv, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv(strv, /*owned=*/ false);
|
||||
|
||||
#define LOG_CONTEXT_PUSH_STRV(strv) \
|
||||
_LOG_CONTEXT_PUSH_STRV(strv, UNIQ_T(c, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_iov(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) \
|
||||
_unused_ _cleanup_strv_free_ strv = strv_new(s); \
|
||||
if (!strv) \
|
||||
free(s); \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(TAKE_PTR(strv))
|
||||
|
||||
#define LOG_CONTEXT_CONSUME_STR(s) \
|
||||
_LOG_CONTEXT_CONSUME_STR(s, UNIQ_T(c, UNIQ), UNIQ_T(sv, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_CONSUME_STRV(strv, c) \
|
||||
_unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(strv);
|
||||
|
||||
#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_unrefp) LogContext *c = log_context_new_iov_consume(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))
|
||||
|
||||
@@ -58,6 +58,7 @@ basic_sources = files(
|
||||
'locale-util.c',
|
||||
'lock-util.c',
|
||||
'log.c',
|
||||
'log-context.c',
|
||||
'login-util.c',
|
||||
'keyring-util.c',
|
||||
'memfd-util.c',
|
||||
|
||||
Reference in New Issue
Block a user