]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
log: Add key/value support to the log context
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 21 Mar 2023 13:51:56 +0000 (14:51 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 21 Mar 2023 13:54:04 +0000 (14:54 +0100)
Now that we have reference counting, it's useful to be able to push
single key values onto the log context separately, so that we don't
have to allocate new storage to join the separate string together into
a single field which means we won't be able to reuse a context containing
the same field.

src/basic/log.c
src/basic/log.h
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-device/device-monitor.c
src/test/test-log.c

index c713b9ac88d28af99a2158a3ddc0f99d2d88b7ba..6b847c37757ee0468f671c9381137b98518c8148 100644 (file)
@@ -42,7 +42,7 @@
 #include "utf8.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
-#define IOVEC_MAX 128U
+#define IOVEC_MAX 256U
 
 static log_syntax_callback_t log_syntax_callback = NULL;
 static void *log_syntax_callback_userdata = NULL;
@@ -79,6 +79,8 @@ typedef struct LogContext {
         char **fields;
         struct iovec *input_iovec;
         size_t n_input_iovec;
+        char *key;
+        char *value;
         bool owned;
         LIST_FIELDS(struct LogContext, ll);
 } LogContext;
@@ -632,6 +634,15 @@ static void log_do_context(struct iovec *iovec, size_t iovec_len, size_t *n) {
                         iovec[(*n)++] = c->input_iovec[i];
                         iovec[(*n)++] = IOVEC_MAKE_STRING("\n");
                 }
+
+                if (c->key && c->value) {
+                        if (*n + 3 >= iovec_len)
+                                return;
+
+                        iovec[(*n)++] = IOVEC_MAKE_STRING(c->key);
+                        iovec[(*n)++] = IOVEC_MAKE_STRING(c->value);
+                        iovec[(*n)++] = IOVEC_MAKE_STRING("\n");
+                }
         }
 }
 
@@ -1568,6 +1579,7 @@ static LogContext* log_context_attach(LogContext *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);
 }
@@ -1576,15 +1588,38 @@ static LogContext* log_context_detach(LogContext *c) {
         if (!c)
                 return NULL;
 
-        assert(_log_context_num_fields >= strv_length(c->fields) + c->n_input_iovec);
+        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(char **fields, bool owned) {
+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;
 
@@ -1607,7 +1642,7 @@ 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) {
+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;
 
@@ -1640,6 +1675,8 @@ static LogContext* log_context_free(LogContext *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);
@@ -1647,16 +1684,16 @@ static LogContext* log_context_free(LogContext *c) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(LogContext, log_context, log_context_free);
 
-LogContext* log_context_new_consume(char **fields) {
-        LogContext *c = log_context_new(fields, /*owned=*/ true);
+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_consumev(struct iovec *input_iovec, size_t n_input_iovec) {
-        LogContext *c = log_context_newv(input_iovec, n_input_iovec, /*owned=*/ true);
+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);
 
index f17a97ee370212164062e7fc357ab0daa8ff0794..28af01f68b8798e427bc1ac01366af8ed60d5e1b 100644 (file)
@@ -457,12 +457,13 @@ typedef struct LogContext LogContext;
 
 bool log_context_enabled(void);
 
-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_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_consume(char **fields);
-LogContext* log_context_new_consumev(struct iovec *input_iovec, size_t n_input_iovec);
+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);
@@ -480,14 +481,20 @@ size_t log_context_num_fields(void);
 #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, /*owned=*/ false);
+        _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_newv(input_iovec, n_input_iovec, /*owned=*/ false);
+        _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))
@@ -501,19 +508,19 @@ size_t log_context_num_fields(void);
         _unused_ _cleanup_strv_free_ strv = strv_new(s);                                                \
         if (!strv)                                                                                      \
                 free(s);                                                                                \
-        _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_consume(TAKE_PTR(strv))
+        _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_consume(strv);
+        _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_consumev(input_iovec, n_input_iovec);
+        _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))
index 4387db3841b53a05970a295e88389661f7402e38..6ee8bb7a7ffeec8c8fa443c84088ada8d8bb2f26 100644 (file)
@@ -2950,7 +2950,7 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
         bus->iteration_counter++;
 
         if (log_context_enabled())
-                c = log_context_new_consume(bus_message_make_log_fields(m));
+                c = log_context_new_strv_consume(bus_message_make_log_fields(m));
 
         log_debug_bus_message(m);
 
index 1d8b7550b66dfae66d51486b4d7715d59330139d..af093385da8355093d87b828f2263208d346b97b 100644 (file)
@@ -249,7 +249,7 @@ static int device_monitor_event_handler(sd_event_source *s, int fd, uint32_t rev
                 return 0;
 
         if (log_context_enabled())
-                c = log_context_new_consume(device_make_log_fields(device));
+                c = log_context_new_strv_consume(device_make_log_fields(device));
 
         if (m->callback)
                 return m->callback(m, device, m->userdata);
index cfbd45c2e34f84850a15d5d20976394fc064a4c6..4fc4bc90874e8c062b1cfc9a3aaaee8f065b857c 100644 (file)
@@ -116,7 +116,7 @@ static void test_log_context(void) {
                 _cleanup_(log_context_unrefp) LogContext *ctx = NULL;
 
                 char **strv = STRV_MAKE("SIXTH=ijn", "SEVENTH=PRP");
-                assert_se(ctx = log_context_new(strv, /*owned=*/ false));
+                assert_se(ctx = log_context_new_strv(strv, /*owned=*/ false));
 
                 assert_se(log_context_num_contexts() == 1);
                 assert_se(log_context_num_fields() == 2);
@@ -160,6 +160,17 @@ static void test_log_context(void) {
                 test_log_syntax();
         }
 
+        {
+                LOG_CONTEXT_PUSH_KEY_VALUE("ABC=", "QED");
+                LOG_CONTEXT_PUSH_KEY_VALUE("ABC=", "QED");
+                assert_se(log_context_num_contexts() == 1);
+                assert_se(log_context_num_fields() == 1);
+
+                test_log_struct();
+                test_long_lines();
+                test_log_syntax();
+        }
+
         assert_se(log_context_num_contexts() == 0);
         assert_se(log_context_num_fields() == 0);
 }