mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MAJOR: stats: Send stats dump over HTTP using zero-copy forwarding
Just like for the cache applet, it is now possible to send response to the opposite side using the zero-copy forwarding. Internal functions were slightly updated but there is nothing special to say. Except the requested size during the nego stage is not exact.
This commit is contained in:
parent
91b77c1632
commit
868205943c
@ -46,7 +46,7 @@ extern THREAD_LOCAL struct field info[];
|
|||||||
extern THREAD_LOCAL struct field *stat_l[];
|
extern THREAD_LOCAL struct field *stat_l[];
|
||||||
|
|
||||||
struct htx;
|
struct htx;
|
||||||
int stats_putchk(struct appctx *appctx, struct htx *htx);
|
int stats_putchk(struct appctx *appctx, struct buffer *buf, struct htx *htx);
|
||||||
|
|
||||||
int stats_dump_one_line(const struct field *stats, size_t stats_count, struct appctx *appctx);
|
int stats_dump_one_line(const struct field *stats, size_t stats_count, struct appctx *appctx);
|
||||||
|
|
||||||
|
@ -2776,7 +2776,7 @@ static int stats_dump_resolv_to_buffer(struct stconn *sc,
|
|||||||
if (!stats_dump_one_line(stats, idx, appctx))
|
if (!stats_dump_one_line(stats, idx, appctx))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!stats_putchk(appctx, NULL))
|
if (!stats_putchk(appctx, NULL, NULL))
|
||||||
goto full;
|
goto full;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
79
src/stats.c
79
src/stats.c
@ -300,7 +300,7 @@ static THREAD_LOCAL struct buffer trash_chunk = BUF_NULL;
|
|||||||
|
|
||||||
static void stats_dump_json_schema(struct buffer *out);
|
static void stats_dump_json_schema(struct buffer *out);
|
||||||
|
|
||||||
int stats_putchk(struct appctx *appctx, struct htx *htx)
|
int stats_putchk(struct appctx *appctx, struct buffer *buf, struct htx *htx)
|
||||||
{
|
{
|
||||||
struct buffer *chk = &trash_chunk;
|
struct buffer *chk = &trash_chunk;
|
||||||
|
|
||||||
@ -315,7 +315,13 @@ int stats_putchk(struct appctx *appctx, struct htx *htx)
|
|||||||
}
|
}
|
||||||
chk->data = 0;
|
chk->data = 0;
|
||||||
}
|
}
|
||||||
else {
|
else if (buf) {
|
||||||
|
if (b_data(chk) > b_room(buf))
|
||||||
|
return 0;
|
||||||
|
b_putblk(buf, b_head(chk), b_data(chk));
|
||||||
|
chk->data = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (applet_putchk(appctx, chk) == -1)
|
if (applet_putchk(appctx, chk) == -1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3138,7 +3144,7 @@ static void stats_dump_html_px_end(struct stconn *sc, struct proxy *px)
|
|||||||
* both by the CLI and the HTTP entry points, and is able to dump the output
|
* both by the CLI and the HTTP entry points, and is able to dump the output
|
||||||
* in HTML or CSV formats.
|
* in HTML or CSV formats.
|
||||||
*/
|
*/
|
||||||
int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
int stats_dump_proxy_to_buffer(struct stconn *sc, struct buffer *buf, struct htx *htx,
|
||||||
struct proxy *px)
|
struct proxy *px)
|
||||||
{
|
{
|
||||||
struct appctx *appctx = __sc_appctx(sc);
|
struct appctx *appctx = __sc_appctx(sc);
|
||||||
@ -3203,7 +3209,7 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
case STAT_PX_ST_TH:
|
case STAT_PX_ST_TH:
|
||||||
if (ctx->flags & STAT_FMT_HTML) {
|
if (ctx->flags & STAT_FMT_HTML) {
|
||||||
stats_dump_html_px_hdr(sc, px);
|
stats_dump_html_px_hdr(sc, px);
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3213,7 +3219,7 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
case STAT_PX_ST_FE:
|
case STAT_PX_ST_FE:
|
||||||
/* print the frontend */
|
/* print the frontend */
|
||||||
if (stats_dump_fe_stats(sc, px)) {
|
if (stats_dump_fe_stats(sc, px)) {
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
ctx->flags |= STAT_STARTED;
|
ctx->flags |= STAT_STARTED;
|
||||||
if (ctx->field)
|
if (ctx->field)
|
||||||
@ -3234,6 +3240,10 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
goto full;
|
goto full;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (buf) {
|
||||||
|
if (buffer_almost_full(buf))
|
||||||
|
goto full;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
struct channel *rep = sc_ic(appctx_sc(appctx));
|
struct channel *rep = sc_ic(appctx_sc(appctx));
|
||||||
|
|
||||||
@ -3257,7 +3267,7 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
|
|
||||||
/* print the frontend */
|
/* print the frontend */
|
||||||
if (stats_dump_li_stats(sc, px, l)) {
|
if (stats_dump_li_stats(sc, px, l)) {
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
ctx->flags |= STAT_STARTED;
|
ctx->flags |= STAT_STARTED;
|
||||||
if (ctx->field)
|
if (ctx->field)
|
||||||
@ -3306,6 +3316,10 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
goto full;
|
goto full;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (buf) {
|
||||||
|
if (buffer_almost_full(buf))
|
||||||
|
goto full;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
struct channel *rep = sc_ic(appctx_sc(appctx));
|
struct channel *rep = sc_ic(appctx_sc(appctx));
|
||||||
|
|
||||||
@ -3346,7 +3360,7 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stats_dump_sv_stats(sc, px, sv)) {
|
if (stats_dump_sv_stats(sc, px, sv)) {
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
ctx->flags |= STAT_STARTED;
|
ctx->flags |= STAT_STARTED;
|
||||||
if (ctx->field)
|
if (ctx->field)
|
||||||
@ -3361,7 +3375,7 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
case STAT_PX_ST_BE:
|
case STAT_PX_ST_BE:
|
||||||
/* print the backend */
|
/* print the backend */
|
||||||
if (stats_dump_be_stats(sc, px)) {
|
if (stats_dump_be_stats(sc, px)) {
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
ctx->flags |= STAT_STARTED;
|
ctx->flags |= STAT_STARTED;
|
||||||
if (ctx->field)
|
if (ctx->field)
|
||||||
@ -3375,7 +3389,7 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
|||||||
case STAT_PX_ST_END:
|
case STAT_PX_ST_END:
|
||||||
if (ctx->flags & STAT_FMT_HTML) {
|
if (ctx->flags & STAT_FMT_HTML) {
|
||||||
stats_dump_html_px_end(sc, px);
|
stats_dump_html_px_end(sc, px);
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3862,7 +3876,7 @@ static void stats_dump_json_end()
|
|||||||
/* Uses <appctx.ctx.stats.obj1> as a pointer to the current proxy and <obj2> as
|
/* Uses <appctx.ctx.stats.obj1> as a pointer to the current proxy and <obj2> as
|
||||||
* a pointer to the current server/listener.
|
* a pointer to the current server/listener.
|
||||||
*/
|
*/
|
||||||
static int stats_dump_proxies(struct stconn *sc,
|
static int stats_dump_proxies(struct stconn *sc, struct buffer *buf,
|
||||||
struct htx *htx)
|
struct htx *htx)
|
||||||
{
|
{
|
||||||
struct appctx *appctx = __sc_appctx(sc);
|
struct appctx *appctx = __sc_appctx(sc);
|
||||||
@ -3877,6 +3891,10 @@ static int stats_dump_proxies(struct stconn *sc,
|
|||||||
goto full;
|
goto full;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (buf) {
|
||||||
|
if (buffer_almost_full(buf))
|
||||||
|
goto full;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
struct channel *rep = sc_ic(appctx_sc(appctx));
|
struct channel *rep = sc_ic(appctx_sc(appctx));
|
||||||
|
|
||||||
@ -3893,7 +3911,7 @@ static int stats_dump_proxies(struct stconn *sc,
|
|||||||
*/
|
*/
|
||||||
if (!(px->flags & PR_FL_DISABLED) && px->uuid > 0 &&
|
if (!(px->flags & PR_FL_DISABLED) && px->uuid > 0 &&
|
||||||
(px->cap & (PR_CAP_FE | PR_CAP_BE)) && !(px->cap & PR_CAP_INT)) {
|
(px->cap & (PR_CAP_FE | PR_CAP_BE)) && !(px->cap & PR_CAP_INT)) {
|
||||||
if (stats_dump_proxy_to_buffer(sc, htx, px) == 0)
|
if (stats_dump_proxy_to_buffer(sc, buf, htx, px) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3914,7 +3932,7 @@ static int stats_dump_proxies(struct stconn *sc,
|
|||||||
* or -1 in case of any error. This function is used by both the CLI and the
|
* or -1 in case of any error. This function is used by both the CLI and the
|
||||||
* HTTP handlers.
|
* HTTP handlers.
|
||||||
*/
|
*/
|
||||||
static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx)
|
static int stats_dump_stat_to_buffer(struct stconn *sc, struct buffer *buf, struct htx *htx)
|
||||||
{
|
{
|
||||||
struct appctx *appctx = __sc_appctx(sc);
|
struct appctx *appctx = __sc_appctx(sc);
|
||||||
struct show_stat_ctx *ctx = appctx->svcctx;
|
struct show_stat_ctx *ctx = appctx->svcctx;
|
||||||
@ -3937,7 +3955,7 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx)
|
|||||||
else if (!(ctx->flags & STAT_FMT_TYPED))
|
else if (!(ctx->flags & STAT_FMT_TYPED))
|
||||||
stats_dump_csv_header(ctx->domain);
|
stats_dump_csv_header(ctx->domain);
|
||||||
|
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
|
|
||||||
if (ctx->flags & STAT_JSON_SCHM) {
|
if (ctx->flags & STAT_JSON_SCHM) {
|
||||||
@ -3950,7 +3968,7 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx)
|
|||||||
case STAT_STATE_INFO:
|
case STAT_STATE_INFO:
|
||||||
if (ctx->flags & STAT_FMT_HTML) {
|
if (ctx->flags & STAT_FMT_HTML) {
|
||||||
stats_dump_html_info(sc);
|
stats_dump_html_info(sc);
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3975,7 +3993,7 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx)
|
|||||||
case STATS_DOMAIN_PROXY:
|
case STATS_DOMAIN_PROXY:
|
||||||
default:
|
default:
|
||||||
/* dump proxies */
|
/* dump proxies */
|
||||||
if (!stats_dump_proxies(sc, htx))
|
if (!stats_dump_proxies(sc, buf, htx))
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3989,7 +4007,7 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx)
|
|||||||
stats_dump_html_end();
|
stats_dump_html_end();
|
||||||
else
|
else
|
||||||
stats_dump_json_end();
|
stats_dump_json_end();
|
||||||
if (!stats_putchk(appctx, htx))
|
if (!stats_putchk(appctx, buf, htx))
|
||||||
goto full;
|
goto full;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4466,6 +4484,20 @@ static int stats_send_http_redirect(struct stconn *sc, struct htx *htx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t http_stats_fastfwd(struct appctx *appctx, struct buffer *buf, size_t count, unsigned int flags)
|
||||||
|
{
|
||||||
|
struct stconn *sc = appctx_sc(appctx);
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
|
ret = b_data(buf);
|
||||||
|
if (stats_dump_stat_to_buffer(sc, buf, NULL)) {
|
||||||
|
se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD);
|
||||||
|
appctx->st0 = STAT_HTTP_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = b_data(buf) - ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* This I/O handler runs as an applet embedded in a stream connector. It is
|
/* This I/O handler runs as an applet embedded in a stream connector. It is
|
||||||
* used to send HTTP stats over a TCP socket. The mechanism is very simple.
|
* used to send HTTP stats over a TCP socket. The mechanism is very simple.
|
||||||
@ -4484,6 +4516,9 @@ static void http_stats_io_handler(struct appctx *appctx)
|
|||||||
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
|
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
||||||
appctx->flags |= APPCTX_FL_OUTBLK_ALLOC;
|
appctx->flags |= APPCTX_FL_OUTBLK_ALLOC;
|
||||||
goto out;
|
goto out;
|
||||||
@ -4503,8 +4538,11 @@ static void http_stats_io_handler(struct appctx *appctx)
|
|||||||
|
|
||||||
if (find_http_meth(istptr(meth), istlen(meth)) == HTTP_METH_HEAD)
|
if (find_http_meth(istptr(meth), istlen(meth)) == HTTP_METH_HEAD)
|
||||||
appctx->st0 = STAT_HTTP_DONE;
|
appctx->st0 = STAT_HTTP_DONE;
|
||||||
else
|
else {
|
||||||
|
if (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD))
|
||||||
|
se_fl_set(appctx->sedesc, SE_FL_MAY_FASTFWD);
|
||||||
appctx->st0 = STAT_HTTP_DUMP;
|
appctx->st0 = STAT_HTTP_DUMP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4514,7 +4552,7 @@ static void http_stats_io_handler(struct appctx *appctx)
|
|||||||
* make sure to perform this call on an empty buffer
|
* make sure to perform this call on an empty buffer
|
||||||
*/
|
*/
|
||||||
trash_chunk.size = buf_room_for_htx_data(&trash_chunk);
|
trash_chunk.size = buf_room_for_htx_data(&trash_chunk);
|
||||||
if (stats_dump_stat_to_buffer(sc, res_htx))
|
if (stats_dump_stat_to_buffer(sc, NULL, res_htx))
|
||||||
appctx->st0 = STAT_HTTP_DONE;
|
appctx->st0 = STAT_HTTP_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4542,6 +4580,7 @@ static void http_stats_io_handler(struct appctx *appctx)
|
|||||||
}
|
}
|
||||||
res_htx->flags |= HTX_FL_EOM;
|
res_htx->flags |= HTX_FL_EOM;
|
||||||
applet_set_eoi(appctx);
|
applet_set_eoi(appctx);
|
||||||
|
se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD);
|
||||||
appctx->st0 = STAT_HTTP_END;
|
appctx->st0 = STAT_HTTP_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4565,6 +4604,7 @@ static void http_stats_io_handler(struct appctx *appctx)
|
|||||||
/* eat the whole request */
|
/* eat the whole request */
|
||||||
b_reset(&appctx->inbuf);
|
b_reset(&appctx->inbuf);
|
||||||
applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL);
|
applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL);
|
||||||
|
appctx->sedesc->iobuf.flags &= ~IOBUF_FL_FF_BLOCKED;
|
||||||
}
|
}
|
||||||
else if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_FULL))
|
else if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_FULL))
|
||||||
applet_wont_consume(appctx);
|
applet_wont_consume(appctx);
|
||||||
@ -5240,7 +5280,7 @@ static int cli_io_handler_dump_info(struct appctx *appctx)
|
|||||||
static int cli_io_handler_dump_stat(struct appctx *appctx)
|
static int cli_io_handler_dump_stat(struct appctx *appctx)
|
||||||
{
|
{
|
||||||
trash_chunk = b_make(trash.area, trash.size, 0, 0);
|
trash_chunk = b_make(trash.area, trash.size, 0, 0);
|
||||||
return stats_dump_stat_to_buffer(appctx_sc(appctx), NULL);
|
return stats_dump_stat_to_buffer(appctx_sc(appctx), NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cli_io_handler_dump_json_schema(struct appctx *appctx)
|
static int cli_io_handler_dump_json_schema(struct appctx *appctx)
|
||||||
@ -5501,6 +5541,7 @@ struct applet http_stats_applet = {
|
|||||||
.fct = http_stats_io_handler,
|
.fct = http_stats_io_handler,
|
||||||
.rcv_buf = appctx_rcv_buf,
|
.rcv_buf = appctx_rcv_buf,
|
||||||
.snd_buf = appctx_snd_buf,
|
.snd_buf = appctx_snd_buf,
|
||||||
|
.fastfwd = http_stats_fastfwd,
|
||||||
.release = NULL,
|
.release = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user