[MEDIUM] continous statistics
By default, counters used for statistics calculation are incremented
only when a session finishes. It works quite well when serving small
objects, but with big ones (for example large images or archives) or
with A/V streaming, a graph generated from haproxy counters looks like
a hedgehog.
This patch implements a contstats (continous statistics) option.
When set counters get incremented continuously, during a whole session.
Recounting touches a hotpath directly so it is not enabled by default,
as it has small performance impact (~0.5%).
diff --git a/doc/configuration.txt b/doc/configuration.txt
index f72a95b..149f330 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -266,6 +266,7 @@
option allbackups X - X X
option checkcache X - X X
option clitcpka X X X -
+option contstats X X X -
option dontlognull X X X -
option forceclose X - X X
option forwardfor X X X X
@@ -324,6 +325,15 @@
----------------------+----------+----------+---------+---------
keyword defaults frontend listen backend
+option contstats
+ By default, counters used for statistics calculation are incremented
+ only when a session finishes. It works quite well when serving small
+ objects, but with big ones (for example large images or archives) or
+ with A/V streaming, a graph generated from haproxy counters looks like
+ a hedgehog. With this option enabled counters get incremented continuously,
+ during a whole session. Recounting touches a hotpath directly so
+ it is not enabled by default, as it has small performance impact (~0.5%).
+
2.1) using ACLs
---------------
diff --git a/include/proto/session.h b/include/proto/session.h
index a18669e..4b86af2 100644
--- a/include/proto/session.h
+++ b/include/proto/session.h
@@ -33,6 +33,8 @@
/* perform minimal intializations, report 0 in case of error, 1 if OK. */
int init_session();
+void session_process_counters(struct session *s);
+
#endif /* _PROTO_SESSION_H */
/*
diff --git a/include/types/backend.h b/include/types/backend.h
index 9089469..c0c0809 100644
--- a/include/types/backend.h
+++ b/include/types/backend.h
@@ -57,6 +57,7 @@
#define PR_O_TPXY_CIP 0x04000000 /* bind to the client's IP address when connect()ing */
#define PR_O_TPXY_CLI 0x06000000 /* bind to the client's IP+port when connect()ing */
#define PR_O_TPXY_MASK 0x06000000 /* bind to a non-local address when connect()ing */
+
#define PR_O_TCPSPLICE 0x08000000 /* delegate data transfer to linux kernel's tcp_splice */
/* BALANCE: exclusive values */
@@ -68,6 +69,7 @@
#define PR_O_BALANCE_L7 0x40000000 /* mask to match layer7-based algorithms */
#define PR_O_BALANCE 0x70000000 /* mask to extract BALANCE algorithm */
+#define PR_O_CONTSTATS 0x80000000 /* continous counters */
#endif /* _TYPES_BACKEND_H */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 9e895c4..cd8bdbb 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -98,6 +98,7 @@
{ "httpclose", PR_O_HTTP_CLOSE, PR_CAP_FE | PR_CAP_BE, 0 },
{ "nolinger", PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0 },
{ "logasap", PR_O_LOGASAP, PR_CAP_FE, 0 },
+ { "contstats", PR_O_CONTSTATS, PR_CAP_FE, 0 },
{ "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0 },
{ "checkcache", PR_O_CHK_CACHE, PR_CAP_BE, 0 },
{ "dontlognull", PR_O_NULLNOLOG, PR_CAP_FE, 0 },
diff --git a/src/proto_http.c b/src/proto_http.c
index feed6cc..3727431 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -613,6 +613,10 @@
} while (fsm_resync);
if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
+
+ if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
+ session_process_counters(s);
+
s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
@@ -651,21 +655,7 @@
}
s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
- if (s->req != NULL)
- s->logs.bytes_in = s->req->total;
- if (s->rep != NULL)
- s->logs.bytes_out = s->rep->total;
-
- s->fe->bytes_in += s->logs.bytes_in;
- s->fe->bytes_out += s->logs.bytes_out;
- if (s->be != s->fe) {
- s->be->bytes_in += s->logs.bytes_in;
- s->be->bytes_out += s->logs.bytes_out;
- }
- if (s->srv) {
- s->srv->bytes_in += s->logs.bytes_in;
- s->srv->bytes_out += s->logs.bytes_out;
- }
+ session_process_counters(s);
/* let's do a final log if we need it */
if (s->logs.logwait &&
@@ -3096,6 +3086,7 @@
http_sess_log(t);
else
tcp_sess_log(t);
+ t->logs.bytes_in = 0;
}
/* Note: we must not try to cheat by jumping directly to DATA,
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 0b3f317..ca7e1e3 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -1300,6 +1300,10 @@
} while (fsm_resync);
if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
+
+ if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
+ session_process_counters(s);
+
s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
@@ -1332,23 +1336,7 @@
}
s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
- if (s->req != NULL)
- s->logs.bytes_in = s->req->total;
- if (s->rep != NULL)
- s->logs.bytes_out = s->rep->total;
-
- if (s->fe) {
- s->fe->bytes_in += s->logs.bytes_in;
- s->fe->bytes_out += s->logs.bytes_out;
- }
- if (s->be && (s->be != s->fe)) {
- s->be->bytes_in += s->logs.bytes_in;
- s->be->bytes_out += s->logs.bytes_out;
- }
- if (s->srv) {
- s->srv->bytes_in += s->logs.bytes_in;
- s->srv->bytes_out += s->logs.bytes_out;
- }
+ session_process_counters(s);
/* let's do a final log if we need it */
if (s->logs.logwait &&
diff --git a/src/session.c b/src/session.c
index 86696f4..e7fd8bd 100644
--- a/src/session.c
+++ b/src/session.c
@@ -102,6 +102,38 @@
return pool2_session != NULL;
}
+void session_process_counters(struct session *s) {
+
+ unsigned long long bytes;
+
+ if (s->req && s->req->total != s->logs.bytes_in) {
+ bytes = s->req->total - s->logs.bytes_in;
+
+ s->fe->bytes_in += bytes;
+
+ if (s->be != s->fe)
+ s->be->bytes_in += bytes;
+
+ if (s->srv)
+ s->srv->bytes_in += bytes;
+
+ s->logs.bytes_in = s->req->total;
+ }
+
+ if (s->rep && s->rep->total != s->logs.bytes_out) {
+ bytes = s->rep->total - s->logs.bytes_out;
+
+ s->fe->bytes_out += bytes;
+
+ if (s->be != s->fe)
+ s->be->bytes_out += bytes;
+
+ if (s->srv)
+ s->srv->bytes_out += bytes;
+
+ s->logs.bytes_out = s->rep->total;
+ }
+}
/*
* Local variables: