MEDIUM: log: carry tag context in logformat node

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...
This commit is contained in:
Aurelien DARRAGON 2024-02-22 20:20:41 +01:00
parent 8cf5c3d7f0
commit 7d8f45b647
2 changed files with 82 additions and 70 deletions

View 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. */

View File

@ -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