diff --git a/include/haproxy/log-t.h b/include/haproxy/log-t.h index 85ea15f04..7447c862d 100644 --- a/include/haproxy/log-t.h +++ b/include/haproxy/log-t.h @@ -59,6 +59,7 @@ * and appear as flags in session->logs.logwait, which are removed once the * required information has been collected. */ +#define LW_LOGSTEPS -1 /* special value: ignore LW_* fields and consider proxy log-steps */ #define LW_INIT 1 /* anything */ #define LW_CLIP 2 /* CLient IP */ #define LW_SVIP 4 /* SerVer IP */ diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index e404f9a80..677eacea0 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -379,7 +379,7 @@ struct proxy { struct buffer log_tag; /* override default syslog tag */ struct ist header_unique_id; /* unique-id header */ struct lf_expr format_unique_id; /* unique-id format */ - int to_log; /* things to be logged (LW_*) */ + int to_log; /* things to be logged (LW_*), special value LW_LOGSTEPS == follow log-steps */ int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */ struct cap_hdr *req_cap; /* chained list of request headers to be captured */ struct cap_hdr *rsp_cap; /* chained list of response headers to be captured */ diff --git a/src/log.c b/src/log.c index 2d73d1b96..9e01ea3d1 100644 --- a/src/log.c +++ b/src/log.c @@ -1293,6 +1293,13 @@ static int _postcheck_log_backend_compat(struct proxy *be) err_code |= ERR_WARN; free_server_rules(&be->server_rules); } + if (be->to_log == LW_LOGSTEPS) { + ha_warning("Cannot use \"log-steps\" with 'mode log' in %s '%s'. It will be ignored.\n", + proxy_type_str(be), be->id); + + err_code |= ERR_WARN; + /* we don't have a convenient freeing function, let the proxy free it upon deinit */ + } if (balance_algo != BE_LB_ALGO_RR && balance_algo != BE_LB_ALGO_RND && balance_algo != BE_LB_ALGO_SS && @@ -6606,6 +6613,105 @@ static int postresolve_loggers() /* config parsers for this section */ REGISTER_CONFIG_SECTION("log-forward", cfg_parse_log_forward, NULL); REGISTER_CONFIG_SECTION("log-profile", cfg_parse_log_profile, NULL); + +static int px_parse_log_steps(char **args, int section_type, struct proxy *curpx, + const struct proxy *defpx, const char *file, int line, + char **err) +{ + char *str; + size_t cur_sep; + int retval = -1; + + if (!(curpx->cap & PR_CAP_FE)) { + memprintf(err, "%s will be ignored because %s '%s' has no frontend capability", + args[0], proxy_type_str(curpx), curpx->id); + retval = 1; + goto end; + } + + if (args[1] == NULL) { + memprintf(err, "%s: invalid arguments, expects 'all' or a composition of logging" + "steps separated by spaces.", + args[0]); + goto end; + } + + if (strcmp(args[1], "all") == 0) { + /* enable all logging steps */ + curpx->to_log = LW_LOGSTEPS; + retval = 0; + goto end; + } + + /* selectively enable logging steps */ + str = args[1]; + + while (str[0]) { + struct eb32_node *cur_step; + enum log_orig_id cur_id; + + cur_sep = strcspn(str, ","); + + /* check for valid logging step */ + if (cur_sep == 6 && strncmp(str, "accept", cur_sep) == 0) + cur_id = LOG_ORIG_TXN_ACCEPT; + else if (cur_sep == 7 && strncmp(str, "request", cur_sep) == 0) + cur_id = LOG_ORIG_TXN_REQUEST; + else if (cur_sep == 7 && strncmp(str, "connect", cur_sep) == 0) + cur_id = LOG_ORIG_TXN_CONNECT; + else if (cur_sep == 8 && strncmp(str, "response", cur_sep) == 0) + cur_id = LOG_ORIG_TXN_RESPONSE; + else if (cur_sep == 5 && strncmp(str, "close", cur_sep) == 0) + cur_id = LOG_ORIG_TXN_CLOSE; + else { + struct log_origin_node *cur; + + list_for_each_entry(cur, &log_origins, list) { + if (cur_sep == strlen(cur->name) && strncmp(str, cur->name, cur_sep) == 0) { + cur_id = cur->tree.key; + break; + } + } + + memprintf(err, + "invalid log step name (%.*s). Expected values are: " + "accept, request, connect, response, close", + (int)cur_sep, str); + list_for_each_entry(cur, &log_origins, list) + memprintf(err, "%s, %s", *err, cur->name); + + goto end; + } + + cur_step = malloc(sizeof(*cur_step)); + if (!cur_step) { + memprintf(err, "memory failure when trying to configure log-step (%.*s)", + (int)cur_sep, str); + goto end; + } + cur_step->key = cur_id; + eb32_insert(&curpx->conf.log_steps, cur_step); + next: + if (str[cur_sep]) + str += cur_sep + 1; + else + str += cur_sep; + } + + curpx->to_log = LW_LOGSTEPS; + retval = 0; + + end: + return retval; +} + +static struct cfg_kw_list cfg_kws_li = {ILH, { + { CFG_LISTEN, "log-steps", px_parse_log_steps }, + { 0, NULL, NULL }, +}}; + +INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws_li); + REGISTER_POST_CHECK(postresolve_loggers); REGISTER_POST_PROXY_CHECK(postcheck_log_backend); REGISTER_POST_PROXY_CHECK(postcheck_logformat_proxy);