From 9969adbcdc1a79a6e8bb0a6283191d8d330a04f1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= Date: Wed, 18 Jan 2023 11:52:21 +0100 Subject: [PATCH] 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. --- include/haproxy/counters-t.h | 3 +- include/haproxy/proxy.h | 30 ++++++++++-- include/haproxy/stats-t.h | 8 ++++ src/http_ana.c | 18 ++++++-- src/log.c | 4 +- src/mux_h1.c | 10 ++-- src/mux_h2.c | 2 + src/mux_quic.c | 5 ++ src/stats.c | 90 ++++++++++++++++++++++++++++++++---- 9 files changed, 147 insertions(+), 23 deletions(-) diff --git a/include/haproxy/counters-t.h b/include/haproxy/counters-t.h index 1ea68dd6c3..849f096838 100644 --- a/include/haproxy/counters-t.h +++ b/include/haproxy/counters-t.h @@ -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 */ diff --git a/include/haproxy/proxy.h b/include/haproxy/proxy.h index 01971531b7..27a7ae861e 100644 --- a/include/haproxy/proxy.h +++ b/include/haproxy/proxy.h @@ -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. + * 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. + * 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 9cc1d33a9f..5a46d30dfa 100644 --- a/include/haproxy/stats-t.h +++ b/include/haproxy/stats-t.h @@ -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 diff --git a/src/http_ana.c b/src/http_ana.c index 4f1decdbbd..8cee6f9122 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -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) && diff --git a/src/log.c b/src/log.c index 3fbae30fc8..fc4cdd9cba 100644 --- a/src/log.c +++ b/src/log.c @@ -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); diff --git a/src/mux_h1.c b/src/mux_h1.c index ce51f43a70..1dea69937d 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -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) diff --git a/src/mux_h2.c b/src/mux_h2.c index 4c5171a0bd..bc82cb3f8e 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/src/mux_quic.c b/src/mux_quic.c index 1060635d24..26006fb667 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -5,9 +5,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -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); diff --git a/src/stats.c b/src/stats.c index 5e3dfbe5c9..4a1dca2f21 100644 --- a/src/stats.c +++ b/src/stats.c @@ -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, + "- HTTP/1 sessions:%s" + "- HTTP/2 sessions:%s" + "- HTTP/3 sessions:%s" + "- other sessions:%s" "Cum. HTTP requests:%s" + "- HTTP/1 requests:%s" + "- HTTP/2 requests:%s" + "- HTTP/3 requests:%s" + "- other requests:%s" + "", + 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, "- HTTP 1xx responses:%s" "- HTTP 2xx responses:%s" "  Compressed 2xx:%s(%d%%)" @@ -925,13 +953,7 @@ static int stats_dump_fields_html(struct buffer *out, "- HTTP 4xx responses:%s" "- HTTP 5xx responses:%s" "- other responses:%s" - "Intercepted requests:%s" - "Cache lookups:%s" - "Cache hits:%s(%d%%)" - "Failed hdr rewrites:%s" - "Internal errors:%s" "", - 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, + "Intercepted requests:%s" + "Cache lookups:%s" + "Cache hits:%s(%d%%)" + "Failed hdr rewrites:%s" + "Internal errors:%s" + "", 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. -- 2.39.5