From 2ed6068f2a9c8731560f60e906d1ecb2a0439deb Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Mon, 8 Jan 2024 18:38:29 +0100 Subject: [PATCH] MINOR: log: custom name for logformat node Add the ability to specify custom name (will be used for representation in verbose output types such as json) to logformat nodes. For now, a custom name should be composed by characters [a-zA-Z0-9-_]* --- include/haproxy/log-t.h | 3 +++ src/log.c | 42 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/include/haproxy/log-t.h b/include/haproxy/log-t.h index a0a25acf14..d5474effc7 100644 --- a/include/haproxy/log-t.h +++ b/include/haproxy/log-t.h @@ -200,6 +200,8 @@ enum { LF_SEPARATOR, // a single separator LF_VAR, // variable name, after '%' or '%{..}' LF_STARTVAR, // % in text + LF_STONAME, // after '%(' and before ')' + LF_EDONAME, // ')' after '%(' LF_STARG, // after '%{' and berore '}' LF_EDARG, // '}' after '%{' LF_STEXPR, // after '%[' or '%{..}[' and berore ']' @@ -212,6 +214,7 @@ struct logformat_node { struct list list; int type; // LOG_FMT_* int options; // LOG_OPT_* + 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 }; diff --git a/src/log.c b/src/log.c index 5e704cddb1..8f0a2b6e24 100644 --- a/src/log.c +++ b/src/log.c @@ -306,7 +306,7 @@ int parse_logformat_var_args(char *args, struct logformat_node *node, char **err * ignored when arg_len is 0. Neither nor may be null. * Returns false in error case and err is filled, otherwise returns true. */ -int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err) +int parse_logformat_var(char *arg, int arg_len, char *name, int name_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err) { int j; struct logformat_node *node = NULL; @@ -321,6 +321,8 @@ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct p goto error_free; } node->type = logformat_keywords[j].type; + if (name) + node->name = my_strndup(name, name_len); node->options = *defoptions; if (arg_len) { node->arg = my_strndup(arg, arg_len); @@ -356,6 +358,7 @@ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct p error_free: if (node) { free(node->arg); + free(node->name); free(node); } return 0; @@ -409,7 +412,7 @@ int add_to_logformat_list(char *start, char *end, int type, struct list *list_fo * * In error case, the function returns 0, otherwise it returns 1. */ -int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err, char **endptr) +int add_sample_to_logformat_list(char *text, char *name, int name_len, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err, char **endptr) { char *cmd[2]; struct sample_expr *expr = NULL; @@ -432,6 +435,8 @@ int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct prox memprintf(err, "out of memory error"); goto error_free; } + if (name) + node->name = my_strndup(name, name_len); node->type = LOG_FMT_EXPR; node->expr = expr; node->options = options; @@ -500,8 +505,10 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list char *sp, *str, *backfmt; /* start pointer for text parts */ char *arg = NULL; /* start pointer for args */ char *var = NULL; /* start pointer for vars */ + char *name = NULL; /* token name (optional) */ int arg_len = 0; int var_len = 0; + int name_len = 0; int cformat; /* current token format */ int pformat; /* previous token format */ struct logformat_node *tmplf, *back; @@ -535,7 +542,31 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list switch (pformat) { case LF_STARTVAR: // text immediately following a '%' arg = NULL; var = NULL; + name = NULL; + name_len = 0; arg_len = var_len = 0; + if (*str == '(') { // custom output name + cformat = LF_STONAME; + name = str + 1; + } + else + goto startvar; + break; + + case LF_STONAME: // text immediately following '%(' + if (*str == ')') { // end of custom output name + cformat = LF_EDONAME; + name_len = str - name; + } else if (!isalnum((unsigned char)*str) && *str != '_' && *str != '-') { + memprintf(err, "invalid character in custom name near '%c' at position %d line : '%s'", + *str, (int)(str - backfmt), fmt); + + goto fail; + } + break; + + case LF_EDONAME: // text immediately following %(name) + startvar: if (*str == '{') { // optional argument cformat = LF_STARG; arg = str + 1; @@ -592,7 +623,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list * part of the expression, which MUST be the trailing * angle bracket. */ - if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str)) + if (!add_sample_to_logformat_list(var, name, name_len, arg, arg_len, curproxy, list_format, options, cap, err, &str)) goto fail; if (*str == ']') { @@ -638,7 +669,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list if (cformat != pformat || pformat == LF_SEPARATOR) { switch (pformat) { case LF_VAR: - if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err)) + if (!parse_logformat_var(arg, arg_len, name, name_len, var, var_len, curproxy, list_format, &options, err)) goto fail; break; case LF_TEXT: @@ -651,7 +682,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list } } - if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) { + if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR || pformat == LF_STONAME || pformat == LF_EDONAME) { memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%"); goto fail; } @@ -2586,6 +2617,7 @@ void free_logformat_list(struct list *fmt) list_for_each_entry_safe(lf, lfb, fmt, list) { LIST_DELETE(&lf->list); release_sample_expr(lf->expr); + free(lf->name); free(lf->arg); free(lf); }