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.
This commit is contained in:
Frdric Lcaille 2023-01-18 11:52:21 +01:00 committed by Willy Tarreau
parent 1ea5f410ff
commit 9969adbcdc
9 changed files with 147 additions and 23 deletions

View File

@ -28,6 +28,7 @@ struct fe_counters {
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 @@ struct fe_counters {
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 */

View File

@ -143,6 +143,21 @@ static inline void proxy_inc_fe_sess_ctr(struct listener *l, struct proxy *fe)
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 @@ static inline void proxy_inc_be_ctr(struct proxy *be)
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));
}

View File

@ -459,6 +459,14 @@ enum stat_field {
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

View File

@ -94,6 +94,8 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit)
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 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit)
}
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 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit)
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) &&

View File

@ -3546,7 +3546,7 @@ void syslog_fd_handler(int fd)
/* 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 @@ static void syslog_io_handler(struct appctx *appctx)
/* 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);

View File

@ -978,6 +978,8 @@ static int h1_init(struct connection *conn, struct proxy *proxy, struct session
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 @@ static int h1_handle_internal_err(struct h1c *h1c)
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 @@ static int h1_handle_parsing_error(struct h1c *h1c)
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 @@ static int h1_handle_not_impl_err(struct h1c *h1c)
}
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 @@ static int h1_handle_req_tout(struct h1c *h1c)
}
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)

View File

@ -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 @@ static int h2_init(struct connection *conn, struct proxy *prx, struct session *s
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);

View File

@ -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 @@ static int qc_init(struct connection *conn, struct proxy *prx,
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);

View File

@ -263,6 +263,14 @@ const struct name_desc stat_fields[ST_F_TOTAL_FIELDS] = {
[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 @@ static int stats_dump_fields_html(struct buffer *out,
/* 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>&nbsp;&nbsp;Compressed 2xx:</th><td>%s</td><td>(%d%%)</td></tr>"
@ -925,13 +953,7 @@ static int stats_dump_fields_html(struct buffer *out,
"<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 @@ static int stats_dump_fields_html(struct buffer *out,
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 @@ int stats_fill_fe_stats(struct proxy *px, struct field *stats, int len,
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 @@ int stats_fill_fe_stats(struct proxy *px, struct field *stats, int len,
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.