>From 1299a2fe5768c502786ef28cd78dae83a31f0c83 Mon Sep 17 00:00:00 2001 From: Krzysztof Piotr Oledzki <o...@ans.pl> Date: Sun, 4 Oct 2009 21:28:53 +0200 Subject: [MINOR] Capture & display more data from health checks
Capture & display more data from health checks, like strerror(errno) for L4 failed checks or a first line from a response for L7 successes/failed checks. Non ascii or HTML control characters are masked. Feature can be disabled by defining HCHK_DESC_LEN to 0. --- include/common/defaults.h | 5 ++ include/types/server.h | 3 + src/checks.c | 101 ++++++++++++++++++++++++++++++++++----------- src/dumpstats.c | 8 +++- 4 files changed, 91 insertions(+), 26 deletions(-) diff --git a/include/common/defaults.h b/include/common/defaults.h index c09f5a4..b0aee86 100644 --- a/include/common/defaults.h +++ b/include/common/defaults.h @@ -174,4 +174,9 @@ #define MAX_HOSTNAME_LEN 32 #endif +/* Maximum health check description length */ +#ifndef HCHK_DESC_LEN +#define HCHK_DESC_LEN 128 +#endif + #endif /* _COMMON_DEFAULTS_H */ diff --git a/include/types/server.h b/include/types/server.h index ddf5a46..3bc089f 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -125,6 +125,9 @@ struct server { struct timeval check_start; /* last health check start time */ unsigned long check_duration; /* time in ms took to finish last health check */ short check_status, check_code; /* check result, check code */ +#if HCHK_DESC_LEN + char check_desc[HCHK_DESC_LEN]; /* healt check descritpion */ +#endif struct freq_ctr sess_per_sec; /* sessions per second on this server */ unsigned int sps_max; /* maximum of new sessions per second seen on this server */ diff --git a/src/checks.c b/src/checks.c index a21386f..d016690 100644 --- a/src/checks.c +++ b/src/checks.c @@ -151,12 +151,16 @@ static void server_status_printf(struct chunk *msg, struct server *s, unsigned o * Show information in logs about failed health check if server is UP * or succeeded health checks if server is DOWN. */ -static void set_server_check_status(struct server *s, short status) { +static void set_server_check_status(struct server *s, short status, char *desc) { struct chunk msg; + char *p; if (status == HCHK_STATUS_START) { s->result = SRV_CHK_UNKNOWN; /* no result yet */ +#if HCHK_DESC_LEN + s->check_desc[0] = '\0'; +#endif s->check_start = now; return; } @@ -164,6 +168,19 @@ static void set_server_check_status(struct server *s, short status) { if (!s->check_status) return; +#if HCHK_DESC_LEN + if (desc && *desc) { + strncpy(s->check_desc, desc, HCHK_DESC_LEN-1); + s->check_desc[HCHK_DESC_LEN-1] = '\0'; + + /* mask non-ascii or HTML control characters */ + for (p = s->check_desc; *p; p++) + if (!isascii(*p) || *p=='<' || *p=='>' || *p=='&') + *p = '.'; + } else + s->check_desc[0] = '\0'; +#endif + s->check_status = status; if (check_statuses[status].result) s->result |= check_statuses[status].result; @@ -503,7 +520,7 @@ static int event_srv_chk_w(int fd) //fprintf(stderr, "event_srv_chk_w, state=%ld\n", unlikely(fdtab[fd].state)); if (unlikely(fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR))) { - set_server_check_status(s, HCHK_STATUS_L4CON); + set_server_check_status(s, HCHK_STATUS_L4CON, strerror(errno)); goto out_error; } @@ -539,11 +556,11 @@ static int event_srv_chk_w(int fd) switch (errno) { case ECONNREFUSED: case ENETUNREACH: - set_server_check_status(s, HCHK_STATUS_L4CON); + set_server_check_status(s, HCHK_STATUS_L4CON, strerror(errno)); break; default: - set_server_check_status(s, HCHK_STATUS_SOCKERR); + set_server_check_status(s, HCHK_STATUS_SOCKERR, strerror(errno)); } goto out_error; @@ -572,12 +589,12 @@ static int event_srv_chk_w(int fd) goto out_poll; if (errno && errno != EISCONN) { - set_server_check_status(s, HCHK_STATUS_L4CON); + set_server_check_status(s, HCHK_STATUS_L4CON, strerror(errno)); goto out_error; } /* good TCP connection is enough */ - set_server_check_status(s, HCHK_STATUS_L4OK); + set_server_check_status(s, HCHK_STATUS_L4OK, NULL); goto out_wakeup; } } @@ -621,6 +638,7 @@ static int event_srv_chk_r(int fd) struct task *t = fdtab[fd].owner; struct server *s = t->context; int skerr; + char *desc, *p; socklen_t lskerr = sizeof(skerr); len = -1; @@ -633,7 +651,7 @@ static int event_srv_chk_r(int fd) /* in case of TCP only, this tells us if the connection failed */ if (!(s->result & SRV_CHK_ERROR)) - set_server_check_status(s, HCHK_STATUS_SOCKERR); + set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL); goto out_wakeup; } @@ -649,6 +667,11 @@ static int event_srv_chk_r(int fd) return 0; } + if (len < sizeof(trash)) + trash[len] = '\0'; + else + trash[len-1] = '\0'; + /* Note: the response will only be accepted if read at once */ if (s->proxy->options & PR_O_HTTP_CHK) { /* Check if the server speaks HTTP 1.X */ @@ -656,50 +679,78 @@ static int event_srv_chk_r(int fd) (memcmp(trash, "HTTP/1.", 7) != 0 || (trash[12] != ' ' && trash[12] != '\r')) || !isdigit(trash[9]) || !isdigit(trash[10]) || !isdigit(trash[11])) { - set_server_check_status(s, HCHK_STATUS_L7RSP); + + desc = trash; + p = strchr(desc, '\r'); + if (p) + *p = '\0'; + + set_server_check_status(s, HCHK_STATUS_L7RSP, desc); + goto out_wakeup; } s->check_code = str2uic(&trash[9]); + desc = &trash[12]; + p = strchr(desc, '\r'); + if (p) + *p = '\0'; + while(*desc == ' ') + desc++; + /* check the reply : HTTP/1.X 2xx and 3xx are OK */ if (trash[9] == '2' || trash[9] == '3') - set_server_check_status(s, HCHK_STATUS_L7OKD); + set_server_check_status(s, HCHK_STATUS_L7OKD, desc); else if ((s->proxy->options & PR_O_DISABLE404) && (s->state & SRV_RUNNING) && (s->check_code == 404)) /* 404 may be accepted as "stopping" only if the server was up */ - set_server_check_status(s, HCHK_STATUS_L7OKCD); + set_server_check_status(s, HCHK_STATUS_L7OKCD, desc); else - set_server_check_status(s, HCHK_STATUS_L7STS); + set_server_check_status(s, HCHK_STATUS_L7STS, desc); } else if (s->proxy->options & PR_O_SSL3_CHK) { /* Check for SSLv3 alert or handshake */ if ((len >= 5) && (trash[0] == 0x15 || trash[0] == 0x16)) - set_server_check_status(s, HCHK_STATUS_L6OK); + set_server_check_status(s, HCHK_STATUS_L6OK, NULL); else - set_server_check_status(s, HCHK_STATUS_L6RSP); + set_server_check_status(s, HCHK_STATUS_L6RSP, NULL); } else if (s->proxy->options & PR_O_SMTP_CHK) { /* Check if the server speaks SMTP */ if ((len < strlen("000\r")) || (trash[3] != ' ' && trash[3] != '\r') || !isdigit(trash[0]) || !isdigit(trash[1]) || !isdigit(trash[2])) { - set_server_check_status(s, HCHK_STATUS_L7RSP); + + desc = trash; + p = strchr(desc, '\r'); + if (p) + *p = '\0'; + + set_server_check_status(s, HCHK_STATUS_L7RSP, desc); + goto out_wakeup; } s->check_code = str2uic(&trash[0]); + desc = &trash[3]; + p = strchr(desc, '\r'); + if (p) + *p = '\0'; + while(*desc == ' ') + desc++; + /* Check for SMTP code 2xx (should be 250) */ if (trash[0] == '2') - set_server_check_status(s, HCHK_STATUS_L7OKD); + set_server_check_status(s, HCHK_STATUS_L7OKD, desc); else - set_server_check_status(s, HCHK_STATUS_L7STS); + set_server_check_status(s, HCHK_STATUS_L7STS, desc); } else { /* other checks are valid if the connection succeeded anyway */ - set_server_check_status(s, HCHK_STATUS_L4OK); + set_server_check_status(s, HCHK_STATUS_L4OK, NULL); } out_wakeup: @@ -749,7 +800,7 @@ struct task *process_chk(struct task *t) } /* we'll initiate a new check */ - set_server_check_status(s, HCHK_STATUS_START); + set_server_check_status(s, HCHK_STATUS_START, NULL); if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) { if ((fd < global.maxsock) && (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) && @@ -824,7 +875,7 @@ struct task *process_chk(struct task *t) } if (ret) { - set_server_check_status(s, HCHK_STATUS_SOCKERR); + set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL); switch (ret) { case 1: Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n", @@ -855,7 +906,7 @@ struct task *process_chk(struct task *t) #endif ret = tcpv4_bind_socket(fd, flags, &s->proxy->source_addr, remote); if (ret) { - set_server_check_status(s, HCHK_STATUS_SOCKERR); + set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL); switch (ret) { case 1: Alert("Cannot bind to source address before connect() for %s '%s'. Aborting.\n", @@ -918,11 +969,11 @@ struct task *process_chk(struct task *t) /* FIXME: is it possible to get ECONNREFUSED/ENETUNREACH with O_NONBLOCK? */ case ECONNREFUSED: case ENETUNREACH: - set_server_check_status(s, HCHK_STATUS_L4CON); + set_server_check_status(s, HCHK_STATUS_L4CON, strerror(errno)); break; default: - set_server_check_status(s, HCHK_STATUS_SOCKERR); + set_server_check_status(s, HCHK_STATUS_SOCKERR, strerror(errno)); } } } @@ -1020,12 +1071,12 @@ struct task *process_chk(struct task *t) else if ((s->result & SRV_CHK_ERROR) || tick_is_expired(t->expire, now_ms)) { if (!(s->result & SRV_CHK_ERROR)) { if (!EV_FD_ISSET(fd, DIR_RD)) { - set_server_check_status(s, HCHK_STATUS_L4TOUT); + set_server_check_status(s, HCHK_STATUS_L4TOUT, NULL); } else { if (s->proxy->options & PR_O_SSL3_CHK) - set_server_check_status(s, HCHK_STATUS_L6TOUT); + set_server_check_status(s, HCHK_STATUS_L6TOUT, NULL); else /* HTTP, SMTP */ - set_server_check_status(s, HCHK_STATUS_L7TOUT); + set_server_check_status(s, HCHK_STATUS_L7TOUT, NULL); } } diff --git a/src/dumpstats.c b/src/dumpstats.c index 29b9252..30f2545 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -1333,8 +1333,14 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) (svs->state & SRV_RUNNING) ? (svs->health - svs->rise + 1) : (svs->health), (svs->state & SRV_RUNNING) ? (svs->fall) : (svs->rise)); - chunk_printf(&msg, "</td><td title=\"%s\" nowrap> %s%s", + chunk_printf(&msg, "</td><td title=\"%s%s%s\" nowrap> %s%s", get_check_status_description(sv->check_status), +#if HCHK_DESC_LEN + (*sv->check_desc) ? ": " : "", + (*sv->check_desc) ? sv->check_desc : "", +#else + "", "", +#endif tv_iszero(&sv->check_start)?"":"* ", get_check_status_info(sv->check_status)); -- 1.6.4.2