MINOR: stats: add by HTTP version cumulated number of sessions and requests
Add cum_sess_ver[] new array of counters to count the number of cumulated
HTTP sessions by version (h1, h2 or h3).
Implement proxy_inc_fe_cum_sess_ver_ctr() to increment these counter.
This function is called each a HTTP mux is correctly initialized. The QUIC
must before verify the application operations for the mux is for h3 before
calling proxy_inc_fe_cum_sess_ver_ctr().
ST_F_SESS_OTHER stat field for the cumulated of sessions others than
HTTP sessions is deduced from ->cum_sess_ver counter (for all the session,
not only HTTP sessions) from which the HTTP sessions counters are substracted.
Add cum_req[] new array of counters to count the number of cumulated HTTP
requests by version and others than HTTP requests. This new member replace ->cum_req.
Modify proxy_inc_fe_req_ctr() which increments these counters to pass an HTTP
version, 0 special values meaning "other than an HTTP request". This is the case
for instance for syslog.c from which proxy_inc_fe_req_ctr() is called with 0
as version parameter.
ST_F_REQ_TOT stat field compputing for the cumulated number of requests is modified
to count the sum of all the cum_req[] counters.
As this patch is useful for QUIC, it must be backported to 2.7.
diff --git a/include/haproxy/counters-t.h b/include/haproxy/counters-t.h
index 1ea68dd..849f096 100644
--- a/include/haproxy/counters-t.h
+++ b/include/haproxy/counters-t.h
@@ -28,6 +28,7 @@
unsigned int conn_max; /* max # of active sessions */
long long cum_conn; /* cumulated number of received connections */
long long cum_sess; /* cumulated number of accepted connections */
+ long long cum_sess_ver[3]; /* cumulated number of h1/h2/h3 sessions */
unsigned int cps_max; /* maximum of new connections received per second */
unsigned int sps_max; /* maximum of new connections accepted per second (sessions) */
@@ -53,7 +54,7 @@
union {
struct {
- long long cum_req; /* cumulated number of processed HTTP requests */
+ long long cum_req[4]; /* cumulated number of processed other/h1/h2/h3 requests */
long long comp_rsp; /* number of compressed responses */
unsigned int rps_max; /* maximum of new HTTP requests second observed */
long long rsp[6]; /* http response codes */
diff --git a/include/haproxy/proxy.h b/include/haproxy/proxy.h
index 0197153..27a7ae8 100644
--- a/include/haproxy/proxy.h
+++ b/include/haproxy/proxy.h
@@ -143,6 +143,21 @@
update_freq_ctr(&fe->fe_sess_per_sec, 1));
}
+/* increase the number of cumulated HTTP sessions on the designated frontend.
+ * <http_ver> must be the HTTP version for such requests.
+ */
+static inline void proxy_inc_fe_cum_sess_ver_ctr(struct listener *l, struct proxy *fe,
+ unsigned int http_ver)
+{
+ if (http_ver == 0 ||
+ http_ver > sizeof(fe->fe_counters.cum_sess_ver) / sizeof(*fe->fe_counters.cum_sess_ver))
+ return;
+
+ _HA_ATOMIC_INC(&fe->fe_counters.cum_sess_ver[http_ver - 1]);
+ if (l && l->counters)
+ _HA_ATOMIC_INC(&l->counters->cum_sess_ver[http_ver - 1]);
+}
+
/* increase the number of cumulated connections on the designated backend */
static inline void proxy_inc_be_ctr(struct proxy *be)
{
@@ -151,12 +166,19 @@
update_freq_ctr(&be->be_sess_per_sec, 1));
}
-/* increase the number of cumulated requests on the designated frontend */
-static inline void proxy_inc_fe_req_ctr(struct listener *l, struct proxy *fe)
+/* increase the number of cumulated requests on the designated frontend.
+ * <http_ver> must be the HTTP version for HTTP request. 0 may be provided
+ * for others requests.
+ */
+static inline void proxy_inc_fe_req_ctr(struct listener *l, struct proxy *fe,
+ unsigned int http_ver)
{
- _HA_ATOMIC_INC(&fe->fe_counters.p.http.cum_req);
+ if (http_ver >= sizeof(fe->fe_counters.p.http.cum_req) / sizeof(*fe->fe_counters.p.http.cum_req))
+ return;
+
+ _HA_ATOMIC_INC(&fe->fe_counters.p.http.cum_req[http_ver]);
if (l && l->counters)
- _HA_ATOMIC_INC(&l->counters->p.http.cum_req);
+ _HA_ATOMIC_INC(&l->counters->p.http.cum_req[http_ver]);
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.p.http.rps_max,
update_freq_ctr(&fe->fe_req_per_sec, 1));
}
diff --git a/include/haproxy/stats-t.h b/include/haproxy/stats-t.h
index 9cc1d33..5a46d30 100644
--- a/include/haproxy/stats-t.h
+++ b/include/haproxy/stats-t.h
@@ -459,6 +459,14 @@
ST_F_AGG_SRV_CHECK_STATUS,
ST_F_AGG_CHECK_STATUS,
ST_F_SRID,
+ ST_F_SESS_OTHER,
+ ST_F_H1SESS,
+ ST_F_H2SESS,
+ ST_F_H3SESS,
+ ST_F_REQ_OTHER,
+ ST_F_H1REQ,
+ ST_F_H2REQ,
+ ST_F_H3REQ,
/* must always be the last one */
ST_F_TOTAL_FIELDS
diff --git a/src/http_ana.c b/src/http_ana.c
index 4f1decd..8cee6f9 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -94,6 +94,8 @@
struct http_msg *msg = &txn->req;
struct htx *htx;
struct htx_sl *sl;
+ char http_ver;
+ int len;
DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn, msg);
@@ -127,11 +129,22 @@
}
htx = htxbuf(&req->buf);
+ sl = http_get_stline(htx);
+ len = HTX_SL_REQ_VLEN(sl);
+ if (len < 6) {
+ http_ver = 0;
+ }
+ else {
+ char *ptr;
+
+ ptr = HTX_SL_REQ_VPTR(sl);
+ http_ver = ptr[5] - '0';
+ }
/* Parsing errors are caught here */
if (htx->flags & (HTX_FL_PARSING_ERROR|HTX_FL_PROCESSING_ERROR)) {
stream_inc_http_req_ctr(s);
- proxy_inc_fe_req_ctr(sess->listener, sess->fe);
+ proxy_inc_fe_req_ctr(sess->listener, sess->fe, http_ver);
if (htx->flags & HTX_FL_PARSING_ERROR) {
stream_inc_http_err_ctr(s);
goto return_bad_req;
@@ -145,13 +158,12 @@
msg->msg_state = HTTP_MSG_BODY;
stream_inc_http_req_ctr(s);
- proxy_inc_fe_req_ctr(sess->listener, sess->fe); /* one more valid request for this FE */
+ proxy_inc_fe_req_ctr(sess->listener, sess->fe, http_ver); /* one more valid request for this FE */
/* kill the pending keep-alive timeout */
req->analyse_exp = TICK_ETERNITY;
BUG_ON(htx_get_first_type(htx) != HTX_BLK_REQ_SL);
- sl = http_get_stline(htx);
/* 0: we might have to print this header in debug mode */
if (unlikely((global.mode & MODE_DEBUG) &&
diff --git a/src/log.c b/src/log.c
index 3fbae30..fc4cdd9 100644
--- a/src/log.c
+++ b/src/log.c
@@ -3546,7 +3546,7 @@
/* update counters */
_HA_ATOMIC_INC(&cum_log_messages);
- proxy_inc_fe_req_ctr(l, l->bind_conf->frontend);
+ proxy_inc_fe_req_ctr(l, l->bind_conf->frontend, 0);
parse_log_message(buf->area, buf->data, &level, &facility, metadata, &message, &size);
@@ -3653,7 +3653,7 @@
/* update counters */
_HA_ATOMIC_INC(&cum_log_messages);
- proxy_inc_fe_req_ctr(l, frontend);
+ proxy_inc_fe_req_ctr(l, frontend, 0);
parse_log_message(buf->area, buf->data, &level, &facility, metadata, &message, &size);
diff --git a/src/mux_h1.c b/src/mux_h1.c
index ce51f43..1dea699 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -978,6 +978,8 @@
else if (h1_recv_allowed(h1c))
h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event);
+ if (!conn_is_back(conn))
+ proxy_inc_fe_cum_sess_ver_ctr(sess->listener, proxy, 1);
HA_ATOMIC_INC(&h1c->px_counters->open_conns);
HA_ATOMIC_INC(&h1c->px_counters->total_conns);
@@ -2655,7 +2657,7 @@
int ret = 0;
session_inc_http_req_ctr(sess);
- proxy_inc_fe_req_ctr(sess->listener, sess->fe);
+ proxy_inc_fe_req_ctr(sess->listener, sess->fe, 1);
_HA_ATOMIC_INC(&sess->fe->fe_counters.p.http.rsp[5]);
_HA_ATOMIC_INC(&sess->fe->fe_counters.internal_errors);
if (sess->listener && sess->listener->counters)
@@ -2685,7 +2687,7 @@
session_inc_http_req_ctr(sess);
session_inc_http_err_ctr(sess);
- proxy_inc_fe_req_ctr(sess->listener, sess->fe);
+ proxy_inc_fe_req_ctr(sess->listener, sess->fe, 1);
_HA_ATOMIC_INC(&sess->fe->fe_counters.p.http.rsp[4]);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_req);
if (sess->listener && sess->listener->counters)
@@ -2717,7 +2719,7 @@
}
session_inc_http_req_ctr(sess);
- proxy_inc_fe_req_ctr(sess->listener, sess->fe);
+ proxy_inc_fe_req_ctr(sess->listener, sess->fe, 1);
_HA_ATOMIC_INC(&sess->fe->fe_counters.p.http.rsp[4]);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_req);
if (sess->listener && sess->listener->counters)
@@ -2747,7 +2749,7 @@
}
session_inc_http_req_ctr(sess);
- proxy_inc_fe_req_ctr(sess->listener, sess->fe);
+ proxy_inc_fe_req_ctr(sess->listener, sess->fe, 1);
_HA_ATOMIC_INC(&sess->fe->fe_counters.p.http.rsp[4]);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_req);
if (sess->listener && sess->listener->counters)
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 4c5171a..bc82cb3 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -26,6 +26,7 @@
#include <haproxy/log.h>
#include <haproxy/mux_h2-t.h>
#include <haproxy/net_helper.h>
+#include <haproxy/proxy.h>
#include <haproxy/session-t.h>
#include <haproxy/stats.h>
#include <haproxy/stconn.h>
@@ -1038,6 +1039,7 @@
goto fail_stream;
}
+ proxy_inc_fe_cum_sess_ver_ctr(sess->listener, prx, 2);
HA_ATOMIC_INC(&h2c->px_counters->open_conns);
HA_ATOMIC_INC(&h2c->px_counters->total_conns);
diff --git a/src/mux_quic.c b/src/mux_quic.c
index 1060635..26006fb 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -5,9 +5,11 @@
#include <haproxy/api.h>
#include <haproxy/connection.h>
#include <haproxy/dynbuf.h>
+#include <haproxy/h3.h>
#include <haproxy/list.h>
#include <haproxy/ncbuf.h>
#include <haproxy/pool.h>
+#include <haproxy/proxy.h>
#include <haproxy/qmux_http.h>
#include <haproxy/qmux_trace.h>
#include <haproxy/quic_conn.h>
@@ -2208,6 +2210,9 @@
goto fail_install_app_ops;
}
+ if (qcc->app_ops == &h3_ops)
+ proxy_inc_fe_cum_sess_ver_ctr(sess->listener, prx, 3);
+
/* init read cycle */
tasklet_wakeup(qcc->wait_event.tasklet);
diff --git a/src/stats.c b/src/stats.c
index 5e3dfbe..4a1dca2 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -263,6 +263,14 @@
[ST_F_AGG_SRV_STATUS ] = { .name = "agg_server_status", .desc = "Backend's aggregated gauge of servers' status" },
[ST_F_AGG_CHECK_STATUS] = { .name = "agg_check_status", .desc = "Backend's aggregated gauge of servers' state check status" },
[ST_F_SRID] = { .name = "srid", .desc = "Server id revision, to prevent server id reuse mixups" },
+ [ST_F_SESS_OTHER] = { .name = "sess_other", .desc = "Total number of sessions other than HTTP since process started" },
+ [ST_F_H1SESS] = { .name = "h1sess", .desc = "Total number of HTTP/1 sessions since process started" },
+ [ST_F_H2SESS] = { .name = "h2sess", .desc = "Total number of HTTP/2 sessions since process started" },
+ [ST_F_H3SESS] = { .name = "h3sess", .desc = "Total number of HTTP/3 sessions since process started" },
+ [ST_F_REQ_OTHER] = { .name = "req_other", .desc = "Total number of sessions other than HTTP processed by this object since the worker process started" },
+ [ST_F_H1REQ] = { .name = "h1req", .desc = "Total number of HTTP/1 sessions processed by this object since the worker process started" },
+ [ST_F_H2REQ] = { .name = "h2req", .desc = "Total number of hTTP/2 sessions processed by this object since the worker process started" },
+ [ST_F_H3REQ] = { .name = "h3req", .desc = "Total number of HTTP/3 sessions processed by this object since the worker process started" },
};
/* one line of info */
@@ -917,7 +925,27 @@
/* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
if (strcmp(field_str(stats, ST_F_MODE), "http") == 0) {
chunk_appendf(out,
+ "<tr><th>- HTTP/1 sessions:</th><td>%s</td></tr>"
+ "<tr><th>- HTTP/2 sessions:</th><td>%s</td></tr>"
+ "<tr><th>- HTTP/3 sessions:</th><td>%s</td></tr>"
+ "<tr><th>- other sessions:</th><td>%s</td></tr>"
"<tr><th>Cum. HTTP requests:</th><td>%s</td></tr>"
+ "<tr><th>- HTTP/1 requests:</th><td>%s</td></tr>"
+ "<tr><th>- HTTP/2 requests:</th><td>%s</td></tr>"
+ "<tr><th>- HTTP/3 requests:</th><td>%s</td></tr>"
+ "<tr><th>- other requests:</th><td>%s</td></tr>"
+ "",
+ U2H(stats[ST_F_H1SESS].u.u64),
+ U2H(stats[ST_F_H2SESS].u.u64),
+ U2H(stats[ST_F_H3SESS].u.u64),
+ U2H(stats[ST_F_SESS_OTHER].u.u64),
+ U2H(stats[ST_F_REQ_TOT].u.u64),
+ U2H(stats[ST_F_H1REQ].u.u64),
+ U2H(stats[ST_F_H2REQ].u.u64),
+ U2H(stats[ST_F_H3REQ].u.u64),
+ U2H(stats[ST_F_REQ_OTHER].u.u64));
+
+ chunk_appendf(out,
"<tr><th>- HTTP 1xx responses:</th><td>%s</td></tr>"
"<tr><th>- HTTP 2xx responses:</th><td>%s</td></tr>"
"<tr><th> Compressed 2xx:</th><td>%s</td><td>(%d%%)</td></tr>"
@@ -925,13 +953,7 @@
"<tr><th>- HTTP 4xx responses:</th><td>%s</td></tr>"
"<tr><th>- HTTP 5xx responses:</th><td>%s</td></tr>"
"<tr><th>- other responses:</th><td>%s</td></tr>"
- "<tr><th>Intercepted requests:</th><td>%s</td></tr>"
- "<tr><th>Cache lookups:</th><td>%s</td></tr>"
- "<tr><th>Cache hits:</th><td>%s</td><td>(%d%%)</td></tr>"
- "<tr><th>Failed hdr rewrites:</th><td>%s</td></tr>"
- "<tr><th>Internal errors:</th><td>%s</td></tr>"
"",
- U2H(stats[ST_F_REQ_TOT].u.u64),
U2H(stats[ST_F_HRSP_1XX].u.u64),
U2H(stats[ST_F_HRSP_2XX].u.u64),
U2H(stats[ST_F_COMP_RSP].u.u64),
@@ -940,7 +962,15 @@
U2H(stats[ST_F_HRSP_3XX].u.u64),
U2H(stats[ST_F_HRSP_4XX].u.u64),
U2H(stats[ST_F_HRSP_5XX].u.u64),
- U2H(stats[ST_F_HRSP_OTHER].u.u64),
+ U2H(stats[ST_F_HRSP_OTHER].u.u64));
+
+ chunk_appendf(out,
+ "<tr><th>Intercepted requests:</th><td>%s</td></tr>"
+ "<tr><th>Cache lookups:</th><td>%s</td></tr>"
+ "<tr><th>Cache hits:</th><td>%s</td><td>(%d%%)</td></tr>"
+ "<tr><th>Failed hdr rewrites:</th><td>%s</td></tr>"
+ "<tr><th>Internal errors:</th><td>%s</td></tr>"
+ "",
U2H(stats[ST_F_INTERCEPTED].u.u64),
U2H(stats[ST_F_CACHE_LOOKUPS].u.u64),
U2H(stats[ST_F_CACHE_HITS].u.u64),
@@ -1805,9 +1835,18 @@
case ST_F_REQ_RATE_MAX:
metric = mkf_u32(FN_MAX, px->fe_counters.p.http.rps_max);
break;
- case ST_F_REQ_TOT:
- metric = mkf_u64(FN_COUNTER, px->fe_counters.p.http.cum_req);
+ case ST_F_REQ_TOT: {
+ int i;
+ uint64_t total_req;
+ size_t nb_reqs =
+ sizeof(px->fe_counters.p.http.cum_req) / sizeof(*px->fe_counters.p.http.cum_req);
+
+ total_req = 0;
+ for (i = 0; i < nb_reqs; i++)
+ total_req += px->fe_counters.p.http.cum_req[i];
+ metric = mkf_u64(FN_COUNTER, total_req);
break;
+ }
case ST_F_COMP_IN:
metric = mkf_u64(FN_COUNTER, px->fe_counters.comp_in);
break;
@@ -1829,6 +1868,39 @@
case ST_F_CONN_TOT:
metric = mkf_u64(FN_COUNTER, px->fe_counters.cum_conn);
break;
+ case ST_F_SESS_OTHER: {
+ int i;
+ uint64_t total_sess;
+ size_t nb_sess =
+ sizeof(px->fe_counters.cum_sess_ver) / sizeof(*px->fe_counters.cum_sess_ver);
+
+ total_sess = px->fe_counters.cum_sess;
+ for (i = 0; i < nb_sess; i++)
+ total_sess -= px->fe_counters.cum_sess_ver[i];
+ metric = mkf_u64(FN_COUNTER, total_sess);
+ break;
+ }
+ case ST_F_H1SESS:
+ metric = mkf_u64(FN_COUNTER, px->fe_counters.cum_sess_ver[0]);
+ break;
+ case ST_F_H2SESS:
+ metric = mkf_u64(FN_COUNTER, px->fe_counters.cum_sess_ver[1]);
+ break;
+ case ST_F_H3SESS:
+ metric = mkf_u64(FN_COUNTER, px->fe_counters.cum_sess_ver[2]);
+ break;
+ case ST_F_REQ_OTHER:
+ metric = mkf_u64(FN_COUNTER, px->fe_counters.p.http.cum_req[0]);
+ break;
+ case ST_F_H1REQ:
+ metric = mkf_u64(FN_COUNTER, px->fe_counters.p.http.cum_req[1]);
+ break;
+ case ST_F_H2REQ:
+ metric = mkf_u64(FN_COUNTER, px->fe_counters.p.http.cum_req[2]);
+ break;
+ case ST_F_H3REQ:
+ metric = mkf_u64(FN_COUNTER, px->fe_counters.p.http.cum_req[3]);
+ break;
default:
/* not used for frontends. If a specific metric
* is requested, return an error. Otherwise continue.