]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: log: carry tag context in logformat node
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 22 Feb 2024 19:20:41 +0000 (20:20 +0100)
committerAurelien DARRAGON <adarragon@haproxy.com>
Thu, 4 Apr 2024 17:10:01 +0000 (19:10 +0200)
This is a pretty simple patch despite requiring to make some visible
changes in the code:

When parsing a logformat string, log tags (ie: '%tag', AKA log tags) are
turned into logformat nodes with their type set to the type of the
corresponding logformat_tag element which was matched by name. Thus, when
"compiling" a logformat tag, we only keep a reference to the tag type
from the original logformat_tag.

For example, for "%B" log tag, we have the following logformat_tag
element:

  {
    .name = "B",
    .type = LOG_FMT_BYTES,
    .mode = PR_MODE_TCP,
    .lw = LW_BYTES,
    .config_callback = NULL
  }

When parsing "%B" string, we search for a matching logformat tag
inside logformat_tags[] array using the provided name, once we find a
matching element, we craft a logformat node whose type will be
LOG_FMT_BYTES, but from the node itself, we no longer have access to
other informations that are set in the logformat_tag struct element.

Thus from a logformat_node resulting from a log tag, with current
implementation, we cannot easily get back to matching logformat_tag
struct element as it would require us to scan the whole logformat_tags
array at runtime using node->type to find the matching element.

Let's take a simpler path and consider all tag-specific LOG_FMT_*
subtypes as being part of the same logformat node type: LOG_FMT_TAG.

Thanks to that, we're now able to distinguish logformat nodes made
from logformat tag from other logformat nodes, and link them to
their corresponding logformat_tag element from logformat_tags[] array. All
it costs is a simple indirection and an extra pointer in logformat_node
struct.

While at it, all LOG_FMT_* types related to logformat tags were moved
inside log.c as they have no use outside of it since they are simply
lookup indexes for sess_build_logline() and could even be replaced by
function pointers some day...

include/haproxy/log-t.h
src/log.c

index 5f77c2b5d67286b0c53d26fce64ca67d496d43a2..91e418051dc373212462fc85aa9e00b69d4bc4ec 100644 (file)
@@ -122,75 +122,10 @@ enum log_tgt {
 /* lists of fields that can be logged, for logformat_node->type */
 enum {
 
-       LOG_FMT_TEXT = 0, /* raw text */
-       LOG_FMT_EXPR,     /* sample expression */
+       LOG_FMT_TEXT = 0,  /* raw text */
+       LOG_FMT_EXPR,      /* sample expression */
        LOG_FMT_SEPARATOR, /* separator replaced by one space */
-
-       /* information fields */
-       LOG_FMT_GLOBAL,
-       LOG_FMT_CLIENTIP,
-       LOG_FMT_CLIENTPORT,
-       LOG_FMT_BACKENDIP,
-       LOG_FMT_BACKENDPORT,
-       LOG_FMT_FRONTENDIP,
-       LOG_FMT_FRONTENDPORT,
-       LOG_FMT_SERVERPORT,
-       LOG_FMT_SERVERIP,
-       LOG_FMT_COUNTER,
-       LOG_FMT_LOGCNT,
-       LOG_FMT_PID,
-       LOG_FMT_DATE,
-       LOG_FMT_DATEGMT,
-       LOG_FMT_DATELOCAL,
-       LOG_FMT_TS,
-       LOG_FMT_MS,
-       LOG_FMT_FRONTEND,
-       LOG_FMT_FRONTEND_XPRT,
-       LOG_FMT_BACKEND,
-       LOG_FMT_SERVER,
-       LOG_FMT_BYTES,
-       LOG_FMT_BYTES_UP,
-       LOG_FMT_Ta,
-       LOG_FMT_Th,
-       LOG_FMT_Ti,
-       LOG_FMT_TQ,
-       LOG_FMT_TW,
-       LOG_FMT_TC,
-       LOG_FMT_Tr,
-       LOG_FMT_tr,
-       LOG_FMT_trg,
-       LOG_FMT_trl,
-       LOG_FMT_TR,
-       LOG_FMT_TD,
-       LOG_FMT_TT,
-       LOG_FMT_TU,
-       LOG_FMT_STATUS,
-       LOG_FMT_CCLIENT,
-       LOG_FMT_CSERVER,
-       LOG_FMT_TERMSTATE,
-       LOG_FMT_TERMSTATE_CK,
-       LOG_FMT_ACTCONN,
-       LOG_FMT_FECONN,
-       LOG_FMT_BECONN,
-       LOG_FMT_SRVCONN,
-       LOG_FMT_RETRIES,
-       LOG_FMT_SRVQUEUE,
-       LOG_FMT_BCKQUEUE,
-       LOG_FMT_HDRREQUEST,
-       LOG_FMT_HDRRESPONS,
-       LOG_FMT_HDRREQUESTLIST,
-       LOG_FMT_HDRRESPONSLIST,
-       LOG_FMT_REQ,
-       LOG_FMT_HTTP_METHOD,
-       LOG_FMT_HTTP_URI,
-       LOG_FMT_HTTP_PATH,
-       LOG_FMT_HTTP_PATH_ONLY,
-       LOG_FMT_HTTP_QUERY,
-       LOG_FMT_HTTP_VERSION,
-       LOG_FMT_HOSTNAME,
-       LOG_FMT_UNIQUEID,
-       LOG_FMT_SSL_CIPHER,
-       LOG_FMT_SSL_VERSION,
+       LOG_FMT_TAG,       /* reference to logformat_tag */
 };
 
 /* enum for parse_logformat_string */
@@ -230,6 +165,7 @@ struct logformat_node {
        char *name;    // printable name for output types that require named fields (ie: json)
        char *arg;     // text for LOG_FMT_TEXT, arg for others
        void *expr;    // for use with LOG_FMT_EXPR
+       const struct logformat_tag *tag; // set if ->type == LOG_FMT_TAG
 };
 
 /* Range of indexes for log sampling. */
index ecb475f1e7534e384b0562c439d80141bd4d4eb8..1dcdd4ba4f13ecdabae9d120e89fce6a2eb4dffe 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -121,6 +121,74 @@ const char sess_fin_state[8]  = "-RCHDLQT";        /* cliRequest, srvConnect, srvHeader
 
 int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
 
+/* logformat tag types (internal use) */
+enum logformat_tag_type {
+       LOG_FMT_GLOBAL,
+       LOG_FMT_CLIENTIP,
+       LOG_FMT_CLIENTPORT,
+       LOG_FMT_BACKENDIP,
+       LOG_FMT_BACKENDPORT,
+       LOG_FMT_FRONTENDIP,
+       LOG_FMT_FRONTENDPORT,
+       LOG_FMT_SERVERPORT,
+       LOG_FMT_SERVERIP,
+       LOG_FMT_COUNTER,
+       LOG_FMT_LOGCNT,
+       LOG_FMT_PID,
+       LOG_FMT_DATE,
+       LOG_FMT_DATEGMT,
+       LOG_FMT_DATELOCAL,
+       LOG_FMT_TS,
+       LOG_FMT_MS,
+       LOG_FMT_FRONTEND,
+       LOG_FMT_FRONTEND_XPRT,
+       LOG_FMT_BACKEND,
+       LOG_FMT_SERVER,
+       LOG_FMT_BYTES,
+       LOG_FMT_BYTES_UP,
+       LOG_FMT_Ta,
+       LOG_FMT_Th,
+       LOG_FMT_Ti,
+       LOG_FMT_TQ,
+       LOG_FMT_TW,
+       LOG_FMT_TC,
+       LOG_FMT_Tr,
+       LOG_FMT_tr,
+       LOG_FMT_trg,
+       LOG_FMT_trl,
+       LOG_FMT_TR,
+       LOG_FMT_TD,
+       LOG_FMT_TT,
+       LOG_FMT_TU,
+       LOG_FMT_STATUS,
+       LOG_FMT_CCLIENT,
+       LOG_FMT_CSERVER,
+       LOG_FMT_TERMSTATE,
+       LOG_FMT_TERMSTATE_CK,
+       LOG_FMT_ACTCONN,
+       LOG_FMT_FECONN,
+       LOG_FMT_BECONN,
+       LOG_FMT_SRVCONN,
+       LOG_FMT_RETRIES,
+       LOG_FMT_SRVQUEUE,
+       LOG_FMT_BCKQUEUE,
+       LOG_FMT_HDRREQUEST,
+       LOG_FMT_HDRRESPONS,
+       LOG_FMT_HDRREQUESTLIST,
+       LOG_FMT_HDRRESPONSLIST,
+       LOG_FMT_REQ,
+       LOG_FMT_HTTP_METHOD,
+       LOG_FMT_HTTP_URI,
+       LOG_FMT_HTTP_PATH,
+       LOG_FMT_HTTP_PATH_ONLY,
+       LOG_FMT_HTTP_QUERY,
+       LOG_FMT_HTTP_VERSION,
+       LOG_FMT_HOSTNAME,
+       LOG_FMT_UNIQUEID,
+       LOG_FMT_SSL_CIPHER,
+       LOG_FMT_SSL_VERSION,
+};
+
 /* log_format tag names */
 static const struct logformat_tag logformat_tags[] = {
        { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL },  /* global option */
@@ -316,7 +384,8 @@ int parse_logformat_tag(char *arg, int arg_len, char *name, int name_len, int ty
                                        memprintf(err, "out of memory error");
                                        goto error_free;
                                }
-                               node->type = logformat_tags[j].type;
+                               node->type = LOG_FMT_TAG;
+                               node->tag = &logformat_tags[j];
                                node->typecast = typecast;
                                if (name)
                                        node->name = my_strndup(name, name_len);
@@ -326,7 +395,7 @@ int parse_logformat_tag(char *arg, int arg_len, char *name, int name_len, int ty
                                        if (!parse_logformat_tag_args(node->arg, node, err))
                                                goto error_free;
                                }
-                               if (node->type == LOG_FMT_GLOBAL) {
+                               if (node->tag->type == LOG_FMT_GLOBAL) {
                                        *defoptions = node->options;
                                        free_logformat_node(node);
                                } else {
@@ -2692,7 +2761,13 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
                                        goto out;
                                tmplog = ret;
                                break;
+               }
+
+               if (tmp->type != LOG_FMT_TAG)
+                       goto next_fmt;
 
+               /* logformat tag */
+               switch (tmp->tag->type) {
                        case LOG_FMT_CLIENTIP:  // %ci
                                addr = (s ? sc_src(s->scf) : sess_src(sess));
                                if (addr)
@@ -3540,6 +3615,7 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
                                break;
 
                }
+ next_fmt:
                if (tmp->type != LOG_FMT_SEPARATOR)
                        last_isspace = 0; // not a separator, hence not a space