From: Willy Tarreau Date: Wed, 17 Oct 2007 16:57:38 +0000 (+0200) Subject: [MEDIUM] implement the statistics output on a unix socket X-Git-Tag: v1.3.13~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3e76e728ce4e6cbf5d14a74139da3470618bf4f6;p=thirdparty%2Fhaproxy.git [MEDIUM] implement the statistics output on a unix socket A unix socket can now access the statistics. It currently only recognizes the "show stat\n" command at the beginning of the input, then returns the statistics in CSV format. --- diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h index cecfbe2268..bcf1540061 100644 --- a/include/proto/dumpstats.h +++ b/include/proto/dumpstats.h @@ -29,6 +29,7 @@ #define STAT_FMT_HTML 0x1 +int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags); int stats_dump_http(struct session *s, struct uri_auth *uri, int flags); int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, int flags); diff --git a/src/dumpstats.c b/src/dumpstats.c index 13196e2782..3fdac86666 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -45,6 +45,88 @@ #include #include +/* + * Produces statistics data for the session . Expects to be called with + * s->cli_state == CL_STSHUTR. It *may* make use of informations from + * and . + * It returns 0 if it had to stop writing data and an I/O is needed, 1 if the + * dump is finished and the session must be closed, or -1 in case of any error. + */ +int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags) +{ + struct buffer *rep = s->rep; + struct proxy *px; + struct chunk msg; + + msg.len = 0; + msg.str = trash; + + switch (s->data_state) { + case DATA_ST_INIT: + /* the function had not been called yet, let's prepare the + * buffer for a response. + */ + client_retnclose(s, &msg); + s->data_state = DATA_ST_HEAD; + /* fall through */ + + case DATA_ST_HEAD: + chunk_printf(&msg, sizeof(trash), + "# pxname,svname," + "qcur,qmax," + "scur,smax,slim,stot," + "bin,bout," + "dreq,dresp," + "ereq,econ,eresp," + "weight,act,bck," + "chkfail,chkdown" + "\n"); + + if (buffer_write_chunk(rep, &msg) != 0) + return 0; + + s->data_state = DATA_ST_INFO; + /* fall through */ + + case DATA_ST_INFO: + memset(&s->data_ctx, 0, sizeof(s->data_ctx)); + + s->data_ctx.stats.px = proxy; + s->data_ctx.stats.px_st = DATA_ST_PX_INIT; + s->data_state = DATA_ST_LIST; + /* fall through */ + + case DATA_ST_LIST: + /* dump proxies */ + while (s->data_ctx.stats.px) { + px = s->data_ctx.stats.px; + /* skip the disabled proxies and non-networked ones */ + if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE))) + if (stats_dump_proxy(s, px, NULL, 0) == 0) + return 0; + + s->data_ctx.stats.px = px->next; + s->data_ctx.stats.px_st = DATA_ST_PX_INIT; + } + /* here, we just have reached the last proxy */ + + s->data_state = DATA_ST_END; + /* fall through */ + + case DATA_ST_END: + s->data_state = DATA_ST_FIN; + return 1; + + case DATA_ST_FIN: + return 1; + + default: + /* unknown state ! */ + return -1; + } +} + + /* * Produces statistics data for the session . Expects to be called with * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN diff --git a/src/proto_uxst.c b/src/proto_uxst.c index e23d1d4f10..d8c0a9090e 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -45,11 +45,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -401,6 +403,7 @@ int uxst_event_accept(int fd) { memset(&s->logs, 0, sizeof(s->logs)); memset(&s->txn, 0, sizeof(s->txn)); + s->data_state = DATA_ST_INIT; s->data_source = DATA_SRC_NONE; s->uniq_id = totalconn; @@ -460,7 +463,6 @@ int uxst_event_accept(int fd) { if (l->timeout && tv_isset(l->timeout)) { EV_FD_SET(cfd, DIR_RD); tv_add(&s->req->rex, &now, &s->req->rto); - tv_add(&s->rep->wex, &now, &s->rep->wto); t->expire = s->req->rex; } @@ -1305,8 +1307,8 @@ void process_uxst_session(struct task *t, struct timeval *next) /* Processes data exchanges on the statistics socket. The client processing * is called and the task is put back in the wait queue or it is cleared. * In order to ease the transition, we simply simulate the server status - * for now. It only knows states SV_STIDLE and SV_STCLOSE. Returns in - * the task's expiration date. + * for now. It only knows states SV_STIDLE, SV_STDATA and SV_STCLOSE. Returns + * in the task's expiration date. */ void process_uxst_stats(struct task *t, struct timeval *next) { @@ -1314,40 +1316,51 @@ void process_uxst_stats(struct task *t, struct timeval *next) struct listener *listener; int fsm_resync = 0; + /* we need to be in DATA phase on the "server" side */ + if (s->srv_state == SV_STIDLE) { + s->srv_state = SV_STDATA; + s->data_source = DATA_SRC_STATS; + } + do { - //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__); - fsm_resync = 0; - fsm_resync |= process_uxst_cli(s); - if (s->srv_state == SV_STIDLE) { - if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) { - s->srv_state = SV_STCLOSE; - fsm_resync |= 1; - continue; - } - else if (s->cli_state == CL_STSHUTR || - (s->req->l >= s->req->rlim - s->req->data)) { - if (s->req->l == 0) { + fsm_resync = process_uxst_cli(s); + if (s->srv_state != SV_STDATA) + continue; + + if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) { + s->srv_state = SV_STCLOSE; + fsm_resync |= 1; + continue; + } + + if (s->data_state == DATA_ST_INIT) { + if ((s->req->l >= 10) && (memcmp(s->req->data, "show stat\n", 10) == 0)) { + /* send the stats, and changes the data_state */ + if (stats_dump_raw(s, NULL, 0) != 0) { s->srv_state = SV_STCLOSE; fsm_resync |= 1; continue; } - /* OK we have some remaining data to process. Just for the - * sake of an exercice, we copy the req into the resp, - * and flush the req. This produces a simple echo function. - */ - memcpy(s->rep->data, s->req->data, sizeof(s->rep->data)); - s->rep->l = s->req->l; - s->rep->rlim = s->rep->data + BUFSIZE; - s->rep->w = s->rep->data; - s->rep->lr = s->rep->r = s->rep->data + s->rep->l; - - s->req->l = 0; + } + else if (s->cli_state == CL_STSHUTR || (s->req->l >= s->req->rlim - s->req->data)) { s->srv_state = SV_STCLOSE; - fsm_resync |= 1; continue; } } + + if (s->data_state == DATA_ST_INIT) + continue; + + /* OK we have some remaining data to process. Just for the + * sake of an exercice, we copy the req into the resp, + * and flush the req. This produces a simple echo function. + */ + if (stats_dump_raw(s, NULL, 0) != 0) { + s->srv_state = SV_STCLOSE; + fsm_resync |= 1; + continue; + } } while (fsm_resync); if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) { @@ -1414,7 +1427,6 @@ __attribute__((constructor)) static void __uxst_protocol_init(void) { protocol_register(&proto_unix); - //tv_eternity(&global.unix_fe.clitimeout); }