mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-02 02:02:03 +00:00
BUG/MEDIUM: stats: Rely on a local trash buffer to dump the stats
It is possible to block the stats applet if a line exceeds the free space in the responsse buffer while the buffer is empty. It is only an issue in HTTP becaues of the HTX overhead and, AFAIK, only with json output. In this case, the applet is unable to write anything in the response buffer and waits for some free space to proceed further. On the other hand, because the response channel is empty, nothing is sent and thus no space can be freed. At this stage, the stream and the applet are blocked waiting for the other side. To avoid this situation, we must take care to not dump a line exceeding the free space in the HTX message. It means we cannot rely anymore on the global trash buffer. At least, not directly. The trick is to use a local trash buffer, mapped on the global one but with a different size. We use b_make() to do so. The local trash buffer is thread local to avoid any concurrency issue. It is a valid fix. However it could be good to review the internal API of the stats applet to not rely on a global variable. This patch should solve the #1873. It must be backported at least as far as 2.6. Older versions must be evaluated first but it is probably possible to hit this bug with long proxy/server names.
This commit is contained in:
parent
ad4ed003f3
commit
a8b7684319
208
src/stats.c
208
src/stats.c
@ -282,6 +282,8 @@ static struct list stats_module_list[STATS_DOMAIN_COUNT] = {
|
||||
};
|
||||
|
||||
THREAD_LOCAL void *trash_counters;
|
||||
static THREAD_LOCAL struct buffer trash_chunk = BUF_NULL;
|
||||
|
||||
|
||||
static inline uint8_t stats_get_domain(uint32_t domain)
|
||||
{
|
||||
@ -346,8 +348,8 @@ static const char *stats_scope_ptr(struct appctx *appctx, struct stconn *sc)
|
||||
*/
|
||||
|
||||
|
||||
/* Dumps the stats CSV header to the trash buffer which. The caller is responsible
|
||||
* for clearing it if needed.
|
||||
/* Dumps the stats CSV header to the local trash buffer. The caller is
|
||||
* responsible for clearing it if needed.
|
||||
* NOTE: Some tools happen to rely on the field position instead of its name,
|
||||
* so please only append new fields at the end, never in the middle.
|
||||
*/
|
||||
@ -355,19 +357,19 @@ static void stats_dump_csv_header(enum stats_domain domain)
|
||||
{
|
||||
int field;
|
||||
|
||||
chunk_appendf(&trash, "# ");
|
||||
chunk_appendf(&trash_chunk, "# ");
|
||||
if (stat_f[domain]) {
|
||||
for (field = 0; field < stat_count[domain]; ++field) {
|
||||
chunk_appendf(&trash, "%s,", stat_f[domain][field].name);
|
||||
chunk_appendf(&trash_chunk, "%s,", stat_f[domain][field].name);
|
||||
|
||||
/* print special delimiter on proxy stats to mark end of
|
||||
static fields */
|
||||
if (domain == STATS_DOMAIN_PROXY && field + 1 == ST_F_TOTAL_FIELDS)
|
||||
chunk_appendf(&trash, "-,");
|
||||
chunk_appendf(&trash_chunk, "-,");
|
||||
}
|
||||
}
|
||||
|
||||
chunk_appendf(&trash, "\n");
|
||||
chunk_appendf(&trash_chunk, "\n");
|
||||
}
|
||||
|
||||
/* Emits a stats field without any surrounding element and properly encoded to
|
||||
@ -1648,13 +1650,13 @@ int stats_dump_one_line(const struct field *stats, size_t stats_count,
|
||||
int ret;
|
||||
|
||||
if (ctx->flags & STAT_FMT_HTML)
|
||||
ret = stats_dump_fields_html(&trash, stats, ctx);
|
||||
ret = stats_dump_fields_html(&trash_chunk, stats, ctx);
|
||||
else if (ctx->flags & STAT_FMT_TYPED)
|
||||
ret = stats_dump_fields_typed(&trash, stats, stats_count, ctx);
|
||||
ret = stats_dump_fields_typed(&trash_chunk, stats, stats_count, ctx);
|
||||
else if (ctx->flags & STAT_FMT_JSON)
|
||||
ret = stats_dump_fields_json(&trash, stats, stats_count, ctx);
|
||||
ret = stats_dump_fields_json(&trash_chunk, stats, stats_count, ctx);
|
||||
else
|
||||
ret = stats_dump_fields_csv(&trash, stats, stats_count, ctx);
|
||||
ret = stats_dump_fields_csv(&trash_chunk, stats, stats_count, ctx);
|
||||
|
||||
if (ret)
|
||||
ctx->flags |= STAT_STARTED;
|
||||
@ -1842,9 +1844,10 @@ int stats_fill_fe_stats(struct proxy *px, struct field *stats, int len,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dumps a frontend's line to the trash for the current proxy <px> and uses
|
||||
* the state from stream connector <sc>. The caller is responsible for clearing
|
||||
* the trash if needed. Returns non-zero if it emits anything, zero otherwise.
|
||||
/* Dumps a frontend's line to the local trash buffer for the current proxy <px>
|
||||
* and uses the state from stream connector <sc>. The caller is responsible for
|
||||
* clearing the local trash buffer if needed. Returns non-zero if it emits
|
||||
* anything, zero otherwise.
|
||||
*/
|
||||
static int stats_dump_fe_stats(struct stconn *sc, struct proxy *px)
|
||||
{
|
||||
@ -2010,9 +2013,10 @@ int stats_fill_li_stats(struct proxy *px, struct listener *l, int flags,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dumps a line for listener <l> and proxy <px> to the trash and uses the state
|
||||
* from stream connector <sc>. The caller is responsible for clearing the trash
|
||||
* if needed. Returns non-zero if it emits anything, zero otherwise.
|
||||
/* Dumps a line for listener <l> and proxy <px> to the local trash buffer and
|
||||
* uses the state from stream connector <sc>. The caller is responsible for
|
||||
* clearing the local trash buffer if needed. Returns non-zero if it emits
|
||||
* anything, zero otherwise.
|
||||
*/
|
||||
static int stats_dump_li_stats(struct stconn *sc, struct proxy *px, struct listener *l)
|
||||
{
|
||||
@ -2524,10 +2528,10 @@ int stats_fill_sv_stats(struct proxy *px, struct server *sv, int flags,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dumps a line for server <sv> and proxy <px> to the trash and uses the state
|
||||
* from stream connector <sc>, and server state <state>. The caller is
|
||||
* responsible for clearing the trash if needed. Returns non-zero if it emits
|
||||
* anything, zero otherwise.
|
||||
/* Dumps a line for server <sv> and proxy <px> to the local trash vbuffer and
|
||||
* uses the state from stream connector <sc>, and server state <state>. The
|
||||
* caller is responsible for clearing the local trash buffer if needed. Returns
|
||||
* non-zero if it emits anything, zero otherwise.
|
||||
*/
|
||||
static int stats_dump_sv_stats(struct stconn *sc, struct proxy *px, struct server *sv)
|
||||
{
|
||||
@ -2855,9 +2859,10 @@ int stats_fill_be_stats(struct proxy *px, int flags, struct field *stats, int le
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dumps a line for backend <px> to the trash for and uses the state from stream
|
||||
* interface <si>. The caller is responsible for clearing the trash if needed.
|
||||
* Returns non-zero if it emits anything, zero otherwise.
|
||||
/* Dumps a line for backend <px> to the local trash buffer for and uses the
|
||||
* state from stream interface <si>. The caller is responsible for clearing the
|
||||
* local trash buffer if needed. Returns non-zero if it emits anything, zero
|
||||
* otherwise.
|
||||
*/
|
||||
static int stats_dump_be_stats(struct stconn *sc, struct proxy *px)
|
||||
{
|
||||
@ -2897,9 +2902,9 @@ static int stats_dump_be_stats(struct stconn *sc, struct proxy *px)
|
||||
return stats_dump_one_line(stats, stats_count, appctx);
|
||||
}
|
||||
|
||||
/* Dumps the HTML table header for proxy <px> to the trash for and uses the state from
|
||||
* stream connector <sc> and per-uri parameters <uri>. The caller is responsible
|
||||
* for clearing the trash if needed.
|
||||
/* Dumps the HTML table header for proxy <px> to the local trash buffer for and
|
||||
* uses the state from stream connector <sc> and per-uri parameters <uri>. The
|
||||
* caller is responsible for clearing the local trash buffer if needed.
|
||||
*/
|
||||
static void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px)
|
||||
{
|
||||
@ -2922,17 +2927,17 @@ static void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px)
|
||||
scope_txt[strlen(STAT_SCOPE_PATTERN) + ctx->scope_len] = 0;
|
||||
}
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<form method=\"post\">");
|
||||
}
|
||||
|
||||
/* print a new table */
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<table class=\"tbl\" width=\"100%%\">\n"
|
||||
"<tr class=\"titre\">"
|
||||
"<th class=\"pxname\" width=\"10%%\">");
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<a name=\"%s\"></a>%s"
|
||||
"<a class=px href=\"#%s\">%s</a>",
|
||||
px->id,
|
||||
@ -2941,13 +2946,13 @@ static void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px)
|
||||
|
||||
if (ctx->flags & STAT_SHLGNDS) {
|
||||
/* cap, mode, id */
|
||||
chunk_appendf(&trash, "<div class=tips>cap: %s, mode: %s, id: %d",
|
||||
chunk_appendf(&trash_chunk, "<div class=tips>cap: %s, mode: %s, id: %d",
|
||||
proxy_cap_str(px->cap), proxy_mode_str(px->mode),
|
||||
px->uuid);
|
||||
chunk_appendf(&trash, "</div>");
|
||||
chunk_appendf(&trash_chunk, "</div>");
|
||||
}
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"%s</th>"
|
||||
"<th class=\"%s\" width=\"90%%\">%s</th>"
|
||||
"</tr>\n"
|
||||
@ -2960,17 +2965,17 @@ static void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px)
|
||||
if (ctx->flags & STAT_ADMIN) {
|
||||
/* Column heading for Enable or Disable server */
|
||||
if ((px->cap & PR_CAP_BE) && px->srv)
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<th rowspan=2 width=1><input type=\"checkbox\" "
|
||||
"onclick=\"for(c in document.getElementsByClassName('%s-checkbox')) "
|
||||
"document.getElementsByClassName('%s-checkbox').item(c).checked = this.checked\"></th>",
|
||||
px->id,
|
||||
px->id);
|
||||
else
|
||||
chunk_appendf(&trash, "<th rowspan=2></th>");
|
||||
chunk_appendf(&trash_chunk, "<th rowspan=2></th>");
|
||||
}
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<th rowspan=2></th>"
|
||||
"<th colspan=3>Queue</th>"
|
||||
"<th colspan=3>Session rate</th><th colspan=6>Sessions</th>"
|
||||
@ -2983,11 +2988,11 @@ static void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px)
|
||||
list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||
++stats_module_len;
|
||||
}
|
||||
chunk_appendf(&trash, "<th colspan=%d>Extra modules</th>",
|
||||
chunk_appendf(&trash_chunk, "<th colspan=%d>Extra modules</th>",
|
||||
stats_module_len);
|
||||
}
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"</tr>\n"
|
||||
"<tr class=\"titre\">"
|
||||
"<th>Cur</th><th>Max</th><th>Limit</th>"
|
||||
@ -3001,26 +3006,27 @@ static void stats_dump_html_px_hdr(struct stconn *sc, struct proxy *px)
|
||||
|
||||
if (ctx->flags & STAT_SHMODULES) {
|
||||
list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||
chunk_appendf(&trash, "<th>%s</th>", mod->name);
|
||||
chunk_appendf(&trash_chunk, "<th>%s</th>", mod->name);
|
||||
}
|
||||
}
|
||||
|
||||
chunk_appendf(&trash, "</tr>");
|
||||
chunk_appendf(&trash_chunk, "</tr>");
|
||||
}
|
||||
|
||||
/* Dumps the HTML table trailer for proxy <px> to the trash for and uses the state from
|
||||
* stream connector <sc>. The caller is responsible for clearing the trash if needed.
|
||||
/* Dumps the HTML table trailer for proxy <px> to the local trash buffer for and
|
||||
* uses the state from stream connector <sc>. The caller is responsible for
|
||||
* clearing the local trash buffer if needed.
|
||||
*/
|
||||
static void stats_dump_html_px_end(struct stconn *sc, struct proxy *px)
|
||||
{
|
||||
struct appctx *appctx = __sc_appctx(sc);
|
||||
struct show_stat_ctx *ctx = appctx->svcctx;
|
||||
|
||||
chunk_appendf(&trash, "</table>");
|
||||
chunk_appendf(&trash_chunk, "</table>");
|
||||
|
||||
if ((px->cap & PR_CAP_BE) && px->srv && (ctx->flags & STAT_ADMIN)) {
|
||||
/* close the form used to enable/disable this proxy servers */
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"Choose the action to perform on the checked servers : "
|
||||
"<select name=action>"
|
||||
"<option value=\"\"></option>"
|
||||
@ -3044,7 +3050,7 @@ static void stats_dump_html_px_end(struct stconn *sc, struct proxy *px)
|
||||
px->uuid);
|
||||
}
|
||||
|
||||
chunk_appendf(&trash, "<p>\n");
|
||||
chunk_appendf(&trash_chunk, "<p>\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3065,7 +3071,7 @@ int stats_dump_proxy_to_buffer(struct stconn *sc, struct htx *htx,
|
||||
struct listener *l;
|
||||
int current_field;
|
||||
|
||||
chunk_reset(&trash);
|
||||
chunk_reset(&trash_chunk);
|
||||
more:
|
||||
current_field = ctx->field;
|
||||
|
||||
@ -3117,7 +3123,7 @@ more:
|
||||
case STAT_PX_ST_TH:
|
||||
if (ctx->flags & STAT_FMT_HTML) {
|
||||
stats_dump_html_px_hdr(sc, px);
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
}
|
||||
|
||||
@ -3127,7 +3133,7 @@ more:
|
||||
case STAT_PX_ST_FE:
|
||||
/* print the frontend */
|
||||
if (stats_dump_fe_stats(sc, px)) {
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
if (ctx->field)
|
||||
goto more;
|
||||
@ -3164,7 +3170,7 @@ more:
|
||||
|
||||
/* print the frontend */
|
||||
if (stats_dump_li_stats(sc, px, l)) {
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
if (ctx->field)
|
||||
goto more;
|
||||
@ -3229,7 +3235,7 @@ more:
|
||||
}
|
||||
|
||||
if (stats_dump_sv_stats(sc, px, sv)) {
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
}
|
||||
} /* for sv */
|
||||
@ -3240,7 +3246,7 @@ more:
|
||||
case STAT_PX_ST_BE:
|
||||
/* print the backend */
|
||||
if (stats_dump_be_stats(sc, px)) {
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
if (ctx->field)
|
||||
goto more;
|
||||
@ -3253,7 +3259,7 @@ more:
|
||||
case STAT_PX_ST_END:
|
||||
if (ctx->flags & STAT_FMT_HTML) {
|
||||
stats_dump_html_px_end(sc, px);
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
}
|
||||
|
||||
@ -3275,15 +3281,16 @@ more:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dumps the HTTP stats head block to the trash for and uses the per-uri
|
||||
* parameters <uri>. The caller is responsible for clearing the trash if needed.
|
||||
/* Dumps the HTTP stats head block to the local trash buffer for and uses the
|
||||
* per-uri parameters <uri>. The caller is responsible for clearing the local
|
||||
* trash buffer if needed.
|
||||
*/
|
||||
static void stats_dump_html_head(struct appctx *appctx, struct uri_auth *uri)
|
||||
{
|
||||
struct show_stat_ctx *ctx = appctx->svcctx;
|
||||
|
||||
/* WARNING! This must fit in the first buffer !!! */
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n"
|
||||
"\"http://www.w3.org/TR/html4/loose.dtd\">\n"
|
||||
"<html><head><title>Statistics Report for " PRODUCT_NAME "%s%s</title>\n"
|
||||
@ -3443,9 +3450,9 @@ static void stats_dump_html_head(struct appctx *appctx, struct uri_auth *uri)
|
||||
);
|
||||
}
|
||||
|
||||
/* Dumps the HTML stats information block to the trash for and uses the state from
|
||||
* stream connector <sc> and per-uri parameters <uri>. The caller is responsible
|
||||
* for clearing the trash if needed.
|
||||
/* Dumps the HTML stats information block to the local trash buffer for and uses
|
||||
* the state from stream connector <sc> and per-uri parameters <uri>. The caller
|
||||
* is responsible for clearing the local trash buffer if needed.
|
||||
*/
|
||||
static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
{
|
||||
@ -3471,7 +3478,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
* We are around 3.5 kB, add adding entries will
|
||||
* become tricky if we want to support 4kB buffers !
|
||||
*/
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
|
||||
PRODUCT_NAME "%s</a></h1>\n"
|
||||
"<h2>Statistics Report for pid %d%s%s%s%s</h2>\n"
|
||||
@ -3529,7 +3536,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
memcpy(scope_txt, scope_ptr, ctx->scope_len);
|
||||
scope_txt[ctx->scope_len] = '\0';
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><form method=\"GET\">Scope : <input value=\"%s\" name=\"" STAT_SCOPE_INPUT_NAME "\" size=\"8\" maxlength=\"%d\" tabindex=\"1\"/></form>\n",
|
||||
(ctx->scope_len > 0) ? scope_txt : "",
|
||||
STAT_SCOPE_TXT_MAXLEN);
|
||||
@ -3543,14 +3550,14 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
}
|
||||
|
||||
if (ctx->flags & STAT_HIDE_DOWN)
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><a href=\"%s%s%s%s\">Show all servers</a><br>\n",
|
||||
uri->uri_prefix,
|
||||
"",
|
||||
(ctx->flags & STAT_NO_REFRESH) ? ";norefresh" : "",
|
||||
scope_txt);
|
||||
else
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><a href=\"%s%s%s%s\">Hide 'DOWN' servers</a><br>\n",
|
||||
uri->uri_prefix,
|
||||
";up",
|
||||
@ -3559,14 +3566,14 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
|
||||
if (uri->refresh > 0) {
|
||||
if (ctx->flags & STAT_NO_REFRESH)
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><a href=\"%s%s%s%s\">Enable refresh</a><br>\n",
|
||||
uri->uri_prefix,
|
||||
(ctx->flags & STAT_HIDE_DOWN) ? ";up" : "",
|
||||
"",
|
||||
scope_txt);
|
||||
else
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><a href=\"%s%s%s%s\">Disable refresh</a><br>\n",
|
||||
uri->uri_prefix,
|
||||
(ctx->flags & STAT_HIDE_DOWN) ? ";up" : "",
|
||||
@ -3574,26 +3581,26 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
}
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><a href=\"%s%s%s%s\">Refresh now</a><br>\n",
|
||||
uri->uri_prefix,
|
||||
(ctx->flags & STAT_HIDE_DOWN) ? ";up" : "",
|
||||
(ctx->flags & STAT_NO_REFRESH) ? ";norefresh" : "",
|
||||
scope_txt);
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><a href=\"%s;csv%s%s\">CSV export</a><br>\n",
|
||||
uri->uri_prefix,
|
||||
(uri->refresh > 0) ? ";norefresh" : "",
|
||||
scope_txt);
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<li><a href=\"%s;json%s%s\">JSON export</a> (<a href=\"%s;json-schema\">schema</a>)<br>\n",
|
||||
uri->uri_prefix,
|
||||
(uri->refresh > 0) ? ";norefresh" : "",
|
||||
scope_txt, uri->uri_prefix);
|
||||
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"</ul></td>"
|
||||
"<td align=\"left\" valign=\"top\" nowrap width=\"1%%\">"
|
||||
"<b>External resources:</b><ul style=\"margin-top: 0.25em;\">\n"
|
||||
@ -3609,7 +3616,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
if (ctx->st_code) {
|
||||
switch (ctx->st_code) {
|
||||
case STAT_STATUS_DONE:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_up>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"Action processed successfully."
|
||||
@ -3619,7 +3626,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
break;
|
||||
case STAT_STATUS_NONE:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_going_down>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"Nothing has changed."
|
||||
@ -3629,7 +3636,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
break;
|
||||
case STAT_STATUS_PART:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_going_down>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"Action partially processed.<br>"
|
||||
@ -3640,7 +3647,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
break;
|
||||
case STAT_STATUS_ERRP:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_down>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"Action not processed because of invalid parameters."
|
||||
@ -3656,7 +3663,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
break;
|
||||
case STAT_STATUS_EXCD:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_down>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"<b>Action not processed : the buffer couldn't store all the data.<br>"
|
||||
@ -3667,7 +3674,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
break;
|
||||
case STAT_STATUS_DENY:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_down>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"<b>Action denied.</b>"
|
||||
@ -3677,7 +3684,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
break;
|
||||
case STAT_STATUS_IVAL:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_down>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"<b>Invalid requests (unsupported method or chunked encoded request).</b>"
|
||||
@ -3687,7 +3694,7 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
scope_txt);
|
||||
break;
|
||||
default:
|
||||
chunk_appendf(&trash,
|
||||
chunk_appendf(&trash_chunk,
|
||||
"<p><div class=active_no_check>"
|
||||
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
|
||||
"Unexpected result."
|
||||
@ -3696,33 +3703,33 @@ static void stats_dump_html_info(struct stconn *sc, struct uri_auth *uri)
|
||||
(ctx->flags & STAT_NO_REFRESH) ? ";norefresh" : "",
|
||||
scope_txt);
|
||||
}
|
||||
chunk_appendf(&trash, "<p>\n");
|
||||
chunk_appendf(&trash_chunk, "<p>\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Dumps the HTML stats trailer block to the trash. The caller is responsible
|
||||
* for clearing the trash if needed.
|
||||
/* Dumps the HTML stats trailer block to the local trash buffer. The caller is
|
||||
* responsible for clearing the local trash buffer if needed.
|
||||
*/
|
||||
static void stats_dump_html_end()
|
||||
{
|
||||
chunk_appendf(&trash, "</body></html>\n");
|
||||
chunk_appendf(&trash_chunk, "</body></html>\n");
|
||||
}
|
||||
|
||||
/* Dumps the stats JSON header to the trash buffer which. The caller is responsible
|
||||
* for clearing it if needed.
|
||||
/* Dumps the stats JSON header to the local trash buffer buffer which. The
|
||||
* caller is responsible for clearing it if needed.
|
||||
*/
|
||||
static void stats_dump_json_header()
|
||||
{
|
||||
chunk_strcat(&trash, "[");
|
||||
chunk_strcat(&trash_chunk, "[");
|
||||
}
|
||||
|
||||
|
||||
/* Dumps the JSON stats trailer block to the trash. The caller is responsible
|
||||
* for clearing the trash if needed.
|
||||
/* Dumps the JSON stats trailer block to the local trash buffer. The caller is
|
||||
* responsible for clearing the local trash buffer if needed.
|
||||
*/
|
||||
static void stats_dump_json_end()
|
||||
{
|
||||
chunk_strcat(&trash, "]\n");
|
||||
chunk_strcat(&trash_chunk, "]\n");
|
||||
}
|
||||
|
||||
/* Uses <appctx.ctx.stats.obj1> as a pointer to the current proxy and <obj2> as
|
||||
@ -3786,7 +3793,7 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx,
|
||||
struct channel *rep = sc_ic(sc);
|
||||
enum stats_domain domain = ctx->domain;
|
||||
|
||||
chunk_reset(&trash);
|
||||
chunk_reset(&trash_chunk);
|
||||
|
||||
switch (ctx->state) {
|
||||
case STAT_STATE_INIT:
|
||||
@ -3797,13 +3804,13 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx,
|
||||
if (ctx->flags & STAT_FMT_HTML)
|
||||
stats_dump_html_head(appctx, uri);
|
||||
else if (ctx->flags & STAT_JSON_SCHM)
|
||||
stats_dump_json_schema(&trash);
|
||||
stats_dump_json_schema(&trash_chunk);
|
||||
else if (ctx->flags & STAT_FMT_JSON)
|
||||
stats_dump_json_header();
|
||||
else if (!(ctx->flags & STAT_FMT_TYPED))
|
||||
stats_dump_csv_header(ctx->domain);
|
||||
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
|
||||
if (ctx->flags & STAT_JSON_SCHM) {
|
||||
@ -3816,7 +3823,7 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx,
|
||||
case STAT_STATE_INFO:
|
||||
if (ctx->flags & STAT_FMT_HTML) {
|
||||
stats_dump_html_info(sc, uri);
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
}
|
||||
|
||||
@ -3855,7 +3862,7 @@ static int stats_dump_stat_to_buffer(struct stconn *sc, struct htx *htx,
|
||||
stats_dump_html_end();
|
||||
else
|
||||
stats_dump_json_end();
|
||||
if (!stats_putchk(rep, htx, &trash))
|
||||
if (!stats_putchk(rep, htx, &trash_chunk))
|
||||
goto full;
|
||||
}
|
||||
|
||||
@ -4375,6 +4382,7 @@ static void http_stats_io_handler(struct appctx *appctx)
|
||||
}
|
||||
|
||||
if (appctx->st0 == STAT_HTTP_DUMP) {
|
||||
trash_chunk = b_make(trash.area, channel_htx_recv_limit(res, res_htx), 0, 0);
|
||||
if (stats_dump_stat_to_buffer(sc, res_htx, s->be->uri_auth))
|
||||
appctx->st0 = STAT_HTTP_DONE;
|
||||
}
|
||||
@ -4619,18 +4627,18 @@ static int stats_dump_info_to_buffer(struct stconn *sc)
|
||||
if (!stats_fill_info(info, INF_TOTAL_FIELDS, ctx->flags))
|
||||
return 0;
|
||||
|
||||
chunk_reset(&trash);
|
||||
chunk_reset(&trash_chunk);
|
||||
more:
|
||||
current_field = ctx->field;
|
||||
|
||||
if (ctx->flags & STAT_FMT_TYPED)
|
||||
ret = stats_dump_typed_info_fields(&trash, info, ctx);
|
||||
ret = stats_dump_typed_info_fields(&trash_chunk, info, ctx);
|
||||
else if (ctx->flags & STAT_FMT_JSON)
|
||||
ret = stats_dump_json_info_fields(&trash, info, ctx);
|
||||
ret = stats_dump_json_info_fields(&trash_chunk, info, ctx);
|
||||
else
|
||||
ret = stats_dump_info_fields(&trash, info, ctx);
|
||||
ret = stats_dump_info_fields(&trash_chunk, info, ctx);
|
||||
|
||||
if (applet_putchk(appctx, &trash) == -1) {
|
||||
if (applet_putchk(appctx, &trash_chunk) == -1) {
|
||||
/* restore previous field */
|
||||
ctx->field = current_field;
|
||||
return 0;
|
||||
@ -4860,11 +4868,12 @@ static void stats_dump_json_schema(struct buffer *out)
|
||||
*/
|
||||
static int stats_dump_json_schema_to_buffer(struct appctx *appctx)
|
||||
{
|
||||
chunk_reset(&trash);
|
||||
|
||||
stats_dump_json_schema(&trash);
|
||||
chunk_reset(&trash_chunk);
|
||||
|
||||
if (applet_putchk(appctx, &trash) == -1)
|
||||
stats_dump_json_schema(&trash_chunk);
|
||||
|
||||
if (applet_putchk(appctx, &trash_chunk) == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@ -5074,6 +5083,7 @@ static int cli_parse_show_stat(char **args, char *payload, struct appctx *appctx
|
||||
|
||||
static int cli_io_handler_dump_info(struct appctx *appctx)
|
||||
{
|
||||
trash_chunk = b_make(trash.area, trash.size, 0, 0);
|
||||
return stats_dump_info_to_buffer(appctx_sc(appctx));
|
||||
}
|
||||
|
||||
@ -5082,11 +5092,13 @@ static int cli_io_handler_dump_info(struct appctx *appctx)
|
||||
*/
|
||||
static int cli_io_handler_dump_stat(struct appctx *appctx)
|
||||
{
|
||||
trash_chunk = b_make(trash.area, trash.size, 0, 0);
|
||||
return stats_dump_stat_to_buffer(appctx_sc(appctx), NULL, NULL);
|
||||
}
|
||||
|
||||
static int cli_io_handler_dump_json_schema(struct appctx *appctx)
|
||||
{
|
||||
trash_chunk = b_make(trash.area, trash.size, 0, 0);
|
||||
return stats_dump_json_schema_to_buffer(appctx);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user