From 8a4e4420fb15b72ca80fd0524d01d691179dd2df Mon Sep 17 00:00:00 2001
From: "Thierry FOURNIER / OZON.IO" <thierry.fournier@ozon.io>
Date: Wed, 23 Nov 2016 00:41:28 +0100
Subject: [PATCH] MEDIUM: log-format: Use standard HAProxy log system to report
 errors

The function log format emit its own error message using Alert(). This
patch replaces this behavior and uses the standard HAProxy error system
(with memprintf).

The benefits are:
 - cleaning the log system

 - the logformat can ignore the caller (actually the caller must set
   a flag designing the caller function).

 - Make the usage of the logformat function easy for future components.
---
 include/proto/log.h |  4 +-
 src/cfgparse.c      | 30 ++++++++++++---
 src/log.c           | 68 +++++++++++++++-------------------
 src/proto_http.c    | 89 +++++++++++++++++++++++++++++++++++++--------
 4 files changed, 130 insertions(+), 61 deletions(-)

diff --git a/include/proto/log.h b/include/proto/log.h
index f5a4f3fc9..2d4ca84f1 100644
--- a/include/proto/log.h
+++ b/include/proto/log.h
@@ -67,14 +67,14 @@ void strm_log(struct stream *s);
 /*
  * add to the logformat linked list
  */
-int add_to_logformat_list(char *start, char *end, int type, struct list *list_format);
+int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err);
 
 /*
  * Parse the log_format string and fill a linked list.
  * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
  * You can set arguments using { } : %{many arguments}varname
  */
-int parse_logformat_string(const char *str, struct proxy *curproxy, struct list *list_format, int options, int cap);
+int parse_logformat_string(const char *str, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err);
 /*
  * Displays the message on stderr with the date and pid. Overrides the quiet
  * mode during startup.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index db1641e98..fbd736466 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -7502,6 +7502,7 @@ int check_config_validity()
 	int err_code = 0;
 	unsigned int next_pxid = 1;
 	struct bind_conf *bind_conf;
+	char *err;
 
 	bind_conf = NULL;
 	/*
@@ -7801,7 +7802,11 @@ int check_config_validity()
 			curproxy->conf.args.ctx = ARGC_UBK;
 			curproxy->conf.args.file = rule->file;
 			curproxy->conf.args.line = rule->line;
-			if (!parse_logformat_string(pxname, curproxy, &rule->be.expr, 0, SMP_VAL_FE_HRQ_HDR)) {
+			err = NULL;
+			if (!parse_logformat_string(pxname, curproxy, &rule->be.expr, 0, SMP_VAL_FE_HRQ_HDR, &err)) {
+				Alert("Parsing [%s:%d]: failed to parse use_backend rule '%s' : %s.\n",
+				      rule->file, rule->line, pxname, err);
+				free(err);
 				cfgerr++;
 				continue;
 			}
@@ -8288,8 +8293,12 @@ out_uri_auth_compat:
 			curproxy->conf.args.ctx = ARGC_LOG;
 			curproxy->conf.args.file = curproxy->conf.lfs_file;
 			curproxy->conf.args.line = curproxy->conf.lfs_line;
+			err = NULL;
 			if (!parse_logformat_string(curproxy->conf.logformat_string, curproxy, &curproxy->logformat, LOG_OPT_MANDATORY,
-			                            SMP_VAL_FE_LOG_END)) {
+			                            SMP_VAL_FE_LOG_END, &err)) {
+				Alert("Parsing [%s:%d]: failed to parse log-format : %s.\n",
+				      curproxy->conf.lfs_file, curproxy->conf.lfs_line, err);
+				free(err);
 				cfgerr++;
 			}
 			curproxy->conf.args.file = NULL;
@@ -8300,10 +8309,17 @@ out_uri_auth_compat:
 			curproxy->conf.args.ctx = ARGC_LOGSD;
 			curproxy->conf.args.file = curproxy->conf.lfsd_file;
 			curproxy->conf.args.line = curproxy->conf.lfsd_line;
+			err = NULL;
 			if (!parse_logformat_string(curproxy->conf.logformat_sd_string, curproxy, &curproxy->logformat_sd, LOG_OPT_MANDATORY,
-			                            SMP_VAL_FE_LOG_END)) {
+			                            SMP_VAL_FE_LOG_END, &err)) {
+				Alert("Parsing [%s:%d]: failed to parse log-format-sd : %s.\n",
+				      curproxy->conf.lfs_file, curproxy->conf.lfs_line, err);
+				free(err);
 				cfgerr++;
-			} else if (!add_to_logformat_list(NULL, NULL, LF_SEPARATOR, &curproxy->logformat_sd)) {
+			} else if (!add_to_logformat_list(NULL, NULL, LF_SEPARATOR, &curproxy->logformat_sd, &err)) {
+				Alert("Parsing [%s:%d]: failed to parse log-format-sd : %s.\n",
+				      curproxy->conf.lfs_file, curproxy->conf.lfs_line, err);
+				free(err);
 				cfgerr++;
 			}
 			curproxy->conf.args.file = NULL;
@@ -8314,8 +8330,12 @@ out_uri_auth_compat:
 			curproxy->conf.args.ctx = ARGC_UIF;
 			curproxy->conf.args.file = curproxy->conf.uif_file;
 			curproxy->conf.args.line = curproxy->conf.uif_line;
+			err = NULL;
 			if (!parse_logformat_string(curproxy->conf.uniqueid_format_string, curproxy, &curproxy->format_unique_id, LOG_OPT_HTTP,
-			                            (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+			                            (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &err)) {
+				Alert("Parsing [%s:%d]: failed to parse unique-id : %s.\n",
+				      curproxy->conf.uif_file, curproxy->conf.uif_line, err);
+				free(err);
 				cfgerr++;
 			}
 			curproxy->conf.args.file = NULL;
diff --git a/src/log.c b/src/log.c
index 9ec89b2b3..3a6f781d9 100644
--- a/src/log.c
+++ b/src/log.c
@@ -291,15 +291,17 @@ int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
  * Parse args in a logformat_var. Returns 0 in error
  * case, otherwise, it returns 1.
  */
-int parse_logformat_var_args(char *args, struct logformat_node *node)
+int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
 {
 	int i = 0;
 	int end = 0;
 	int flags = 0;  // 1 = +  2 = -
 	char *sp = NULL; // start pointer
 
-	if (args == NULL)
+	if (args == NULL) {
+		memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
 		return 0;
+	}
 
 	while (1) {
 		if (*args == '\0')
@@ -345,7 +347,7 @@ int parse_logformat_var_args(char *args, struct logformat_node *node)
  * ignored when arg_len is 0. Neither <var> nor <var_len> 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)
+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 j;
 	struct logformat_node *node;
@@ -356,14 +358,14 @@ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct p
 			if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
 				node = calloc(1, sizeof(*node));
 				if (!node) {
-					Alert("Out of memory error.\n");
+					memprintf(err, "out of memory error");
 					return 0;
 				}
 				node->type = logformat_keywords[j].type;
 				node->options = *defoptions;
 				if (arg_len) {
 					node->arg = my_strndup(arg, arg_len);
-					if (!parse_logformat_var_args(node->arg, node))
+					if (!parse_logformat_var_args(node->arg, node, err))
 						return 0;
 				}
 				if (node->type == LOG_FMT_GLOBAL) {
@@ -384,9 +386,8 @@ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct p
 					        logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
 				return 1;
 			} else {
-				Alert("parsing [%s:%d] : '%s' : format variable '%s' is reserved for HTTP mode.\n",
-				      curproxy->conf.args.file, curproxy->conf.args.line, fmt_directive(curproxy),
-				      logformat_keywords[j].name);
+				memprintf(err, "format variable '%s' is reserved for HTTP mode",
+				          logformat_keywords[j].name);
 				return 0;
 			}
 		}
@@ -394,8 +395,7 @@ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct p
 
 	j = var[var_len];
 	var[var_len] = 0;
-	Alert("parsing [%s:%d] : no such format variable '%s' in '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%' in log-format expressions.\n",
-	      curproxy->conf.args.file, curproxy->conf.args.line, var, fmt_directive(curproxy));
+	memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
 	var[var_len] = j;
 	return 0;
 }
@@ -411,14 +411,14 @@ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct p
  *  LOG_TEXT: copy chars from start to end excluding end.
  *
 */
-int add_to_logformat_list(char *start, char *end, int type, struct list *list_format)
+int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
 {
 	char *str;
 
 	if (type == LF_TEXT) { /* type text */
 		struct logformat_node *node = calloc(1, sizeof(*node));
 		if (!node) {
-			Alert("Out of memory error.\n");
+			memprintf(err, "out of memory error");
 			return 0;
 		}
 		str = calloc(1, end - start + 1);
@@ -430,7 +430,7 @@ int add_to_logformat_list(char *start, char *end, int type, struct list *list_fo
 	} else if (type == LF_SEPARATOR) {
 		struct logformat_node *node = calloc(1, sizeof(*node));
 		if (!node) {
-			Alert("Out of memory error.\n");
+			memprintf(err, "out of memory error");
 			return 0;
 		}
 		node->type = LOG_FMT_SEPARATOR;
@@ -446,29 +446,26 @@ 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, const char *file, int line)
+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 *cmd[2];
 	struct sample_expr *expr;
 	struct logformat_node *node;
 	int cmd_arg;
-	char *errmsg = NULL;
 
 	cmd[0] = text;
 	cmd[1] = "";
 	cmd_arg = 0;
 
-	expr = sample_parse_expr(cmd, &cmd_arg, file, line, &errmsg, &curpx->conf.args);
+	expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args);
 	if (!expr) {
-		Alert("parsing [%s:%d] : '%s' : sample fetch <%s> failed with : %s\n",
-		      curpx->conf.args.file, curpx->conf.args.line, fmt_directive(curpx),
-		      text, errmsg);
+		memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
 		return 0;
 	}
 
 	node = calloc(1, sizeof(*node));
 	if (!node) {
-		Alert("Out of memory error.\n");
+		memprintf(err, "out of memory error");
 		return 0;
 	}
 	node->type = LOG_FMT_EXPR;
@@ -477,7 +474,7 @@ int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct prox
 
 	if (arg_len) {
 		node->arg = my_strndup(arg, arg_len);
-		if (!parse_logformat_var_args(node->arg, node))
+		if (!parse_logformat_var_args(node->arg, node, err))
 			return 0;
 	}
 	if (expr->fetch->val & cap & SMP_VAL_REQUEST)
@@ -487,9 +484,8 @@ int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct prox
 		node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
 
 	if (!(expr->fetch->val & cap)) {
-		Alert("parsing [%s:%d] : '%s' : sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here.\n",
-		      curpx->conf.args.file, curpx->conf.args.line, fmt_directive(curpx),
-		      text, sample_src_names(expr->fetch->use));
+		memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
+		          text, sample_src_names(expr->fetch->use));
 		return 0;
 	}
 
@@ -519,9 +515,9 @@ int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct prox
  *  options: LOG_OPT_* to force on every node
  *  cap: all SMP_VAL_* flags supported by the consumer
  *
- * The function returns 1 in success case, otherwise, it returns 0.
+ * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
  */
-int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap)
+int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err)
 {
 	char *sp, *str, *backfmt; /* start pointer for text parts */
 	char *arg = NULL; /* start pointer for args */
@@ -534,7 +530,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
 
 	sp = str = backfmt = strdup(fmt);
 	if (!str) {
-		Alert("Out of memory error.\n");
+		memprintf(err, "out of memory error");
 		return 0;
 	}
 	curproxy->to_log |= LW_INIT;
@@ -579,8 +575,8 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
 				cformat = LF_TEXT;
 				pformat = LF_TEXT; /* finally we include the previous char as well */
 				sp = str - 1; /* send both the '%' and the current char */
-				Alert("parsing [%s:%d] : Unexpected variable name near '%c' at position %d in %s line : '%s'. Maybe you want to write a simgle '%%', use the syntax '%%%%'.\n",
-				      curproxy->conf.args.file, curproxy->conf.args.line, *str, (int)(str - backfmt), fmt_directive(curproxy), fmt);
+				memprintf(err, "unexpected variable name near '%c' at position %d line : '%s'. Maybe you want to write a simgle '%%', use the syntax '%%%%'",
+				          *str, (int)(str - backfmt), fmt);
 				return 0;
 
 			}
@@ -607,8 +603,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
 				var = str;
 				break;
 			}
-			Alert("parsing [%s:%d] : Parse argument modifier without variable name, in '%s' near '%%{%s}'\n",
-			      curproxy->conf.args.file, curproxy->conf.args.line, fmt_directive(curproxy), arg);
+			memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
 			return 0;
 
 		case LF_STEXPR:                        // text immediately following '%['
@@ -641,17 +636,16 @@ 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))
+				if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
 					return 0;
 				break;
 			case LF_STEXPR:
-				if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap,
-				                             curproxy->conf.args.file, curproxy->conf.args.line))
+				if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err))
 					return 0;
 				break;
 			case LF_TEXT:
 			case LF_SEPARATOR:
-				if (!add_to_logformat_list(sp, str, pformat, list_format))
+				if (!add_to_logformat_list(sp, str, pformat, list_format, err))
 					return 0;
 				break;
 			}
@@ -660,9 +654,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
 	}
 
 	if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
-		Alert("parsing [%s:%d] : Truncated '%s' line after '%s'\n",
-		      curproxy->conf.args.file, curproxy->conf.args.line, fmt_directive(curproxy),
-		      var ? var : arg ? arg : "%");
+		memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
 		return 0;
 	}
 	free(backfmt);
diff --git a/src/proto_http.c b/src/proto_http.c
index 725ea9c0a..6dfc8f9c9 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -9139,8 +9139,12 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
 		LIST_INIT(&rule->arg.hdr_add.fmt);
 
 		proxy->conf.args.ctx = ARGC_HRQ;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9171,8 +9175,12 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
 		}
 
 		proxy->conf.args.ctx = ARGC_HRQ;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 
@@ -9285,8 +9293,12 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
 
 		LIST_INIT(&rule->arg.map.key);
 		proxy->conf.args.ctx = ARGC_HRQ;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9313,8 +9325,12 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
 
 		LIST_INIT(&rule->arg.map.key);
 		proxy->conf.args.ctx = ARGC_HRQ;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9341,8 +9357,12 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
 
 		LIST_INIT(&rule->arg.map.key);
 		proxy->conf.args.ctx = ARGC_HRQ;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-request %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9372,14 +9392,22 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li
 		proxy->conf.args.ctx = ARGC_HRQ;
 
 		/* key pattern */
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-request %s' key: %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 
 		/* value pattern */
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+		                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-request %s' pattern: %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9551,8 +9579,12 @@ struct act_rule *parse_http_res_cond(const char **args, const char *file, int li
 		LIST_INIT(&rule->arg.hdr_add.fmt);
 
 		proxy->conf.args.ctx = ARGC_HRS;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR)) {
+		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9583,8 +9615,12 @@ struct act_rule *parse_http_res_cond(const char **args, const char *file, int li
 		}
 
 		proxy->conf.args.ctx = ARGC_HRQ;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR)) {
+		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 
@@ -9631,8 +9667,12 @@ struct act_rule *parse_http_res_cond(const char **args, const char *file, int li
 
 		LIST_INIT(&rule->arg.map.key);
 		proxy->conf.args.ctx = ARGC_HRS;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR)) {
+		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9660,8 +9700,12 @@ struct act_rule *parse_http_res_cond(const char **args, const char *file, int li
 
 		LIST_INIT(&rule->arg.map.key);
 		proxy->conf.args.ctx = ARGC_HRS;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR)) {
+		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-response %s': %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9688,8 +9732,12 @@ struct act_rule *parse_http_res_cond(const char **args, const char *file, int li
 
 		LIST_INIT(&rule->arg.map.key);
 		proxy->conf.args.ctx = ARGC_HRS;
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR)) {
+		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-response %s' %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 		free(proxy->conf.lfs_file);
@@ -9720,14 +9768,22 @@ struct act_rule *parse_http_res_cond(const char **args, const char *file, int li
 		proxy->conf.args.ctx = ARGC_HRS;
 
 		/* key pattern */
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR)) {
+		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-response %s' name: %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 
 		/* value pattern */
+		error = NULL;
 		if (!parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
-		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR)) {
+		                            (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR, &error)) {
+			Alert("parsing [%s:%d]: 'http-response %s' value: %s.\n",
+			      file, linenum, args[0], error);
+			free(error);
 			goto out_err;
 		}
 
@@ -9975,7 +10031,8 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
 		if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
 			if (!parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP,
 			                            dir ? (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRS_HDR : SMP_VAL_BE_HRS_HDR
-			                                : (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+			                                : (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
+			                            errmsg)) {
 				return  NULL;
 			}
 			free(curproxy->conf.lfs_file);
@@ -12471,7 +12528,7 @@ enum act_parse_ret parse_set_req_line(const char **args, int *orig_arg, struct p
 	LIST_INIT(&rule->arg.http.logfmt);
 	proxy->conf.args.ctx = ARGC_HRQ;
 	if (!parse_logformat_string(args[cur_arg], proxy, &rule->arg.http.logfmt, LOG_OPT_HTTP,
-	                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR)) {
+	                            (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, err)) {
 		return ACT_RET_PRS_ERR;
 	}