From: Willy Tarreau Date: Wed, 17 Oct 2007 16:44:57 +0000 (+0200) Subject: [MEDIUM] implement the CSV output for the statistics X-Git-Tag: v1.3.13~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55bb8450c0b0fb4b081c611f97d25fa00331c11c;p=thirdparty%2Fhaproxy.git [MEDIUM] implement the CSV output for the statistics It is now possible to get CSV ouput from the statistics by simply appending ";csv" to the HTTP request sent to get the stats. The fields keep the same ordering as in the HTML page, and a field "pxname" has been prepended at the beginning of the line. --- diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h index 3fc14e7554..cecfbe2268 100644 --- a/include/proto/dumpstats.h +++ b/include/proto/dumpstats.h @@ -27,6 +27,8 @@ #include #include +#define STAT_FMT_HTML 0x1 + 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/include/types/session.h b/include/types/session.h index a76861912c..347bbaa8b7 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -74,8 +74,10 @@ #define SN_FINST_SHIFT 12 /* bit shift */ /* unused: 0x00008000 */ +/* Note: those flags must move to another place */ #define SN_STAT_HIDEDWN 0x00010000 /* hide 'down' servers in the stats page */ #define SN_STAT_NORFRSH 0x00020000 /* do not automatically refresh the stats page */ +#define SN_STAT_FMTCSV 0x00040000 /* dump the stats in CSV format instead of HTML */ /* WARNING: if new fields are added, they must be initialized in event_accept() diff --git a/src/dumpstats.c b/src/dumpstats.c index 4e2929c591..c77528dcc0 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -72,7 +72,8 @@ int stats_dump_http(struct session *s, struct uri_auth *uri, int flags) "HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n" "Connection: close\r\n" - "Content-Type: text/html\r\n"); + "Content-Type: %s\r\n", + (flags & STAT_FMT_HTML) ? "text/html" : "text/plain"); if (uri->refresh > 0 && !(s->flags & SN_STAT_NORFRSH)) chunk_printf(&msg, sizeof(trash), "Refresh: %d\r\n", @@ -100,8 +101,9 @@ int stats_dump_http(struct session *s, struct uri_auth *uri, int flags) /* fall through */ case DATA_ST_HEAD: - /* WARNING! This must fit in the first buffer !!! */ - chunk_printf(&msg, sizeof(trash), + if (flags & STAT_FMT_HTML) { + /* WARNING! This must fit in the first buffer !!! */ + chunk_printf(&msg, sizeof(trash), "Statistics Report for " PRODUCT_NAME "\n" "\n" "\n"); - + } else { + 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; @@ -184,7 +197,8 @@ int stats_dump_http(struct session *s, struct uri_auth *uri, int flags) * We are around 3.5 kB, add adding entries will * become tricky if we want to support 4kB buffers ! */ - chunk_printf(&msg, sizeof(trash), + if (flags & STAT_FMT_HTML) { + chunk_printf(&msg, sizeof(trash), "

" PRODUCT_NAME "%s

\n" "

Statistics Report for pid %d

\n" @@ -226,41 +240,41 @@ int stats_dump_http(struct session *s, struct uri_auth *uri, int flags) actconn ); - if (s->flags & SN_STAT_HIDEDWN) - chunk_printf(&msg, sizeof(trash), + if (s->flags & SN_STAT_HIDEDWN) + chunk_printf(&msg, sizeof(trash), "
  • Show all servers
    \n", uri->uri_prefix, "", (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : ""); - else - chunk_printf(&msg, sizeof(trash), + else + chunk_printf(&msg, sizeof(trash), "
  • Hide 'DOWN' servers
    \n", uri->uri_prefix, ";up", (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : ""); - if (uri->refresh > 0) { - if (s->flags & SN_STAT_NORFRSH) - chunk_printf(&msg, sizeof(trash), + if (uri->refresh > 0) { + if (s->flags & SN_STAT_NORFRSH) + chunk_printf(&msg, sizeof(trash), "
  • Enable refresh
    \n", uri->uri_prefix, (s->flags & SN_STAT_HIDEDWN) ? ";up" : "", ""); - else - chunk_printf(&msg, sizeof(trash), + else + chunk_printf(&msg, sizeof(trash), "
  • Disable refresh
    \n", uri->uri_prefix, (s->flags & SN_STAT_HIDEDWN) ? ";up" : "", ";norefresh"); - } + } - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, sizeof(trash), "
  • Refresh now
    \n", uri->uri_prefix, (s->flags & SN_STAT_HIDEDWN) ? ";up" : "", (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : ""); - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, sizeof(trash), "" "" "External ressources:
      \n" @@ -273,8 +287,9 @@ int stats_dump_http(struct session *s, struct uri_auth *uri, int flags) "" ); - if (buffer_write_chunk(rep, &msg) != 0) - return 0; + if (buffer_write_chunk(rep, &msg) != 0) + return 0; + } memset(&s->data_ctx, 0, sizeof(s->data_ctx)); @@ -301,9 +316,11 @@ int stats_dump_http(struct session *s, struct uri_auth *uri, int flags) /* fall through */ case DATA_ST_END: - chunk_printf(&msg, sizeof(trash), "\n"); - if (buffer_write_chunk(rep, &msg) != 0) - return 0; + if (flags & STAT_FMT_HTML) { + chunk_printf(&msg, sizeof(trash), "\n"); + if (buffer_write_chunk(rep, &msg) != 0) + return 0; + } s->data_state = DATA_ST_FIN; /* fall through */ @@ -366,30 +383,32 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, /* fall through */ case DATA_ST_PX_TH: - /* print a new table */ - chunk_printf(&msg, sizeof(trash), - "\n" - "" - "" - "" - "\n" - "" - "" - "" - "" - "" - "\n" - "" - "" - "" - "" - "" - "\n" - "", - px->id); - - if (buffer_write_chunk(rep, &msg) != 0) - return 0; + if (flags & STAT_FMT_HTML) { + /* print a new table */ + chunk_printf(&msg, sizeof(trash), + "
      %s
      QueueSessionsBytesDeniedErrorsServer
      CurMaxCurMaxLimitCumulInOutReqRespReqConnRespStatusWeightActBckCheckDown
      \n" + "" + "" + "" + "\n" + "" + "" + "" + "" + "" + "\n" + "" + "" + "" + "" + "" + "\n" + "", + px->id); + + if (buffer_write_chunk(rep, &msg) != 0) + return 0; + } s->data_ctx.stats.px_st = DATA_ST_PX_FE; /* fall through */ @@ -397,18 +416,20 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, case DATA_ST_PX_FE: /* print the frontend */ if (px->cap & PR_CAP_FE) { - chunk_printf(&msg, sizeof(trash), + if (flags & STAT_FMT_HTML) { + chunk_printf(&msg, sizeof(trash), /* name, queue */ "" - /* sessions : current, max, limit, cumul. */ - "" + /* sessions : current, max, limit, cumul */ + "" + "" /* bytes : in, out */ "" /* denied: req, resp */ "" /* errors : request, connect, response */ "" - /* server status : reflect backend status */ + /* server status : reflect frontend status */ "" /* rest of server: nothing */ "" @@ -419,6 +440,31 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, px->failed_req, px->state == PR_STRUN ? "OPEN" : px->state == PR_STIDLE ? "FULL" : "STOP"); + } else { + chunk_printf(&msg, sizeof(trash), + /* pxid, name, queue cur, queue max, */ + "%s,FRONTEND,,," + /* sessions : current, max, limit, cumul */ + "%d,%d,%d,%d," + /* bytes : in, out */ + "%lld,%lld," + /* denied: req, resp */ + "%d,%d," + /* errors : request, connect, response */ + "%d,,," + /* server status : reflect frontend status */ + "%s," + /* rest of server: nothing */ + ",,,,," + "\n", + px->id, + px->feconn, px->feconn_max, px->maxconn, px->cum_feconn, + px->bytes_in, px->bytes_out, + px->denied_req, px->denied_resp, + px->failed_req, + px->state == PR_STRUN ? "OPEN" : + px->state == PR_STIDLE ? "FULL" : "STOP"); + } if (buffer_write_chunk(rep, &msg) != 0) return 0; @@ -431,7 +477,6 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, case DATA_ST_PX_SV: /* stats.sv has been initialized above */ while (s->data_ctx.stats.sv != NULL) { - static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d ↑", "UP %d/%d ↓", "UP", "no check" }; int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */ sv = s->data_ctx.stats.sv; @@ -456,13 +501,17 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, continue; } - chunk_printf(&msg, sizeof(trash), + if (flags & STAT_FMT_HTML) { + static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d ↑", "UP %d/%d ↓", + "UP", "no check" }; + chunk_printf(&msg, sizeof(trash), /* name */ "" /* queue : current, max */ "" /* sessions : current, max, limit, cumul */ - "" + "" + "" /* bytes : in, out */ "" /* denied: req, resp */ @@ -478,14 +527,14 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, sv->failed_secu, sv->failed_conns, sv->failed_resp); - /* status */ - chunk_printf(&msg, sizeof(trash), "" /* act, bck */ @@ -495,15 +544,61 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, (sv->state & SRV_BACKUP) ? "-" : "Y", (sv->state & SRV_BACKUP) ? "Y" : "-"); - /* check failures : unique, fatal */ - if (sv->state & SRV_CHECKED) - chunk_printf(&msg, sizeof(trash), + /* check failures : unique, fatal */ + if (sv->state & SRV_CHECKED) + chunk_printf(&msg, sizeof(trash), "\n", sv->failed_checks, sv->down_trans); - else - chunk_printf(&msg, sizeof(trash), + else + chunk_printf(&msg, sizeof(trash), "\n"); + } else { + static char *srv_hlt_st[5] = { "DOWN,", "DOWN %d/%d,", "UP %d/%d,", + "UP,", "no check," }; + chunk_printf(&msg, sizeof(trash), + /* pxid, name */ + "%s,%s," + /* queue : current, max */ + "%d,%d," + /* sessions : current, max, limit, cumul */ + "%d,%d,%s,%d," + /* bytes : in, out */ + "%lld,%lld," + /* denied: req, resp */ + ",%d," + /* errors : request, connect, response */ + ",%d,%d," + "", + px->id, sv->id, + sv->nbpend, sv->nbpend_max, + sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess, + sv->bytes_in, sv->bytes_out, + sv->failed_secu, + sv->failed_conns, sv->failed_resp); + + /* status */ + chunk_printf(&msg, sizeof(trash), + srv_hlt_st[sv_state], + (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health), + (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise)); + + chunk_printf(&msg, sizeof(trash), + /* weight, active, backup */ + "%d,%d,%d," + "", + sv->uweight, + (sv->state & SRV_BACKUP) ? 0 : 1, + (sv->state & SRV_BACKUP) ? 1 : 0); + /* check failures : unique, fatal */ + if (sv->state & SRV_CHECKED) + chunk_printf(&msg, sizeof(trash), + "%d,%d,\n", + sv->failed_checks, sv->down_trans); + else + chunk_printf(&msg, sizeof(trash), + ",,\n"); + } if (buffer_write_chunk(rep, &msg) != 0) return 0; @@ -528,7 +623,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, if (px->srv && px->srv->eweight) gcd = px->srv->uweight / px->srv->eweight; - chunk_printf(&msg, sizeof(trash), + if (flags & STAT_FMT_HTML) { + chunk_printf(&msg, sizeof(trash), /* name */ "" /* queue : current, max */ @@ -557,7 +653,38 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, px->failed_conns, px->failed_resp, (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN", px->srv_map_sz * gcd, px->srv_act, px->srv_bck); - + } else { + chunk_printf(&msg, sizeof(trash), + /* pxid, name */ + "%s,BACKEND," + /* queue : current, max */ + "%d,%d," + /* sessions : current, max, limit, cumul */ + "%d,%d,%d,%d," + /* bytes : in, out */ + "%lld,%lld," + /* denied: req, resp */ + "%d,%d," + /* errors : request, connect, response */ + ",%d,%d," + /* server status : reflect backend status (up/down) : we display UP + * if the backend has known working servers or if it has no server at + * all (eg: for stats). Tthen we display the total weight, number of + * active and backups. */ + "%s," + "%d,%d,%d," + /* rest of server: nothing */ + ",," + "\n", + px->id, + px->nbpend /* or px->totpend ? */, px->nbpend_max, + px->beconn, px->beconn_max, px->fullconn, px->cum_beconn, + px->bytes_in, px->bytes_out, + px->denied_req, px->denied_resp, + px->failed_conns, px->failed_resp, + (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN", + px->srv_map_sz * gcd, px->srv_act, px->srv_bck); + } if (buffer_write_chunk(rep, &msg) != 0) return 0; } @@ -566,10 +693,12 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, /* fall through */ case DATA_ST_PX_END: - chunk_printf(&msg, sizeof(trash), "
      %s
      QueueSessionsBytesDeniedErrorsServer
      CurMaxCurMaxLimitCumulInOutReqRespReqConnRespStatusWeightActBckCheckDown
      Frontend%d%d%d%d%d%d%d%d%lld%lld%d%d%d%s
      %s%d%d%d%d%s%d%d%d%s%d%lld%lld"); - chunk_printf(&msg, sizeof(trash), + /* status */ + chunk_printf(&msg, sizeof(trash), ""); + chunk_printf(&msg, sizeof(trash), srv_hlt_st[sv_state], (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health), (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise)); - chunk_printf(&msg, sizeof(trash), + chunk_printf(&msg, sizeof(trash), /* weight */ "%d%d%d
      Backend

      \n"); + if (flags & STAT_FMT_HTML) { + chunk_printf(&msg, sizeof(trash), "

      \n"); - if (buffer_write_chunk(rep, &msg) != 0) - return 0; + if (buffer_write_chunk(rep, &msg) != 0) + return 0; + } s->data_ctx.stats.px_st = DATA_ST_PX_FIN; /* fall through */ diff --git a/src/proto_http.c b/src/proto_http.c index 82b8cea968..7077df5da9 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3387,7 +3387,8 @@ int produce_content(struct session *s) } else if (s->data_source == DATA_SRC_STATS) { /* dump server statistics */ - int ret = stats_dump_http(s, s->be->uri_auth, 0); + int ret = stats_dump_http(s, s->be->uri_auth, + (s->flags & SN_STAT_FMTCSV) ? 0 : STAT_FMT_HTML); if (ret >= 0) return ret; /* -1 indicates an error */ @@ -4694,6 +4695,15 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend) } } + h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len; + while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) { + if (memcmp(h, ";csv", 4) == 0) { + t->flags |= SN_STAT_FMTCSV; + break; + } + h++; + } + /* we are in front of a interceptable URI. Let's check * if there's an authentication and if it's valid. */