1
0
mirror of http://git.haproxy.org/git/haproxy.git/ synced 2025-04-07 01:31:35 +00:00

MINOR: include comment in tcpcheck error log

tcpcheck error messages include the step id where the error occurs.
In some cases, this is not enough. Now, HAProxy also use the comment
field of the latest tcpcheck rule which has been run.
This commit allows HAProxy to parse a new directive in the tcpcheck
ruleset: 'comment'.
It is used to setup comments on the current tcpcheck rules.
This commit is contained in:
Baptiste Assmann 2015-05-01 08:03:04 +02:00 committed by Willy Tarreau
parent aa12b47b06
commit 22b09d2393
3 changed files with 191 additions and 7 deletions

View File

@ -204,6 +204,7 @@ enum {
TCPCHK_ACT_SEND = 0, /* send action, regular string format */ TCPCHK_ACT_SEND = 0, /* send action, regular string format */
TCPCHK_ACT_EXPECT, /* expect action, either regular or binary string */ TCPCHK_ACT_EXPECT, /* expect action, either regular or binary string */
TCPCHK_ACT_CONNECT, /* connect action, to probe a new port */ TCPCHK_ACT_CONNECT, /* connect action, to probe a new port */
TCPCHK_ACT_COMMENT, /* no action, simply a comment used for logs */
}; };
/* flags used by tcpcheck_rule->conn_opts */ /* flags used by tcpcheck_rule->conn_opts */

View File

@ -4683,7 +4683,26 @@ stats_error_parsing:
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
err_code |= ERR_WARN; err_code |= ERR_WARN;
if (strcmp(args[1], "connect") == 0) { if (strcmp(args[1], "comment") == 0) {
int cur_arg;
struct tcpcheck_rule *tcpcheck;
cur_arg = 1;
tcpcheck = (struct tcpcheck_rule *)calloc(1, sizeof(*tcpcheck));
tcpcheck->action = TCPCHK_ACT_COMMENT;
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
file, linenum, args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
tcpcheck->comment = strdup(args[cur_arg + 1]);
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
}
else if (strcmp(args[1], "connect") == 0) {
const char *ptr_arg; const char *ptr_arg;
int cur_arg; int cur_arg;
struct tcpcheck_rule *tcpcheck; struct tcpcheck_rule *tcpcheck;
@ -4693,6 +4712,13 @@ stats_error_parsing:
l = (struct list *)&curproxy->tcpcheck_rules; l = (struct list *)&curproxy->tcpcheck_rules;
if (l->p != l->n) { if (l->p != l->n) {
tcpcheck = (struct tcpcheck_rule *)l->n; tcpcheck = (struct tcpcheck_rule *)l->n;
while (tcpcheck->action == TCPCHK_ACT_COMMENT) {
tcpcheck = (struct tcpcheck_rule *)tcpcheck->list.n;
}
/* we've reached the end of the list, and the list is full of comments */
if (tcpcheck == (struct tcpcheck_rule *)l)
tcpcheck = NULL;
if (tcpcheck && tcpcheck->action != TCPCHK_ACT_CONNECT) { if (tcpcheck && tcpcheck->action != TCPCHK_ACT_CONNECT) {
Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n", Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
file, linenum); file, linenum);
@ -4731,11 +4757,22 @@ stats_error_parsing:
cur_arg++; cur_arg++;
} }
#endif /* USE_OPENSSL */ #endif /* USE_OPENSSL */
/* comment for this tcpcheck line */
else if (strcmp(args[cur_arg], "comment") == 0) {
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
file, linenum, args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
tcpcheck->comment = strdup(args[cur_arg + 1]);
cur_arg += 2;
}
else { else {
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
Alert("parsing [%s:%d] : '%s %s' expects 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n", Alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
#else /* USE_OPENSSL */ #else /* USE_OPENSSL */
Alert("parsing [%s:%d] : '%s %s' expects 'port', 'send-proxy' or but got '%s' as argument.\n", Alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
#endif /* USE_OPENSSL */ #endif /* USE_OPENSSL */
file, linenum, args[0], args[1], args[cur_arg]); file, linenum, args[0], args[1], args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
@ -4763,6 +4800,17 @@ stats_error_parsing:
tcpcheck->string = strdup(args[2]); tcpcheck->string = strdup(args[2]);
tcpcheck->expect_regex = NULL; tcpcheck->expect_regex = NULL;
/* comment for this tcpcheck line */
if (strcmp(args[3], "comment") == 0) {
if (!*args[4]) {
Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
file, linenum, args[3]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
tcpcheck->comment = strdup(args[4]);
}
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
} }
} }
@ -4788,6 +4836,17 @@ stats_error_parsing:
} }
tcpcheck->expect_regex = NULL; tcpcheck->expect_regex = NULL;
/* comment for this tcpcheck line */
if (strcmp(args[3], "comment") == 0) {
if (!*args[4]) {
Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
file, linenum, args[3]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
tcpcheck->comment = strdup(args[4]);
}
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
} }
} }
@ -4839,6 +4898,18 @@ stats_error_parsing:
tcpcheck->expect_regex = NULL; tcpcheck->expect_regex = NULL;
tcpcheck->inverse = inverse; tcpcheck->inverse = inverse;
/* tcpcheck comment */
cur_arg += 2;
if (strcmp(args[cur_arg], "comment") == 0) {
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
file, linenum, args[cur_arg + 1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
tcpcheck->comment = strdup(args[cur_arg + 1]);
}
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
} }
else if (strcmp(ptr_arg, "string") == 0) { else if (strcmp(ptr_arg, "string") == 0) {
@ -4859,6 +4930,18 @@ stats_error_parsing:
tcpcheck->expect_regex = NULL; tcpcheck->expect_regex = NULL;
tcpcheck->inverse = inverse; tcpcheck->inverse = inverse;
/* tcpcheck comment */
cur_arg += 2;
if (strcmp(args[cur_arg], "comment") == 0) {
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
file, linenum, args[cur_arg + 1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
tcpcheck->comment = strdup(args[cur_arg + 1]);
}
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
} }
else if (strcmp(ptr_arg, "rstring") == 0) { else if (strcmp(ptr_arg, "rstring") == 0) {
@ -4887,6 +4970,18 @@ stats_error_parsing:
} }
tcpcheck->inverse = inverse; tcpcheck->inverse = inverse;
/* tcpcheck comment */
cur_arg += 2;
if (strcmp(args[cur_arg], "comment") == 0) {
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
file, linenum, args[cur_arg + 1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
tcpcheck->comment = strdup(args[cur_arg + 1]);
}
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list); LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
} }
else { else {
@ -4897,7 +4992,7 @@ stats_error_parsing:
} }
} }
else { else {
Alert("parsing [%s:%d] : '%s' only supports 'connect', 'send' or 'expect'.\n", file, linenum, args[0]); Alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }

View File

@ -62,6 +62,7 @@
static int httpchk_expect(struct server *s, int done); static int httpchk_expect(struct server *s, int done);
static int tcpcheck_get_step_id(struct check *); static int tcpcheck_get_step_id(struct check *);
static char * tcpcheck_get_step_comment(struct check *, int);
static void tcpcheck_main(struct connection *); static void tcpcheck_main(struct connection *);
static const struct check_status check_statuses[HCHK_STATUS_SIZE] = { static const struct check_status check_statuses[HCHK_STATUS_SIZE] = {
@ -608,6 +609,7 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
const char *err_msg; const char *err_msg;
struct chunk *chk; struct chunk *chk;
int step; int step;
char *comment;
if (check->result != CHK_RES_UNKNOWN) if (check->result != CHK_RES_UNKNOWN)
return; return;
@ -648,6 +650,10 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_SEND) { else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_SEND) {
chunk_appendf(chk, " (send)"); chunk_appendf(chk, " (send)");
} }
comment = tcpcheck_get_step_comment(check, step);
if (comment)
chunk_appendf(chk, " comment: '%s'", comment);
} }
} }
@ -2382,9 +2388,44 @@ static int tcpcheck_get_step_id(struct check *check)
return i; return i;
} }
/*
* return the latest known comment before (including) the given stepid
* returns NULL if no comment found
*/
static char * tcpcheck_get_step_comment(struct check *check, int stepid)
{
struct tcpcheck_rule *cur = NULL;
char *ret = NULL;
int i = 0;
/* not even started anything yet, return latest comment found before any action */
if (!check->current_step) {
list_for_each_entry(cur, check->tcpcheck_rules, list) {
if (cur->action == TCPCHK_ACT_COMMENT)
ret = cur->comment;
else
goto return_comment;
}
}
i = 1;
list_for_each_entry(cur, check->tcpcheck_rules, list) {
if (cur->comment)
ret = cur->comment;
if (i >= stepid)
goto return_comment;
++i;
}
return_comment:
return ret;
}
static void tcpcheck_main(struct connection *conn) static void tcpcheck_main(struct connection *conn)
{ {
char *contentptr; char *contentptr, *comment;
struct tcpcheck_rule *cur, *next; struct tcpcheck_rule *cur, *next;
int done = 0, ret = 0, step = 0; int done = 0, ret = 0, step = 0;
struct check *check = conn->owner; struct check *check = conn->owner;
@ -2483,6 +2524,12 @@ static void tcpcheck_main(struct connection *conn)
/* have 'next' point to the next rule or NULL if we're on the last one */ /* have 'next' point to the next rule or NULL if we're on the last one */
next = (struct tcpcheck_rule *)cur->list.n; next = (struct tcpcheck_rule *)cur->list.n;
/* bypass all comment rules */
while (next->action == TCPCHK_ACT_COMMENT)
next = (struct tcpcheck_rule *)next->list.n;
/* NULL if we're on the last rule */
if (&next->list == head) if (&next->list == head)
next = NULL; next = NULL;
@ -2572,6 +2619,9 @@ static void tcpcheck_main(struct connection *conn)
step = tcpcheck_get_step_id(check); step = tcpcheck_get_step_id(check);
chunk_printf(&trash, "TCPCHK error establishing connection at step %d: %s", chunk_printf(&trash, "TCPCHK error establishing connection at step %d: %s",
step, strerror(errno)); step, strerror(errno));
comment = tcpcheck_get_step_comment(check, step);
if (comment)
chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L4CON, trash.str); set_server_check_status(check, HCHK_STATUS_L4CON, trash.str);
goto out_end_tcpcheck; goto out_end_tcpcheck;
case SF_ERR_PRXCOND: case SF_ERR_PRXCOND:
@ -2579,12 +2629,20 @@ static void tcpcheck_main(struct connection *conn)
case SF_ERR_INTERNAL: case SF_ERR_INTERNAL:
step = tcpcheck_get_step_id(check); step = tcpcheck_get_step_id(check);
chunk_printf(&trash, "TCPCHK error establishing connection at step %d", step); chunk_printf(&trash, "TCPCHK error establishing connection at step %d", step);
comment = tcpcheck_get_step_comment(check, step);
if (comment)
chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.str); set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.str);
goto out_end_tcpcheck; goto out_end_tcpcheck;
} }
/* allow next rule */ /* allow next rule */
cur = (struct tcpcheck_rule *)cur->list.n; cur = (struct tcpcheck_rule *)cur->list.n;
/* bypass all comment rules */
while (cur->action == TCPCHK_ACT_COMMENT)
cur = (struct tcpcheck_rule *)cur->list.n;
check->current_step = cur; check->current_step = cur;
/* don't do anything until the connection is established */ /* don't do anything until the connection is established */
@ -2640,6 +2698,11 @@ static void tcpcheck_main(struct connection *conn)
/* go to next rule and try to send */ /* go to next rule and try to send */
cur = (struct tcpcheck_rule *)cur->list.n; cur = (struct tcpcheck_rule *)cur->list.n;
/* bypass all comment rules */
while (cur->action == TCPCHK_ACT_COMMENT)
cur = (struct tcpcheck_rule *)cur->list.n;
check->current_step = cur; check->current_step = cur;
} /* end 'send' */ } /* end 'send' */
else if (check->current_step->action == TCPCHK_ACT_EXPECT) { else if (check->current_step->action == TCPCHK_ACT_EXPECT) {
@ -2688,6 +2751,9 @@ static void tcpcheck_main(struct connection *conn)
/* empty response */ /* empty response */
step = tcpcheck_get_step_id(check); step = tcpcheck_get_step_id(check);
chunk_printf(&trash, "TCPCHK got an empty response at step %d", step); chunk_printf(&trash, "TCPCHK got an empty response at step %d", step);
comment = tcpcheck_get_step_comment(check, step);
if (comment)
chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str); set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str);
goto out_end_tcpcheck; goto out_end_tcpcheck;
@ -2719,13 +2785,23 @@ static void tcpcheck_main(struct connection *conn)
/* we were looking for a regex */ /* we were looking for a regex */
chunk_printf(&trash, "TCPCHK matched unwanted content (regex) at step %d", step); chunk_printf(&trash, "TCPCHK matched unwanted content (regex) at step %d", step);
} }
comment = tcpcheck_get_step_comment(check, step);
if (comment)
chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str); set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str);
goto out_end_tcpcheck; goto out_end_tcpcheck;
} }
/* matched and was supposed to => OK, next step */ /* matched and was supposed to => OK, next step */
else { else {
/* allow next rule */
cur = (struct tcpcheck_rule *)cur->list.n; cur = (struct tcpcheck_rule *)cur->list.n;
/* bypass all comment rules */
while (cur->action == TCPCHK_ACT_COMMENT)
cur = (struct tcpcheck_rule *)cur->list.n;
check->current_step = cur; check->current_step = cur;
if (check->current_step->action == TCPCHK_ACT_EXPECT) if (check->current_step->action == TCPCHK_ACT_EXPECT)
goto tcpcheck_expect; goto tcpcheck_expect;
__conn_data_stop_recv(conn); __conn_data_stop_recv(conn);
@ -2735,6 +2811,15 @@ static void tcpcheck_main(struct connection *conn)
/* not matched */ /* not matched */
/* not matched and was not supposed to => OK, next step */ /* not matched and was not supposed to => OK, next step */
if (cur->inverse) { if (cur->inverse) {
/* allow next rule */
cur = (struct tcpcheck_rule *)cur->list.n;
/* bypass all comment rules */
while (cur->action == TCPCHK_ACT_COMMENT)
cur = (struct tcpcheck_rule *)cur->list.n;
check->current_step = cur;
cur = (struct tcpcheck_rule*)cur->list.n; cur = (struct tcpcheck_rule*)cur->list.n;
check->current_step = cur; check->current_step = cur;
if (check->current_step->action == TCPCHK_ACT_EXPECT) if (check->current_step->action == TCPCHK_ACT_EXPECT)
@ -2753,6 +2838,9 @@ static void tcpcheck_main(struct connection *conn)
chunk_printf(&trash, "TCPCHK did not match content (regex) at step %d", chunk_printf(&trash, "TCPCHK did not match content (regex) at step %d",
step); step);
} }
comment = tcpcheck_get_step_comment(check, step);
if (comment)
chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str); set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str);
goto out_end_tcpcheck; goto out_end_tcpcheck;
} }