]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Allow to specify max log tag length for all log messages 5492/head
authorVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 5 Jun 2025 14:00:39 +0000 (15:00 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 5 Jun 2025 14:00:39 +0000 (15:00 +0100)
src/libserver/cfg_file.h
src/libserver/cfg_rcl.cxx
src/libserver/logger/logger.c
src/libserver/logger/logger_private.h
src/libutil/mem_pool.c
src/libutil/mem_pool.h

index f59c6ff89ea99210eaa0f001b7e1a1f0e7941d26..2d0797c98613910fc0f79e697159d7edb3a2f6c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 Vsevolod Stakhov
+ * Copyright 2025 Vsevolod Stakhov
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -395,6 +395,8 @@ struct rspamd_config {
        unsigned int log_error_elts;                        /**< number of elements in error logbuf                                     */
        unsigned int log_error_elt_maxlen;                  /**< maximum size of error log element                                      */
        unsigned int log_task_max_elts;                     /**< maximum number of elements in task logging                     */
+       unsigned int log_max_tag_len;                       /**< maximum length of log tag                                                      */
+       char *log_tag_strip_policy_str;                     /**< log tag strip policy string                                            */
        struct rspamd_worker_log_pipe *log_pipes;
 
        gboolean compat_messages; /**< use old messages in the protocol (array)                         */
index b42a40499b35982d4c4d1e2128d134d17c96e967..0a48e8a4f435b43602498a6e3a4ea8cdf8e36abb 100644 (file)
@@ -299,6 +299,14 @@ rspamd_rcl_logging_handler(rspamd_mempool_t *pool, const ucl_object_t *obj,
                cfg->log_flags |= RSPAMD_LOG_FLAG_USEC;
        }
 
+       /* Set default values for new log tag options */
+       if (cfg->log_max_tag_len == 0) {
+               cfg->log_max_tag_len = RSPAMD_LOG_ID_LEN; /* Default to new max size */
+       }
+       if (cfg->log_tag_strip_policy_str == NULL) {
+               cfg->log_tag_strip_policy_str = rspamd_mempool_strdup(cfg->cfg_pool, "right");
+       }
+
        return rspamd_rcl_section_parse_defaults(cfg, *section, cfg->cfg_pool, obj,
                                                                                         (void *) cfg, err);
 }
@@ -1700,6 +1708,18 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections)
                                                                           G_STRUCT_OFFSET(struct rspamd_config, log_task_max_elts),
                                                                           RSPAMD_CL_FLAG_UINT,
                                                                           "Maximum number of elements in task log entry (7 by default)");
+               rspamd_rcl_add_default_handler(sub,
+                                                                          "max_tag_len",
+                                                                          rspamd_rcl_parse_struct_integer,
+                                                                          G_STRUCT_OFFSET(struct rspamd_config, log_max_tag_len),
+                                                                          RSPAMD_CL_FLAG_UINT,
+                                                                          "Maximum length of log tag cannot exceed 32 (" G_STRINGIFY(RSPAMD_LOG_ID_LEN) ") by default)");
+               rspamd_rcl_add_default_handler(sub,
+                                                                          "tag_strip_policy",
+                                                                          rspamd_rcl_parse_struct_string,
+                                                                          G_STRUCT_OFFSET(struct rspamd_config, log_tag_strip_policy_str),
+                                                                          0,
+                                                                          "Log tag strip policy when tag exceeds max length: 'right', 'left', 'middle' (right by default)");
 
                /* Documentation only options, handled in log_handler to map flags */
                rspamd_rcl_add_doc_by_path(cfg,
index dc0a85a05ae196d7ef486f81ef07120c102a0505..600b7f1e15251f69a24d1d8b37c153d68862ce4e 100644 (file)
@@ -22,7 +22,6 @@
 #include "unix-std.h"
 #include "logger_private.h"
 
-
 static rspamd_logger_t *default_logger = NULL;
 static rspamd_logger_t *emergency_logger = NULL;
 static struct rspamd_log_modules *log_modules = NULL;
@@ -30,6 +29,61 @@ static struct rspamd_log_modules *log_modules = NULL;
 static const char lf_chr = '\n';
 
 unsigned int rspamd_task_log_id = (unsigned int) -1;
+
+/**
+ * Strip log tag according to the configured policy
+ * @param original_tag original log tag
+ * @param original_len length of original tag
+ * @param dest destination buffer
+ * @param max_len maximum length allowed
+ * @param policy stripping policy
+ * @return actual length of stripped tag
+ */
+static gsize
+rspamd_log_strip_tag(const char *original_tag, gsize original_len,
+                                        char *dest, gsize max_len,
+                                        enum rspamd_log_tag_strip_policy policy)
+{
+       if (original_len <= max_len) {
+               /* No stripping needed */
+               memcpy(dest, original_tag, original_len);
+               return original_len;
+       }
+
+       switch (policy) {
+       case RSPAMD_LOG_TAG_STRIP_RIGHT:
+               /* Cut right part (current behavior) */
+               memcpy(dest, original_tag, max_len);
+               return max_len;
+
+       case RSPAMD_LOG_TAG_STRIP_LEFT:
+               /* Cut left part (take last elements) */
+               memcpy(dest, original_tag + (original_len - max_len), max_len);
+               return max_len;
+
+       case RSPAMD_LOG_TAG_STRIP_MIDDLE:
+               /* Half from start and half from end */
+               if (max_len >= 2) {
+                       gsize first_half = max_len / 2;
+                       gsize second_half = max_len - first_half;
+
+                       memcpy(dest, original_tag, first_half);
+                       memcpy(dest + first_half,
+                                  original_tag + (original_len - second_half),
+                                  second_half);
+               }
+               else if (max_len == 1) {
+                       /* Just take first character */
+                       dest[0] = original_tag[0];
+               }
+               return max_len;
+
+       default:
+               /* Fallback to right stripping */
+               memcpy(dest, original_tag, max_len);
+               return max_len;
+       }
+}
 RSPAMD_CONSTRUCTOR(rspamd_task_log_init)
 {
        rspamd_task_log_id = rspamd_logger_add_debug_module("task");
@@ -160,6 +214,10 @@ rspamd_log_open_emergency(rspamd_mempool_t *pool, int flags)
        logger->process_type = "main";
        logger->pid = getpid();
 
+       /* Initialize log tag configuration with defaults */
+       logger->max_log_tag_len = RSPAMD_LOG_ID_LEN; /* Keep backward compatibility default */
+       logger->log_tag_strip_policy = RSPAMD_LOG_TAG_STRIP_RIGHT;
+
        const struct rspamd_logger_funcs *funcs = &console_log_funcs;
        memcpy(&logger->ops, funcs, sizeof(*funcs));
 
@@ -258,6 +316,28 @@ rspamd_log_open_specific(rspamd_mempool_t *pool,
        logger->process_type = ptype;
        logger->enabled = TRUE;
 
+       /* Initialize log tag configuration with defaults */
+       if (cfg && cfg->log_max_tag_len > 0) {
+               logger->max_log_tag_len = MIN(MEMPOOL_UID_LEN, cfg->log_max_tag_len);
+       }
+       else {
+               logger->max_log_tag_len = RSPAMD_LOG_ID_LEN; /* Keep backward compatibility default */
+       }
+
+       logger->log_tag_strip_policy = RSPAMD_LOG_TAG_STRIP_RIGHT;
+
+       if (cfg && cfg->log_tag_strip_policy_str) {
+               if (g_ascii_strcasecmp(cfg->log_tag_strip_policy_str, "left") == 0) {
+                       logger->log_tag_strip_policy = RSPAMD_LOG_TAG_STRIP_LEFT;
+               }
+               else if (g_ascii_strcasecmp(cfg->log_tag_strip_policy_str, "middle") == 0) {
+                       logger->log_tag_strip_policy = RSPAMD_LOG_TAG_STRIP_MIDDLE;
+               }
+               else {
+                       logger->log_tag_strip_policy = RSPAMD_LOG_TAG_STRIP_RIGHT; /* Default */
+               }
+       }
+
        /* Set up conditional logging */
        if (cfg) {
                if (cfg->debug_ip_map != NULL) {
@@ -1026,16 +1106,34 @@ log_time(double now, rspamd_logger_t *rspamd_log, char *timebuf,
        }
 }
 
+/**
+ * Process log ID with stripping policy and return the effective length
+ * @param logger logger instance with configuration
+ * @param id original log ID
+ * @param processed_id buffer to store processed ID (should be at least max_log_tag_len + 1)
+ * @return effective length of processed ID
+ */
 static inline int
-rspamd_log_id_strlen(const char *id)
+rspamd_log_process_id(rspamd_logger_t *logger, const char *id, char *processed_id)
 {
-       for (int i = 0; i < RSPAMD_LOG_ID_LEN; i++) {
-               if (G_UNLIKELY(id[i] == '\0')) {
-                       return i;
-               }
+       if (id == NULL) {
+               return 0;
+       }
+
+       gsize original_len = strlen(id);
+       gsize max_len = MIN(MEMPOOL_UID_LEN, logger->max_log_tag_len);
+
+       if (original_len <= max_len) {
+               /* No processing needed */
+               memcpy(processed_id, id, original_len);
+               return original_len;
        }
 
-       return RSPAMD_LOG_ID_LEN;
+       /* Apply stripping policy */
+       gsize processed_len = rspamd_log_strip_tag(id, original_len, processed_id, max_len,
+                                                                                          logger->log_tag_strip_policy);
+
+       return processed_len;
 }
 
 void rspamd_log_fill_iov(struct rspamd_logger_iov_ctx *iov_ctx,
@@ -1071,8 +1169,17 @@ void rspamd_log_fill_iov(struct rspamd_logger_iov_ctx *iov_ctx,
 
        if (G_UNLIKELY(log_json)) {
                /* Perform JSON logging */
-               unsigned int slen = id ? strlen(id) : strlen("(NULL)");
-               slen = MIN(RSPAMD_LOG_ID_LEN, slen);
+               char processed_id[MEMPOOL_UID_LEN];
+               int processed_len = 0;
+
+               if (id) {
+                       processed_len = rspamd_log_process_id(logger, id, processed_id);
+               }
+               else {
+                       strcpy(processed_id, "(NULL)");
+                       processed_len = strlen(processed_id);
+               }
+
                r = rspamd_snprintf(tmpbuf, sizeof(tmpbuf), "{\"ts\": %f, "
                                                                                                        "\"pid\": %P, "
                                                                                                        "\"severity\": \"%s\", "
@@ -1085,7 +1192,7 @@ void rspamd_log_fill_iov(struct rspamd_logger_iov_ctx *iov_ctx,
                                                        logger->pid,
                                                        rspamd_get_log_severity_string(level_flags),
                                                        logger->process_type,
-                                                       slen, id,
+                                                       processed_len, processed_id,
                                                        module,
                                                        function);
                iov_ctx->iov[0].iov_base = tmpbuf;
@@ -1241,14 +1348,17 @@ void rspamd_log_fill_iov(struct rspamd_logger_iov_ctx *iov_ctx,
 
                glong mremain, mr;
                char *m;
+               char processed_id[MEMPOOL_UID_LEN];
+               int processed_len = 0;
 
                modulebuf[0] = '\0';
                mremain = sizeof(modulebuf);
                m = modulebuf;
 
                if (id != NULL) {
-                       mr = rspamd_snprintf(m, mremain, "<%*.s>; ", rspamd_log_id_strlen(id),
-                                                                id);
+                       processed_len = rspamd_log_process_id(logger, id, processed_id);
+                       mr = rspamd_snprintf(m, mremain, "<%*.s>; ", processed_len,
+                                                                processed_id);
                        m += mr;
                        mremain -= mr;
                }
@@ -1300,10 +1410,13 @@ void rspamd_log_fill_iov(struct rspamd_logger_iov_ctx *iov_ctx,
                        iov_ctx->iov[niov].iov_base = (void *) timebuf;
                        iov_ctx->iov[niov++].iov_len = strlen(timebuf);
                        if (id != NULL) {
+                               char processed_id[MEMPOOL_UID_LEN];
+                               int processed_len = rspamd_log_process_id(logger, id, processed_id);
+
                                iov_ctx->iov[niov].iov_base = (void *) "; ";
                                iov_ctx->iov[niov++].iov_len = 2;
-                               iov_ctx->iov[niov].iov_base = (void *) id;
-                               iov_ctx->iov[niov++].iov_len = rspamd_log_id_strlen(id);
+                               iov_ctx->iov[niov].iov_base = (void *) processed_id;
+                               iov_ctx->iov[niov++].iov_len = processed_len;
                                iov_ctx->iov[niov].iov_base = (void *) ";";
                                iov_ctx->iov[niov++].iov_len = 1;
                        }
index 80178ad3273eda0449431a2b7520420e7e861bed..387d8639b10fde9215adfba458ebbd000f656ca5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 Vsevolod Stakhov
+ * Copyright 2025 Vsevolod Stakhov
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #define REPEATS_MAX 300
 #define LOGBUF_LEN 8192
 
+enum rspamd_log_tag_strip_policy {
+       RSPAMD_LOG_TAG_STRIP_RIGHT = 0, /* Cut right part (current behavior) */
+       RSPAMD_LOG_TAG_STRIP_LEFT,      /* Cut left part (take last elements) */
+       RSPAMD_LOG_TAG_STRIP_MIDDLE,    /* Half from start and half from end */
+};
+
 struct rspamd_log_module {
        char *mname;
        unsigned int id;
@@ -73,6 +79,10 @@ struct rspamd_logger_s {
        gboolean is_debug;
        gboolean no_lock;
 
+       /* Log tag configuration */
+       unsigned int max_log_tag_len;
+       enum rspamd_log_tag_strip_policy log_tag_strip_policy;
+
        pid_t pid;
        const char *process_type;
        struct rspamd_radix_map_helper *debug_ip;
index 3dc67bc5f57fc2f88b53b2f35422b75225d2bfa9..575b4e4970205d3f70f1ef80e3efb243f2fd522e 100644 (file)
@@ -403,9 +403,10 @@ rspamd_mempool_new_(gsize size, const char *tag, int flags, const char *loc)
 
        /* Generate new uid */
        uint64_t uid = rspamd_random_uint64_fast();
-       rspamd_encode_hex_buf((unsigned char *) &uid, sizeof(uid),
-                                                 new_pool->tag.uid, sizeof(new_pool->tag.uid) - 1);
-       new_pool->tag.uid[sizeof(new_pool->tag.uid) - 1] = '\0';
+       G_STATIC_ASSERT(sizeof(new_pool->tag.uid) >= sizeof(uid) * 2 + 1);
+       int enc_len = rspamd_encode_hex_buf((unsigned char *) &uid, sizeof(uid),
+                                                                               new_pool->tag.uid, sizeof(new_pool->tag.uid) - 1);
+       new_pool->tag.uid[enc_len] = '\0';
 
        mem_pool_stat->pools_allocated++;
 
index 651b44661961d9e880fb131de9fae91598c5634f..00d1a20676498b5a14eb6613b2f85bfde7c48e3e 100644 (file)
@@ -71,7 +71,7 @@ struct f_str_s;
 #endif
 
 #define MEMPOOL_TAG_LEN 16
-#define MEMPOOL_UID_LEN 16
+#define MEMPOOL_UID_LEN 32
 /* All pointers are aligned as this variable */
 #define MIN_MEM_ALIGNMENT G_MEM_ALIGN