[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 cecfbe2..bcf1540 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 13196e2..3fdac86 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -47,6 +47,88 @@
/*
* Produces statistics data for the session <s>. Expects to be called with
+ * s->cli_state == CL_STSHUTR. It *may* make use of informations from <uri>
+ * and <flags>.
+ * 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 <s>. Expects to be called with
* s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
* flag from the session, which it uses to keep on being called when there is
* free space in the buffer, of simply by letting an empty buffer upon return.
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index e23d1d4..d8c0a90 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -45,11 +45,13 @@
#include <proto/acl.h>
#include <proto/backend.h>
#include <proto/buffers.h>
+#include <proto/dumpstats.h>
#include <proto/fd.h>
#include <proto/log.h>
#include <proto/protocols.h>
#include <proto/proto_uxst.h>
#include <proto/queue.h>
+#include <proto/senddata.h>
#include <proto/session.h>
#include <proto/stream_sock.h>
#include <proto/task.h>
@@ -401,6 +403,7 @@
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 @@
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 @@
/* 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 <next>
- * the task's expiration date.
+ * for now. It only knows states SV_STIDLE, SV_STDATA and SV_STCLOSE. Returns
+ * in <next> the task's expiration date.
*/
void process_uxst_stats(struct task *t, struct timeval *next)
{
@@ -1314,40 +1316,51 @@
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 @@
static void __uxst_protocol_init(void)
{
protocol_register(&proto_unix);
- //tv_eternity(&global.unix_fe.clitimeout);
}