};
THREAD_LOCAL void *trash_counters;
+static THREAD_LOCAL struct buffer trash_chunk = BUF_NULL;
+
static inline uint8_t stats_get_domain(uint32_t domain)
{
*/
-/* 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.
*/
{
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
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;
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)
{
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)
{
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)
{
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)
{
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)
{
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,
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"
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>"
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>"
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>"
px->uuid);
}
- chunk_appendf(&trash, "<p>\n");
+ chunk_appendf(&trash_chunk, "<p>\n");
}
/*
struct listener *l;
int current_field;
- chunk_reset(&trash);
+ chunk_reset(&trash_chunk);
more:
current_field = ctx->field;
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;
}
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;
/* 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;
}
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 */
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;
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;
}
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"
);
}
-/* 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)
{
* 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"
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);
}
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",
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" : "",
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"
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."
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."
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>"
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."
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>"
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>"
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>"
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."
(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
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:
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) {
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;
}
stats_dump_html_end();
else
stats_dump_json_end();
- if (!stats_putchk(rep, htx, &trash))
+ if (!stats_putchk(rep, htx, &trash_chunk))
goto full;
}
}
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;
}
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;
*/
static int stats_dump_json_schema_to_buffer(struct appctx *appctx)
{
- chunk_reset(&trash);
- stats_dump_json_schema(&trash);
+ chunk_reset(&trash_chunk);
+
+ stats_dump_json_schema(&trash_chunk);
- if (applet_putchk(appctx, &trash) == -1)
+ if (applet_putchk(appctx, &trash_chunk) == -1)
return 0;
return 1;
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));
}
*/
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);
}