diff --git a/doc/configuration.txt b/doc/configuration.txt
index 42cd5f883..e7ef09429 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -23116,6 +23116,10 @@ fe_client_timeout integer
fe_defbe string
fe_id integer
fe_name string
+req.in integer
+req.out integer
+res.in integer
+res.out integer
res.timer.data integer
sc0_bytes_in_rate([
]) integer
sc0_bytes_out_rate([]) integer
@@ -23751,6 +23755,28 @@ fe_name : string
backends to check from which frontend it was called, or to stick all users
coming via a same frontend to the same server.
+req.in : integer
+ This returns the number of bytes received from the client. The value
+ corresponds to what was received by HAProxy, including some headers and some
+ internal encoding overhead. Request compression does not affect the value
+ reported here.
+
+req.out : integer
+ This returns the number of bytes sent to the server. The value corresponds to
+ what was sent by HAProxy, including some headers and some internal encoding
+ overhead. Request compression affects the value reported here.
+
+res.in : integer
+ This returns the number of bytes received from the server. The value
+ corresponds to what was received by HAProxy, including some headers and some
+ internal encoding overhead. Response compression does not affect the value
+ reported here.
+
+res.out : integer
+ This returns the number of bytes sent to the client. The value corresponds to
+ what was sent by HAProxy, including some headers and some internal encoding
+ overhead. Response compression affects the value reported here.
+
res.timer.data : integer
this is the total transfer time of the response payload till the last byte
sent to the client. In HTTP it starts after the last response header (after
diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h
index 06f7e4be0..8a1ba8fb3 100644
--- a/include/haproxy/stream-t.h
+++ b/include/haproxy/stream-t.h
@@ -225,6 +225,10 @@ struct strm_logs {
unsigned long t_close; /* total stream duration */
unsigned long srv_queue_pos; /* number of streams de-queued while waiting for a connection slot on this server */
unsigned long prx_queue_pos; /* number of streams de-qeuued while waiting for a connection slot on this instance */
+ long long req_in; /* number of bytes received from the client */
+ long long req_out; /* number of bytes sent to the server */
+ long long res_in; /* number of bytes received from the server */
+ long long res_out; /* number of bytes sent to the client */
long long bytes_in; /* number of bytes transferred from the client to the server */
long long bytes_out; /* number of bytes transferred from the server to the client */
};
diff --git a/src/cli.c b/src/cli.c
index 5a19be559..22a6bf689 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -3488,6 +3488,8 @@ int pcli_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
/* don't count other requests' data */
s->logs.bytes_in -= ci_data(&s->req);
s->logs.bytes_out -= ci_data(&s->res);
+ s->logs.req_in -= ci_data(&s->req);
+ s->logs.res_in -= ci_data(&s->res);
/* we may need to know the position in the queue */
pendconn_free(s);
@@ -3524,6 +3526,8 @@ int pcli_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
s->logs.bytes_in = s->req.total = ci_data(&s->req);
s->logs.bytes_out = s->res.total = ci_data(&s->res);
+ s->logs.req_in = s->scf->bytes_in = ci_data(&s->req);
+ s->logs.res_in = s->scb->bytes_in = ci_data(&s->res);
stream_del_srv_conn(s);
if (objt_server(s->target)) {
diff --git a/src/http_ana.c b/src/http_ana.c
index 532a4860d..6630edec2 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -2002,9 +2002,9 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
*/
if (do_log) {
s->logs.t_close = s->logs.t_data; /* to get a valid end date */
- s->logs.bytes_out = htx->data;
+ s->logs.res_in = s->logs.bytes_out = htx->data;
s->do_log(s, log_orig(LOG_ORIG_TXN_RESPONSE, LOG_ORIG_FL_NONE));
- s->logs.bytes_out = 0;
+ s->logs.res_in = s->logs.bytes_out = 0;
}
done:
diff --git a/src/sample.c b/src/sample.c
index ce9dd9301..c4fc16afc 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -5444,11 +5444,12 @@ static int smp_fetch_bytes(const struct arg *args, struct sample *smp, const cha
if (!logs)
return 0;
- if (kw[6] == 'i') { /* bytes_in */
- smp->data.u.sint = logs->bytes_in;
- } else { /* bytes_out */
- smp->data.u.sint = logs->bytes_out;
- }
+ if (kw[2] == 'q') /* req.in or req.out */
+ smp->data.u.sint = (kw[4] == 'i') ? logs->req_in : logs->req_out;
+ if (kw[2] == 's') /* res.in or res.out */
+ smp->data.u.sint = (kw[4] == 'i') ? logs->res_in : logs->res_out;
+ else /* bytes_in or bytes_out */
+ smp->data.u.sint = (kw[6] == 'i') ? logs->bytes_in : logs->bytes_out;
return 1;
}
@@ -5496,10 +5497,14 @@ static struct sample_fetch_kw_list smp_logs_kws = {ILH, {
{ "fc.timer.handshake", smp_fetch_conn_timers, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI }, /* "Th" */
{ "fc.timer.total", smp_fetch_conn_timers, 0, NULL, SMP_T_SINT, SMP_USE_SSFIN }, /* "Tt" */
+ { "req.in", smp_fetch_bytes, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
+ { "req.out", smp_fetch_bytes, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
{ "req.timer.idle", smp_fetch_reX_timers, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV }, /* "Ti" */
{ "req.timer.tq", smp_fetch_reX_timers, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV }, /* "Tq" */
{ "req.timer.hdr", smp_fetch_reX_timers, 0, NULL, SMP_T_SINT, SMP_USE_HRQHV }, /* "TR" */
{ "req.timer.queue", smp_fetch_reX_timers, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV }, /* "Tw" */
+ { "res.in", smp_fetch_bytes, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
+ { "res.out", smp_fetch_bytes, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },
{ "res.timer.data", smp_fetch_reX_timers, 0, NULL, SMP_T_SINT, SMP_USE_RSFIN }, /* "Td" */
{ "res.timer.hdr", smp_fetch_reX_timers, 0, NULL, SMP_T_SINT, SMP_USE_HRSHV }, /* "Tr" */
{ /* END */ },
diff --git a/src/stream.c b/src/stream.c
index 07b6523ad..11cb96781 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -368,6 +368,8 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer
s->logs.t_connect = -1;
s->logs.t_data = -1;
s->logs.t_close = 0;
+ s->logs.req_in = s->logs.req_out = 0;
+ s->logs.res_in = s->logs.res_out = 0;
s->logs.bytes_in = s->logs.bytes_out = 0;
s->logs.prx_queue_pos = 0; /* we get the number of pending conns before us */
s->logs.srv_queue_pos = 0; /* we will get this number soon */
@@ -864,6 +866,11 @@ void stream_process_counters(struct stream *s)
stkctr_inc_bytes_out_ctr(&sess->stkctr[i], bytes);
}
}
+
+ s->logs.req_in = s->scf->bytes_in;
+ s->logs.req_out = s->scb->bytes_out;
+ s->logs.res_in = s->scb->bytes_in;
+ s->logs.res_out = s->scf->bytes_out;
}
/* Abort processing on the both channels in same time */