]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] implement the statistics output on a unix socket
authorWilly Tarreau <w@1wt.eu>
Wed, 17 Oct 2007 16:57:38 +0000 (18:57 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 18 Oct 2007 12:13:13 +0000 (14:13 +0200)
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.

include/proto/dumpstats.h
src/dumpstats.c
src/proto_uxst.c

index cecfbe2268d07ab697991eafd6cc9597e516537e..bcf1540061ea32dbecf41958a2fb1bf35686e9dc 100644 (file)
@@ -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);
 
index 13196e27825ab4268679f3a93c8a146f36806f83..3fdac866663ac2eb67cc770f4864d082722476d2 100644 (file)
 #include <proto/senddata.h>
 #include <proto/session.h>
 
+/*
+ * 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
index e23d1d4f107095fbd684861440928d3298597888..d8c0a9090ebb65ee674839b25930d339b0d6f6bf 100644 (file)
 #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 @@ 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 <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 @@ 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);
 }