REORG: stats: dump the server stats via the generic function
The code was simply moved as-is to the new function. There's no
functional change.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 00c9bfe..83cd86a 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -3254,6 +3254,8 @@
*/
static int stats_dump_fields_html(const struct field *stats, int admin, unsigned int flags, struct proxy *px)
{
+ struct chunk src;
+
if (stats[ST_F_TYPE].u.u32 == STATS_TYPE_FE) {
chunk_appendf(&trash,
/* name, queue */
@@ -3453,155 +3455,431 @@
U2H(stats[ST_F_EREQ].u.u64),
field_str(stats, ST_F_STATUS));
}
- return 1;
-}
+ else if (stats[ST_F_TYPE].u.u32 == STATS_TYPE_SV) {
+ const char *style;
-/* Dumps a frontend's line to the trash for the current proxy <px> 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.
- */
-static int stats_dump_fe_stats(struct stream_interface *si, struct proxy *px)
-{
- struct appctx *appctx = __objt_appctx(si->end);
+ /* determine the style to use depending on the server's state,
+ * its health and weight. There isn't a 1-to-1 mapping between
+ * state and styles for the cases where the server is (still)
+ * up. The reason is that we don't want to report nolb and
+ * drain with the same color.
+ */
- if (!(px->cap & PR_CAP_FE))
- return 0;
+ if (strcmp(field_str(stats, ST_F_STATUS), "DOWN") == 0 ||
+ strcmp(field_str(stats, ST_F_STATUS), "DOWN (agent)") == 0) {
+ style = "down";
+ }
+ else if (strcmp(field_str(stats, ST_F_STATUS), "DOWN ") == 0) {
+ style = "going_up";
+ }
+ else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB ") == 0) {
+ style = "going_down";
+ }
+ else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB") == 0) {
+ style = "nolb";
+ }
+ else if (strcmp(field_str(stats, ST_F_STATUS), "no check") == 0) {
+ style = "no_check";
+ }
+ else if (!stats[ST_F_CHKFAIL].type ||
+ stats[ST_F_CHECK_HEALTH].u.u32 == stats[ST_F_CHECK_RISE].u.u32 + stats[ST_F_CHECK_FALL].u.u32 - 1) {
+ /* no check or max health = UP */
+ if (stats[ST_F_WEIGHT].u.u32)
+ style = "up";
+ else
+ style = "draining";
+ }
+ else {
+ style = "going_down";
+ }
- if ((appctx->ctx.stats.flags & STAT_BOUND) && !(appctx->ctx.stats.type & (1 << STATS_TYPE_FE)))
- return 0;
+ if (memcmp(field_str(stats, ST_F_STATUS), "MAINT", 5) == 0)
+ chunk_appendf(&trash, "<tr class=\"maintain\">");
+ else
+ chunk_appendf(&trash,
+ "<tr class=\"%s_%s\">",
+ (stats[ST_F_BCK].u.u32) ? "backup" : "active", style);
- memset(&stats, 0, sizeof(stats));
- stats[ST_F_PXNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, px->id);
- stats[ST_F_SVNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, "FRONTEND");
- stats[ST_F_SCUR] = mkf_u32(0, px->feconn);
- stats[ST_F_SMAX] = mkf_u32(FN_MAX, px->fe_counters.conn_max);
- stats[ST_F_SLIM] = mkf_u32(FO_CONFIG|FN_LIMIT, px->maxconn);
- stats[ST_F_STOT] = mkf_u64(FN_COUNTER, px->fe_counters.cum_sess);
- stats[ST_F_BIN] = mkf_u64(FN_COUNTER, px->fe_counters.bytes_in);
- stats[ST_F_BOUT] = mkf_u64(FN_COUNTER, px->fe_counters.bytes_out);
- stats[ST_F_DREQ] = mkf_u64(FN_COUNTER, px->fe_counters.denied_req);
- stats[ST_F_DRESP] = mkf_u64(FN_COUNTER, px->fe_counters.denied_resp);
- stats[ST_F_EREQ] = mkf_u64(FN_COUNTER, px->fe_counters.failed_req);
- stats[ST_F_STATUS] = mkf_str(FO_STATUS, px->state == PR_STREADY ? "OPEN" : px->state == PR_STFULL ? "FULL" : "STOP");
- stats[ST_F_PID] = mkf_u32(FO_KEY, relative_pid);
- stats[ST_F_IID] = mkf_u32(FO_KEY|FS_SERVICE, px->uuid);
- stats[ST_F_SID] = mkf_u32(FO_KEY|FS_SERVICE, 0);
- stats[ST_F_TYPE] = mkf_u32(FO_CONFIG|FS_SERVICE, STATS_TYPE_FE);
- stats[ST_F_RATE] = mkf_u32(FN_RATE, read_freq_ctr(&px->fe_sess_per_sec));
- stats[ST_F_RATE_LIM] = mkf_u32(FO_CONFIG|FN_LIMIT, px->fe_sps_lim);
- stats[ST_F_RATE_MAX] = mkf_u32(FN_MAX, px->fe_counters.sps_max);
+ if (admin)
+ chunk_appendf(&trash,
+ "<td><input type=\"checkbox\" name=\"s\" value=\"%s\"></td>",
+ field_str(stats, ST_F_SVNAME));
- /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
- if (px->mode == PR_MODE_HTTP) {
- stats[ST_F_HRSP_1XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[1]);
- stats[ST_F_HRSP_2XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[2]);
- stats[ST_F_HRSP_3XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[3]);
- stats[ST_F_HRSP_4XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[4]);
- stats[ST_F_HRSP_5XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[5]);
- stats[ST_F_HRSP_OTHER] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[0]);
- }
+ chunk_appendf(&trash,
+ "<td class=ac><a name=\"%s/%s\"></a>%s"
+ "<a class=lfsb href=\"#%s/%s\">%s</a>"
+ "",
+ field_str(stats, ST_F_PXNAME), field_str(stats, ST_F_SVNAME),
+ (flags & ST_SHLGNDS) ? "<u>" : "",
+ field_str(stats, ST_F_PXNAME), field_str(stats, ST_F_SVNAME), field_str(stats, ST_F_SVNAME));
- /* requests : req_rate, req_rate_max, req_tot, */
- stats[ST_F_REQ_RATE] = mkf_u32(FN_RATE, read_freq_ctr(&px->fe_req_per_sec));
- stats[ST_F_REQ_RATE_MAX] = mkf_u32(FN_MAX, px->fe_counters.p.http.rps_max);
- stats[ST_F_REQ_TOT] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.cum_req);
+ if (flags & ST_SHLGNDS) {
+ chunk_appendf(&trash, "<div class=tips>");
- /* compression: in, out, bypassed, responses */
- stats[ST_F_COMP_IN] = mkf_u64(FN_COUNTER, px->fe_counters.comp_in);
- stats[ST_F_COMP_OUT] = mkf_u64(FN_COUNTER, px->fe_counters.comp_out);
- stats[ST_F_COMP_BYP] = mkf_u64(FN_COUNTER, px->fe_counters.comp_byp);
- stats[ST_F_COMP_RSP] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.comp_rsp);
+ if (isdigit(*field_str(stats, ST_F_ADDR)))
+ chunk_appendf(&trash, "IPv4: %s, ", field_str(stats, ST_F_ADDR));
+ else if (*field_str(stats, ST_F_ADDR) == '[')
+ chunk_appendf(&trash, "IPv6: %s, ", field_str(stats, ST_F_ADDR));
+ else if (*field_str(stats, ST_F_ADDR))
+ chunk_appendf(&trash, "%s, ", field_str(stats, ST_F_ADDR));
- if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
- int admin;
+ /* id */
+ chunk_appendf(&trash, "id: %d", stats[ST_F_SID].u.u32);
- admin = (px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN);
- stats_dump_fields_html(stats, admin, 0, px);
- }
- else { /* CSV mode */
- /* dump everything */
- stats_dump_fields_csv(&trash, stats);
- }
- return 1;
-}
+ /* cookie */
+ if (stats[ST_F_COOKIE].type) {
+ chunk_appendf(&trash, ", cookie: '");
+ chunk_initstr(&src, field_str(stats, ST_F_COOKIE));
+ chunk_htmlencode(&trash, &src);
+ chunk_appendf(&trash, "'");
+ }
-/* Dumps a line for listener <l> and proxy <px> to the trash and uses the state
- * from stream interface <si>, and stats flags <flags>. The caller is responsible
- * for clearing the trash if needed. Returns non-zero if it emits anything, zero
- * otherwise.
- */
-static int stats_dump_li_stats(struct stream_interface *si, struct proxy *px, struct listener *l, int flags)
-{
- struct appctx *appctx = __objt_appctx(si->end);
- struct chunk *out = get_trash_chunk();
+ chunk_appendf(&trash, "</div>");
+ }
- chunk_reset(out);
- memset(&stats, 0, sizeof(stats));
+ chunk_appendf(&trash,
+ /* queue : current, max, limit */
+ "%s</td><td>%s</td><td>%s</td><td>%s</td>"
+ /* sessions rate : current, max, limit */
+ "<td>%s</td><td>%s</td><td></td>"
+ "",
+ (flags & ST_SHLGNDS) ? "</u>" : "",
+ U2H(stats[ST_F_QCUR].u.u32), U2H(stats[ST_F_QMAX].u.u32), LIM2A(stats[ST_F_QLIMIT].u.u32, "-"),
+ U2H(stats[ST_F_RATE].u.u32), U2H(stats[ST_F_RATE_MAX].u.u32));
- stats[ST_F_PXNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, px->id);
- stats[ST_F_SVNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, l->name);
- stats[ST_F_SCUR] = mkf_u32(0, l->nbconn);
- stats[ST_F_SMAX] = mkf_u32(FN_MAX, l->counters->conn_max);
- stats[ST_F_SLIM] = mkf_u32(FO_CONFIG|FN_LIMIT, l->maxconn);
- stats[ST_F_STOT] = mkf_u64(FN_COUNTER, l->counters->cum_conn);
- stats[ST_F_BIN] = mkf_u64(FN_COUNTER, l->counters->bytes_in);
- stats[ST_F_BOUT] = mkf_u64(FN_COUNTER, l->counters->bytes_out);
- stats[ST_F_DREQ] = mkf_u64(FN_COUNTER, l->counters->denied_req);
- stats[ST_F_DRESP] = mkf_u64(FN_COUNTER, l->counters->denied_resp);
- stats[ST_F_EREQ] = mkf_u64(FN_COUNTER, l->counters->failed_req);
- stats[ST_F_STATUS] = mkf_str(FO_STATUS, (l->nbconn < l->maxconn) ? (l->state == LI_LIMITED) ? "WAITING" : "OPEN" : "FULL");
- stats[ST_F_PID] = mkf_u32(FO_KEY, relative_pid);
- stats[ST_F_IID] = mkf_u32(FO_KEY|FS_SERVICE, px->uuid);
- stats[ST_F_SID] = mkf_u32(FO_KEY|FS_SERVICE, l->luid);
- stats[ST_F_TYPE] = mkf_u32(FO_CONFIG|FS_SERVICE, STATS_TYPE_SO);
+ chunk_appendf(&trash,
+ /* sessions: current, max, limit, total */
+ "<td>%s</td><td>%s</td><td>%s</td>"
+ "<td><u>%s<div class=tips><table class=det>"
+ "<tr><th>Cum. sessions:</th><td>%s</td></tr>"
+ "",
+ U2H(stats[ST_F_SCUR].u.u32), U2H(stats[ST_F_SMAX].u.u32), LIM2A(stats[ST_F_SLIM].u.u32, "-"),
+ U2H(stats[ST_F_STOT].u.u64),
+ U2H(stats[ST_F_STOT].u.u64));
- if (flags & ST_SHLGNDS) {
- char str[INET6_ADDRSTRLEN];
- int port;
+ /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
+ if (px->mode == PR_MODE_HTTP) {
+ unsigned long long tot;
- port = get_host_port(&l->addr);
- switch (addr_to_str(&l->addr, str, sizeof(str))) {
- case AF_INET:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
- chunk_appendf(out, "%s:%d", str, port);
- break;
- case AF_INET6:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
- chunk_appendf(out, "[%s]:%d", str, port);
- break;
- case AF_UNIX:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, "unix");
- break;
- case -1:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
- chunk_strcat(out, strerror(errno));
- break;
- default: /* address family not supported */
- break;
+ tot = stats[ST_F_HRSP_OTHER].u.u64;
+ tot += stats[ST_F_HRSP_1XX].u.u64;
+ tot += stats[ST_F_HRSP_2XX].u.u64;
+ tot += stats[ST_F_HRSP_3XX].u.u64;
+ tot += stats[ST_F_HRSP_4XX].u.u64;
+ tot += stats[ST_F_HRSP_5XX].u.u64;
+
+ chunk_appendf(&trash,
+ "<tr><th>Cum. HTTP responses:</th><td>%s</td></tr>"
+ "<tr><th>- HTTP 1xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
+ "<tr><th>- HTTP 2xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
+ "<tr><th>- HTTP 3xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
+ "<tr><th>- HTTP 4xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
+ "<tr><th>- HTTP 5xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
+ "<tr><th>- other responses:</th><td>%s</td><td>(%d%%)</td></tr>"
+ "",
+ U2H(tot),
+ U2H(stats[ST_F_HRSP_1XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_1XX].u.u64 / tot) : 0,
+ U2H(stats[ST_F_HRSP_2XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_2XX].u.u64 / tot) : 0,
+ U2H(stats[ST_F_HRSP_3XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_3XX].u.u64 / tot) : 0,
+ U2H(stats[ST_F_HRSP_4XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_4XX].u.u64 / tot) : 0,
+ U2H(stats[ST_F_HRSP_5XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_5XX].u.u64 / tot) : 0,
+ U2H(stats[ST_F_HRSP_OTHER].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_OTHER].u.u64 / tot) : 0);
}
- }
- if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
- int admin;
+ chunk_appendf(&trash, "<tr><th colspan=3>Avg over last 1024 success. conn.</th></tr>");
+ chunk_appendf(&trash, "<tr><th>- Queue time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_QTIME].u.u32));
+ chunk_appendf(&trash, "<tr><th>- Connect time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_CTIME].u.u32));
+ if (px->mode == PR_MODE_HTTP)
+ chunk_appendf(&trash, "<tr><th>- Response time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_RTIME].u.u32));
+ chunk_appendf(&trash, "<tr><th>- Total time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_TTIME].u.u32));
- admin = (px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN);
- stats_dump_fields_html(stats, admin, flags, px);
- }
- else { /* CSV mode */
- /* dump everything */
- stats_dump_fields_csv(&trash, stats);
- }
- return 1;
-}
+ chunk_appendf(&trash,
+ "</table></div></u></td>"
+ /* sessions: lbtot, last */
+ "<td>%s</td><td>%s</td>",
+ U2H(stats[ST_F_LBTOT].u.u64),
+ human_time(stats[ST_F_LASTSESS].u.s32, 1));
-enum srv_stats_state {
- SRV_STATS_STATE_DOWN = 0,
- SRV_STATS_STATE_DOWN_AGENT,
- SRV_STATS_STATE_GOING_UP,
- SRV_STATS_STATE_UP_GOING_DOWN,
- SRV_STATS_STATE_UP,
- SRV_STATS_STATE_NOLB_GOING_DOWN,
+ chunk_appendf(&trash,
+ /* bytes : in, out */
+ "<td>%s</td><td>%s</td>"
+ /* denied: req, resp */
+ "<td></td><td>%s</td>"
+ /* errors : request, connect */
+ "<td></td><td>%s</td>"
+ /* errors : response */
+ "<td><u>%s<div class=tips>Connection resets during transfers: %lld client, %lld server</div></u></td>"
+ /* warnings: retries, redispatches */
+ "<td>%lld</td><td>%lld</td>"
+ "",
+ U2H(stats[ST_F_BIN].u.u64), U2H(stats[ST_F_BOUT].u.u64),
+ U2H(stats[ST_F_DRESP].u.u64),
+ U2H(stats[ST_F_ECON].u.u64),
+ U2H(stats[ST_F_ERESP].u.u64),
+ (long long)stats[ST_F_CLI_ABRT].u.u64,
+ (long long)stats[ST_F_SRV_ABRT].u.u64,
+ (long long)stats[ST_F_WRETR].u.u64,
+ (long long)stats[ST_F_WREDIS].u.u64);
+
+ /* status, last change */
+ chunk_appendf(&trash, "<td class=ac>");
+
+ /* FIXME!!!!
+ * LASTCHG should contain the last change for *this* server and must be computed
+ * properly above, as was done below, ie: this server if maint, otherwise ref server
+ * if tracking. Note that ref is either local or remote depending on tracking.
+ */
+
+
+ if (memcmp(field_str(stats, ST_F_STATUS), "MAINT", 5) == 0) {
+ chunk_appendf(&trash, "%s MAINT", human_time(stats[ST_F_LASTCHG].u.u32, 1));
+ }
+ else if (memcmp(field_str(stats, ST_F_STATUS), "no check", 5) == 0) {
+ chunk_strcat(&trash, "<i>no check</i>");
+ }
+ else {
+ chunk_appendf(&trash, "%s %s", human_time(stats[ST_F_LASTCHG].u.u32, 1), field_str(stats, ST_F_STATUS));
+ if (memcmp(field_str(stats, ST_F_STATUS), "DOWN", 4) == 0) {
+ if (stats[ST_F_CHECK_HEALTH].u.u32)
+ chunk_strcat(&trash, " ↑");
+ }
+ else if (stats[ST_F_CHECK_HEALTH].u.u32 < stats[ST_F_CHECK_RISE].u.u32 + stats[ST_F_CHECK_FALL].u.u32 - 1)
+ chunk_strcat(&trash, " ↓");
+ }
+
+ if (memcmp(field_str(stats, ST_F_STATUS), "DOWN", 4) == 0 &&
+ stats[ST_F_AGENT_STATUS].type && !stats[ST_F_AGENT_HEALTH].u.u32) {
+ chunk_appendf(&trash,
+ "</td><td class=ac><u> %s",
+ field_str(stats, ST_F_AGENT_STATUS));
+
+ if (stats[ST_F_AGENT_CODE].type)
+ chunk_appendf(&trash, "/%d", stats[ST_F_AGENT_CODE].u.u32);
+
+ if (stats[ST_F_AGENT_DURATION].type && stats[ST_F_AGENT_DURATION].u.u64 >= 0)
+ chunk_appendf(&trash, " in %lums", (long)stats[ST_F_AGENT_DURATION].u.u64);
+
+ chunk_appendf(&trash, "<div class=tips>%s", field_str(stats, ST_F_AGENT_DESC));
+
+ if (*field_str(stats, ST_F_LAST_AGT)) {
+ chunk_appendf(&trash, ": ");
+ chunk_initstr(&src, field_str(stats, ST_F_LAST_AGT));
+ chunk_htmlencode(&trash, &src);
+ }
+ chunk_appendf(&trash, "</div></u>");
+ }
+ else if (stats[ST_F_CHECK_STATUS].type) {
+ chunk_appendf(&trash,
+ "</td><td class=ac><u> %s",
+ field_str(stats, ST_F_CHECK_STATUS));
+
+ if (stats[ST_F_CHECK_CODE].type)
+ chunk_appendf(&trash, "/%d", stats[ST_F_CHECK_CODE].u.u32);
+
+ if (stats[ST_F_CHECK_DURATION].type && stats[ST_F_CHECK_DURATION].u.u64 >= 0)
+ chunk_appendf(&trash, " in %lums", (long)stats[ST_F_CHECK_DURATION].u.u64);
+
+ chunk_appendf(&trash, "<div class=tips>%s", field_str(stats, ST_F_CHECK_DESC));
+
+ if (*field_str(stats, ST_F_LAST_CHK)) {
+ chunk_appendf(&trash, ": ");
+ chunk_initstr(&src, field_str(stats, ST_F_LAST_CHK));
+ chunk_htmlencode(&trash, &src);
+ }
+ chunk_appendf(&trash, "</div></u>");
+ }
+ else
+ chunk_appendf(&trash, "</td><td>");
+
+ chunk_appendf(&trash,
+ /* weight */
+ "</td><td class=ac>%d</td>"
+ /* act, bck */
+ "<td class=ac>%s</td><td class=ac>%s</td>"
+ "",
+ stats[ST_F_WEIGHT].u.u32,
+ stats[ST_F_BCK].u.u32 ? "-" : "Y",
+ stats[ST_F_BCK].u.u32 ? "Y" : "-");
+
+ /* check failures: unique, fatal, down time */
+ if (stats[ST_F_CHKFAIL].type) {
+ chunk_appendf(&trash, "<td><u>%lld", (long long)stats[ST_F_CHKFAIL].u.u64);
+
+ if (stats[ST_F_HANAFAIL].type)
+ chunk_appendf(&trash, "/%lld", (long long)stats[ST_F_HANAFAIL].u.u64);
+
+ chunk_appendf(&trash,
+ "<div class=tips>Failed Health Checks%s</div></u></td>"
+ "<td>%lld</td><td>%s</td>"
+ "",
+ stats[ST_F_HANAFAIL].type ? "/Health Analyses" : "",
+ (long long)stats[ST_F_CHKDOWN].u.u64, human_time(stats[ST_F_DOWNTIME].u.u32, 1));
+ }
+ else if (strcmp(field_str(stats, ST_F_STATUS), "MAINT") != 0 && field_format(stats, ST_F_TRACKED) == FF_STR) {
+ /* tracking a server (hence inherited maint would appear as "MAINT (via...)" */
+ chunk_appendf(&trash,
+ "<td class=ac colspan=3><a class=lfsb href=\"#%s\">via %s</a></td>",
+ field_str(stats, ST_F_TRACKED), field_str(stats, ST_F_TRACKED));
+ }
+ else
+ chunk_appendf(&trash, "<td colspan=3></td>");
+
+ /* throttle */
+ if (stats[ST_F_THROTTLE].type)
+ chunk_appendf(&trash, "<td class=ac>%d %%</td></tr>\n", stats[ST_F_THROTTLE].u.u32);
+ else
+ chunk_appendf(&trash, "<td class=ac>-</td></tr>\n");
+ }
+ return 1;
+}
+
+/* Dumps a frontend's line to the trash for the current proxy <px> 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.
+ */
+static int stats_dump_fe_stats(struct stream_interface *si, struct proxy *px)
+{
+ struct appctx *appctx = __objt_appctx(si->end);
+
+ if (!(px->cap & PR_CAP_FE))
+ return 0;
+
+ if ((appctx->ctx.stats.flags & STAT_BOUND) && !(appctx->ctx.stats.type & (1 << STATS_TYPE_FE)))
+ return 0;
+
+ memset(&stats, 0, sizeof(stats));
+
+ stats[ST_F_PXNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, px->id);
+ stats[ST_F_SVNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, "FRONTEND");
+ stats[ST_F_SCUR] = mkf_u32(0, px->feconn);
+ stats[ST_F_SMAX] = mkf_u32(FN_MAX, px->fe_counters.conn_max);
+ stats[ST_F_SLIM] = mkf_u32(FO_CONFIG|FN_LIMIT, px->maxconn);
+ stats[ST_F_STOT] = mkf_u64(FN_COUNTER, px->fe_counters.cum_sess);
+ stats[ST_F_BIN] = mkf_u64(FN_COUNTER, px->fe_counters.bytes_in);
+ stats[ST_F_BOUT] = mkf_u64(FN_COUNTER, px->fe_counters.bytes_out);
+ stats[ST_F_DREQ] = mkf_u64(FN_COUNTER, px->fe_counters.denied_req);
+ stats[ST_F_DRESP] = mkf_u64(FN_COUNTER, px->fe_counters.denied_resp);
+ stats[ST_F_EREQ] = mkf_u64(FN_COUNTER, px->fe_counters.failed_req);
+ stats[ST_F_STATUS] = mkf_str(FO_STATUS, px->state == PR_STREADY ? "OPEN" : px->state == PR_STFULL ? "FULL" : "STOP");
+ stats[ST_F_PID] = mkf_u32(FO_KEY, relative_pid);
+ stats[ST_F_IID] = mkf_u32(FO_KEY|FS_SERVICE, px->uuid);
+ stats[ST_F_SID] = mkf_u32(FO_KEY|FS_SERVICE, 0);
+ stats[ST_F_TYPE] = mkf_u32(FO_CONFIG|FS_SERVICE, STATS_TYPE_FE);
+ stats[ST_F_RATE] = mkf_u32(FN_RATE, read_freq_ctr(&px->fe_sess_per_sec));
+ stats[ST_F_RATE_LIM] = mkf_u32(FO_CONFIG|FN_LIMIT, px->fe_sps_lim);
+ stats[ST_F_RATE_MAX] = mkf_u32(FN_MAX, px->fe_counters.sps_max);
+
+ /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
+ if (px->mode == PR_MODE_HTTP) {
+ stats[ST_F_HRSP_1XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[1]);
+ stats[ST_F_HRSP_2XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[2]);
+ stats[ST_F_HRSP_3XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[3]);
+ stats[ST_F_HRSP_4XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[4]);
+ stats[ST_F_HRSP_5XX] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[5]);
+ stats[ST_F_HRSP_OTHER] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.rsp[0]);
+ }
+
+ /* requests : req_rate, req_rate_max, req_tot, */
+ stats[ST_F_REQ_RATE] = mkf_u32(FN_RATE, read_freq_ctr(&px->fe_req_per_sec));
+ stats[ST_F_REQ_RATE_MAX] = mkf_u32(FN_MAX, px->fe_counters.p.http.rps_max);
+ stats[ST_F_REQ_TOT] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.cum_req);
+
+ /* compression: in, out, bypassed, responses */
+ stats[ST_F_COMP_IN] = mkf_u64(FN_COUNTER, px->fe_counters.comp_in);
+ stats[ST_F_COMP_OUT] = mkf_u64(FN_COUNTER, px->fe_counters.comp_out);
+ stats[ST_F_COMP_BYP] = mkf_u64(FN_COUNTER, px->fe_counters.comp_byp);
+ stats[ST_F_COMP_RSP] = mkf_u64(FN_COUNTER, px->fe_counters.p.http.comp_rsp);
+
+ if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
+ int admin;
+
+ admin = (px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN);
+ stats_dump_fields_html(stats, admin, 0, px);
+ }
+ else { /* CSV mode */
+ /* dump everything */
+ stats_dump_fields_csv(&trash, stats);
+ }
+ return 1;
+}
+
+/* Dumps a line for listener <l> and proxy <px> to the trash and uses the state
+ * from stream interface <si>, and stats flags <flags>. The caller is responsible
+ * for clearing the trash if needed. Returns non-zero if it emits anything, zero
+ * otherwise.
+ */
+static int stats_dump_li_stats(struct stream_interface *si, struct proxy *px, struct listener *l, int flags)
+{
+ struct appctx *appctx = __objt_appctx(si->end);
+ struct chunk *out = get_trash_chunk();
+
+ chunk_reset(out);
+ memset(&stats, 0, sizeof(stats));
+
+ stats[ST_F_PXNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, px->id);
+ stats[ST_F_SVNAME] = mkf_str(FO_KEY|FN_NAME|FS_SERVICE, l->name);
+ stats[ST_F_SCUR] = mkf_u32(0, l->nbconn);
+ stats[ST_F_SMAX] = mkf_u32(FN_MAX, l->counters->conn_max);
+ stats[ST_F_SLIM] = mkf_u32(FO_CONFIG|FN_LIMIT, l->maxconn);
+ stats[ST_F_STOT] = mkf_u64(FN_COUNTER, l->counters->cum_conn);
+ stats[ST_F_BIN] = mkf_u64(FN_COUNTER, l->counters->bytes_in);
+ stats[ST_F_BOUT] = mkf_u64(FN_COUNTER, l->counters->bytes_out);
+ stats[ST_F_DREQ] = mkf_u64(FN_COUNTER, l->counters->denied_req);
+ stats[ST_F_DRESP] = mkf_u64(FN_COUNTER, l->counters->denied_resp);
+ stats[ST_F_EREQ] = mkf_u64(FN_COUNTER, l->counters->failed_req);
+ stats[ST_F_STATUS] = mkf_str(FO_STATUS, (l->nbconn < l->maxconn) ? (l->state == LI_LIMITED) ? "WAITING" : "OPEN" : "FULL");
+ stats[ST_F_PID] = mkf_u32(FO_KEY, relative_pid);
+ stats[ST_F_IID] = mkf_u32(FO_KEY|FS_SERVICE, px->uuid);
+ stats[ST_F_SID] = mkf_u32(FO_KEY|FS_SERVICE, l->luid);
+ stats[ST_F_TYPE] = mkf_u32(FO_CONFIG|FS_SERVICE, STATS_TYPE_SO);
+
+ if (flags & ST_SHLGNDS) {
+ char str[INET6_ADDRSTRLEN];
+ int port;
+
+ port = get_host_port(&l->addr);
+ switch (addr_to_str(&l->addr, str, sizeof(str))) {
+ case AF_INET:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
+ chunk_appendf(out, "%s:%d", str, port);
+ break;
+ case AF_INET6:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
+ chunk_appendf(out, "[%s]:%d", str, port);
+ break;
+ case AF_UNIX:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, "unix");
+ break;
+ case -1:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
+ chunk_strcat(out, strerror(errno));
+ break;
+ default: /* address family not supported */
+ break;
+ }
+ }
+
+ if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
+ int admin;
+
+ admin = (px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN);
+ stats_dump_fields_html(stats, admin, flags, px);
+ }
+ else { /* CSV mode */
+ /* dump everything */
+ stats_dump_fields_csv(&trash, stats);
+ }
+ return 1;
+}
+
+enum srv_stats_state {
+ SRV_STATS_STATE_DOWN = 0,
+ SRV_STATS_STATE_DOWN_AGENT,
+ SRV_STATS_STATE_GOING_UP,
+ SRV_STATS_STATE_UP_GOING_DOWN,
+ SRV_STATS_STATE_UP,
+ SRV_STATS_STATE_NOLB_GOING_DOWN,
SRV_STATS_STATE_NOLB,
SRV_STATS_STATE_DRAIN_GOING_DOWN,
SRV_STATS_STATE_DRAIN,
@@ -3635,7 +3913,6 @@
struct appctx *appctx = __objt_appctx(si->end);
struct server *via, *ref;
char str[INET6_ADDRSTRLEN];
- struct chunk src;
struct chunk *out = get_trash_chunk();
enum srv_stats_state state;
char *fld_status;
@@ -3723,409 +4000,139 @@
(ref->state != SRV_ST_STOPPED) ? (ref->check.fall) : (ref->check.rise));
stats[ST_F_STATUS] = mkf_str(FO_STATUS, fld_status);
- stats[ST_F_LASTCHG] = mkf_u32(FN_AGE, now.tv_sec - sv->last_change);
- stats[ST_F_WEIGHT] = mkf_u32(FN_AVG, (sv->eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv);
- stats[ST_F_ACT] = mkf_u32(FO_STATUS, (sv->flags & SRV_F_BACKUP) ? 0 : 1);
- stats[ST_F_BCK] = mkf_u32(FO_STATUS, (sv->flags & SRV_F_BACKUP) ? 1 : 0);
-
- /* check failures: unique, fatal; last change, total downtime */
- if (sv->check.state & CHK_ST_ENABLED) {
- stats[ST_F_CHKFAIL] = mkf_u64(FN_COUNTER, sv->counters.failed_checks);
- stats[ST_F_CHKDOWN] = mkf_u64(FN_COUNTER, sv->counters.down_trans);
- stats[ST_F_DOWNTIME] = mkf_u32(FN_COUNTER, srv_downtime(sv));
- }
-
- if (sv->maxqueue)
- stats[ST_F_QLIMIT] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->maxqueue);
-
- stats[ST_F_PID] = mkf_u32(FO_KEY, relative_pid);
- stats[ST_F_IID] = mkf_u32(FO_KEY|FS_SERVICE, px->uuid);
- stats[ST_F_SID] = mkf_u32(FO_KEY|FS_SERVICE, sv->puid);
-
- if (sv->state == SRV_ST_STARTING && !server_is_draining(sv))
- stats[ST_F_THROTTLE] = mkf_u32(FN_AVG, server_throttle_rate(sv));
-
- stats[ST_F_LBTOT] = mkf_u64(FN_COUNTER, sv->counters.cum_lbconn);
-
- if (sv->track) {
- char *fld_track = chunk_newstr(out);
-
- chunk_appendf(out, "%s/%s", sv->track->proxy->id, sv->track->id);
- stats[ST_F_TRACKED] = mkf_str(FO_CONFIG|FN_NAME|FS_SERVICE, fld_track);
- }
-
- stats[ST_F_TYPE] = mkf_u32(FO_CONFIG|FS_SERVICE, STATS_TYPE_SV);
- stats[ST_F_RATE] = mkf_u32(FN_RATE, read_freq_ctr(&sv->sess_per_sec));
- stats[ST_F_RATE_MAX] = mkf_u32(FN_MAX, sv->counters.sps_max);
-
- if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) {
- const char *fld_chksts;
-
- fld_chksts = chunk_newstr(out);
- chunk_strcat(out, "* "); // for check in progress
- chunk_strcat(out, get_check_status_info(sv->check.status));
- if (!(sv->check.state & CHK_ST_INPROGRESS))
- fld_chksts += 2; // skip "* "
- stats[ST_F_CHECK_STATUS] = mkf_str(FN_OUTPUT, fld_chksts);
-
- if (sv->check.status >= HCHK_STATUS_L57DATA)
- stats[ST_F_CHECK_CODE] = mkf_u32(FN_OUTPUT, sv->check.code);
-
- if (sv->check.status >= HCHK_STATUS_CHECKED)
- stats[ST_F_CHECK_DURATION] = mkf_u64(FN_DURATION, sv->check.duration);
-
- stats[ST_F_CHECK_DESC] = mkf_str(FN_OUTPUT, get_check_status_description(sv->check.status));
- stats[ST_F_LAST_CHK] = mkf_str(FN_OUTPUT, sv->check.desc);
- stats[ST_F_CHECK_RISE] = mkf_u32(FO_CONFIG|FS_SERVICE, ref->check.rise);
- stats[ST_F_CHECK_FALL] = mkf_u32(FO_CONFIG|FS_SERVICE, ref->check.fall);
- stats[ST_F_CHECK_HEALTH] = mkf_u32(FO_CONFIG|FS_SERVICE, ref->check.health);
- }
-
- if ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) {
- const char *fld_chksts;
-
- fld_chksts = chunk_newstr(out);
- chunk_strcat(out, "* "); // for check in progress
- chunk_strcat(out, get_check_status_info(sv->agent.status));
- if (!(sv->agent.state & CHK_ST_INPROGRESS))
- fld_chksts += 2; // skip "* "
- stats[ST_F_AGENT_STATUS] = mkf_str(FN_OUTPUT, fld_chksts);
-
- if (sv->agent.status >= HCHK_STATUS_L57DATA)
- stats[ST_F_AGENT_CODE] = mkf_u32(FN_OUTPUT, sv->agent.code);
-
- if (sv->agent.status >= HCHK_STATUS_CHECKED)
- stats[ST_F_AGENT_DURATION] = mkf_u64(FN_DURATION, sv->agent.duration);
-
- stats[ST_F_AGENT_DESC] = mkf_str(FN_OUTPUT, get_check_status_description(sv->agent.status));
- stats[ST_F_LAST_AGT] = mkf_str(FN_OUTPUT, sv->agent.desc);
- stats[ST_F_AGENT_RISE] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->agent.rise);
- stats[ST_F_AGENT_FALL] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->agent.fall);
- stats[ST_F_AGENT_HEALTH] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->agent.health);
- }
-
- /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
- if (px->mode == PR_MODE_HTTP) {
- stats[ST_F_HRSP_1XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[1]);
- stats[ST_F_HRSP_2XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[2]);
- stats[ST_F_HRSP_3XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[3]);
- stats[ST_F_HRSP_4XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[4]);
- stats[ST_F_HRSP_5XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[5]);
- stats[ST_F_HRSP_OTHER] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[0]);
- }
-
- if (ref->observe)
- stats[ST_F_HANAFAIL] = mkf_u64(FN_COUNTER, sv->counters.failed_hana);
-
- stats[ST_F_CLI_ABRT] = mkf_u64(FN_COUNTER, sv->counters.cli_aborts);
- stats[ST_F_SRV_ABRT] = mkf_u64(FN_COUNTER, sv->counters.srv_aborts);
- stats[ST_F_LASTSESS] = mkf_s32(FN_AGE, srv_lastsession(sv));
-
- stats[ST_F_QTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES));
- stats[ST_F_CTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES));
- stats[ST_F_RTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES));
- stats[ST_F_TTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES));
-
- if (flags & ST_SHLGNDS) {
- switch (addr_to_str(&sv->addr, str, sizeof(str))) {
- case AF_INET:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
- chunk_appendf(out, "%s:%d", str, get_host_port(&sv->addr));
- break;
- case AF_INET6:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
- chunk_appendf(out, "[%s]:%d", str, get_host_port(&sv->addr));
- break;
- case AF_UNIX:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, "unix");
- break;
- case -1:
- stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
- chunk_strcat(out, strerror(errno));
- break;
- default: /* address family not supported */
- break;
- }
-
- if (sv->cookie)
- stats[ST_F_COOKIE] = mkf_str(FO_CONFIG|FN_NAME|FS_SERVICE, sv->cookie);
- }
-
- if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
- const char *style;
-
- /* determine the style to use depending on the server's state,
- * its health and weight. There isn't a 1-to-1 mapping between
- * state and styles for the cases where the server is (still)
- * up. The reason is that we don't want to report nolb and
- * drain with the same color.
- */
-
- if (strcmp(field_str(stats, ST_F_STATUS), "DOWN") == 0 ||
- strcmp(field_str(stats, ST_F_STATUS), "DOWN (agent)") == 0) {
- style = "down";
- }
- else if (strcmp(field_str(stats, ST_F_STATUS), "DOWN ") == 0) {
- style = "going_up";
- }
- else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB ") == 0) {
- style = "going_down";
- }
- else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB") == 0) {
- style = "nolb";
- }
- else if (strcmp(field_str(stats, ST_F_STATUS), "no check") == 0) {
- style = "no_check";
- }
- else if (!stats[ST_F_CHKFAIL].type ||
- stats[ST_F_CHECK_HEALTH].u.u32 == stats[ST_F_CHECK_RISE].u.u32 + stats[ST_F_CHECK_FALL].u.u32 - 1) {
- /* no check or max health = UP */
- if (stats[ST_F_WEIGHT].u.u32)
- style = "up";
- else
- style = "draining";
- }
- else {
- style = "going_down";
- }
-
- if (memcmp(field_str(stats, ST_F_STATUS), "MAINT", 5) == 0)
- chunk_appendf(&trash, "<tr class=\"maintain\">");
- else
- chunk_appendf(&trash,
- "<tr class=\"%s_%s\">",
- (stats[ST_F_BCK].u.u32) ? "backup" : "active", style);
-
-
- if ((px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN))
- chunk_appendf(&trash,
- "<td><input type=\"checkbox\" name=\"s\" value=\"%s\"></td>",
- field_str(stats, ST_F_SVNAME));
-
- chunk_appendf(&trash,
- "<td class=ac><a name=\"%s/%s\"></a>%s"
- "<a class=lfsb href=\"#%s/%s\">%s</a>"
- "",
- field_str(stats, ST_F_PXNAME), field_str(stats, ST_F_SVNAME),
- (flags & ST_SHLGNDS) ? "<u>" : "",
- field_str(stats, ST_F_PXNAME), field_str(stats, ST_F_SVNAME), field_str(stats, ST_F_SVNAME));
-
- if (flags & ST_SHLGNDS) {
- chunk_appendf(&trash, "<div class=tips>");
-
- if (isdigit(*field_str(stats, ST_F_ADDR)))
- chunk_appendf(&trash, "IPv4: %s, ", field_str(stats, ST_F_ADDR));
- else if (*field_str(stats, ST_F_ADDR) == '[')
- chunk_appendf(&trash, "IPv6: %s, ", field_str(stats, ST_F_ADDR));
- else if (*field_str(stats, ST_F_ADDR))
- chunk_appendf(&trash, "%s, ", field_str(stats, ST_F_ADDR));
-
- /* id */
- chunk_appendf(&trash, "id: %d", stats[ST_F_SID].u.u32);
-
- /* cookie */
- if (stats[ST_F_COOKIE].type) {
- chunk_appendf(&trash, ", cookie: '");
- chunk_initstr(&src, field_str(stats, ST_F_COOKIE));
- chunk_htmlencode(&trash, &src);
- chunk_appendf(&trash, "'");
- }
-
- chunk_appendf(&trash, "</div>");
- }
-
- chunk_appendf(&trash,
- /* queue : current, max, limit */
- "%s</td><td>%s</td><td>%s</td><td>%s</td>"
- /* sessions rate : current, max, limit */
- "<td>%s</td><td>%s</td><td></td>"
- "",
- (flags & ST_SHLGNDS) ? "</u>" : "",
- U2H(stats[ST_F_QCUR].u.u32), U2H(stats[ST_F_QMAX].u.u32), LIM2A(stats[ST_F_QLIMIT].u.u32, "-"),
- U2H(stats[ST_F_RATE].u.u32), U2H(stats[ST_F_RATE_MAX].u.u32));
-
- chunk_appendf(&trash,
- /* sessions: current, max, limit, total */
- "<td>%s</td><td>%s</td><td>%s</td>"
- "<td><u>%s<div class=tips><table class=det>"
- "<tr><th>Cum. sessions:</th><td>%s</td></tr>"
- "",
- U2H(stats[ST_F_SCUR].u.u32), U2H(stats[ST_F_SMAX].u.u32), LIM2A(stats[ST_F_SLIM].u.u32, "-"),
- U2H(stats[ST_F_STOT].u.u64),
- U2H(stats[ST_F_STOT].u.u64));
+ stats[ST_F_LASTCHG] = mkf_u32(FN_AGE, now.tv_sec - sv->last_change);
+ stats[ST_F_WEIGHT] = mkf_u32(FN_AVG, (sv->eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv);
+ stats[ST_F_ACT] = mkf_u32(FO_STATUS, (sv->flags & SRV_F_BACKUP) ? 0 : 1);
+ stats[ST_F_BCK] = mkf_u32(FO_STATUS, (sv->flags & SRV_F_BACKUP) ? 1 : 0);
- /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
- if (px->mode == PR_MODE_HTTP) {
- unsigned long long tot;
+ /* check failures: unique, fatal; last change, total downtime */
+ if (sv->check.state & CHK_ST_ENABLED) {
+ stats[ST_F_CHKFAIL] = mkf_u64(FN_COUNTER, sv->counters.failed_checks);
+ stats[ST_F_CHKDOWN] = mkf_u64(FN_COUNTER, sv->counters.down_trans);
+ stats[ST_F_DOWNTIME] = mkf_u32(FN_COUNTER, srv_downtime(sv));
+ }
- tot = stats[ST_F_HRSP_OTHER].u.u64;
- tot += stats[ST_F_HRSP_1XX].u.u64;
- tot += stats[ST_F_HRSP_2XX].u.u64;
- tot += stats[ST_F_HRSP_3XX].u.u64;
- tot += stats[ST_F_HRSP_4XX].u.u64;
- tot += stats[ST_F_HRSP_5XX].u.u64;
+ if (sv->maxqueue)
+ stats[ST_F_QLIMIT] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->maxqueue);
- chunk_appendf(&trash,
- "<tr><th>Cum. HTTP responses:</th><td>%s</td></tr>"
- "<tr><th>- HTTP 1xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
- "<tr><th>- HTTP 2xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
- "<tr><th>- HTTP 3xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
- "<tr><th>- HTTP 4xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
- "<tr><th>- HTTP 5xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
- "<tr><th>- other responses:</th><td>%s</td><td>(%d%%)</td></tr>"
- "",
- U2H(tot),
- U2H(stats[ST_F_HRSP_1XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_1XX].u.u64 / tot) : 0,
- U2H(stats[ST_F_HRSP_2XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_2XX].u.u64 / tot) : 0,
- U2H(stats[ST_F_HRSP_3XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_3XX].u.u64 / tot) : 0,
- U2H(stats[ST_F_HRSP_4XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_4XX].u.u64 / tot) : 0,
- U2H(stats[ST_F_HRSP_5XX].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_5XX].u.u64 / tot) : 0,
- U2H(stats[ST_F_HRSP_OTHER].u.u64), tot ? (int)(100 * stats[ST_F_HRSP_OTHER].u.u64 / tot) : 0);
- }
+ stats[ST_F_PID] = mkf_u32(FO_KEY, relative_pid);
+ stats[ST_F_IID] = mkf_u32(FO_KEY|FS_SERVICE, px->uuid);
+ stats[ST_F_SID] = mkf_u32(FO_KEY|FS_SERVICE, sv->puid);
- chunk_appendf(&trash, "<tr><th colspan=3>Avg over last 1024 success. conn.</th></tr>");
- chunk_appendf(&trash, "<tr><th>- Queue time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_QTIME].u.u32));
- chunk_appendf(&trash, "<tr><th>- Connect time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_CTIME].u.u32));
- if (px->mode == PR_MODE_HTTP)
- chunk_appendf(&trash, "<tr><th>- Response time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_RTIME].u.u32));
- chunk_appendf(&trash, "<tr><th>- Total time:</th><td>%s</td><td>ms</td></tr>", U2H(stats[ST_F_TTIME].u.u32));
+ if (sv->state == SRV_ST_STARTING && !server_is_draining(sv))
+ stats[ST_F_THROTTLE] = mkf_u32(FN_AVG, server_throttle_rate(sv));
- chunk_appendf(&trash,
- "</table></div></u></td>"
- /* sessions: lbtot, last */
- "<td>%s</td><td>%s</td>",
- U2H(stats[ST_F_LBTOT].u.u64),
- human_time(stats[ST_F_LASTSESS].u.s32, 1));
+ stats[ST_F_LBTOT] = mkf_u64(FN_COUNTER, sv->counters.cum_lbconn);
- chunk_appendf(&trash,
- /* bytes : in, out */
- "<td>%s</td><td>%s</td>"
- /* denied: req, resp */
- "<td></td><td>%s</td>"
- /* errors : request, connect */
- "<td></td><td>%s</td>"
- /* errors : response */
- "<td><u>%s<div class=tips>Connection resets during transfers: %lld client, %lld server</div></u></td>"
- /* warnings: retries, redispatches */
- "<td>%lld</td><td>%lld</td>"
- "",
- U2H(stats[ST_F_BIN].u.u64), U2H(stats[ST_F_BOUT].u.u64),
- U2H(stats[ST_F_DRESP].u.u64),
- U2H(stats[ST_F_ECON].u.u64),
- U2H(stats[ST_F_ERESP].u.u64),
- (long long)stats[ST_F_CLI_ABRT].u.u64,
- (long long)stats[ST_F_SRV_ABRT].u.u64,
- (long long)stats[ST_F_WRETR].u.u64,
- (long long)stats[ST_F_WREDIS].u.u64);
+ if (sv->track) {
+ char *fld_track = chunk_newstr(out);
- /* status, last change */
- chunk_appendf(&trash, "<td class=ac>");
+ chunk_appendf(out, "%s/%s", sv->track->proxy->id, sv->track->id);
+ stats[ST_F_TRACKED] = mkf_str(FO_CONFIG|FN_NAME|FS_SERVICE, fld_track);
+ }
- /* FIXME!!!!
- * LASTCHG should contain the last change for *this* server and must be computed
- * properly above, as was done below, ie: this server if maint, otherwise ref server
- * if tracking. Note that ref is either local or remote depending on tracking.
- */
+ stats[ST_F_TYPE] = mkf_u32(FO_CONFIG|FS_SERVICE, STATS_TYPE_SV);
+ stats[ST_F_RATE] = mkf_u32(FN_RATE, read_freq_ctr(&sv->sess_per_sec));
+ stats[ST_F_RATE_MAX] = mkf_u32(FN_MAX, sv->counters.sps_max);
+ if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) {
+ const char *fld_chksts;
- if (memcmp(field_str(stats, ST_F_STATUS), "MAINT", 5) == 0) {
- chunk_appendf(&trash, "%s MAINT", human_time(stats[ST_F_LASTCHG].u.u32, 1));
- }
- else if (memcmp(field_str(stats, ST_F_STATUS), "no check", 5) == 0) {
- chunk_strcat(&trash, "<i>no check</i>");
- }
- else {
- chunk_appendf(&trash, "%s %s", human_time(stats[ST_F_LASTCHG].u.u32, 1), field_str(stats, ST_F_STATUS));
- if (memcmp(field_str(stats, ST_F_STATUS), "DOWN", 4) == 0) {
- if (stats[ST_F_CHECK_HEALTH].u.u32)
- chunk_strcat(&trash, " ↑");
- }
- else if (stats[ST_F_CHECK_HEALTH].u.u32 < stats[ST_F_CHECK_RISE].u.u32 + stats[ST_F_CHECK_FALL].u.u32 - 1)
- chunk_strcat(&trash, " ↓");
- }
+ fld_chksts = chunk_newstr(out);
+ chunk_strcat(out, "* "); // for check in progress
+ chunk_strcat(out, get_check_status_info(sv->check.status));
+ if (!(sv->check.state & CHK_ST_INPROGRESS))
+ fld_chksts += 2; // skip "* "
+ stats[ST_F_CHECK_STATUS] = mkf_str(FN_OUTPUT, fld_chksts);
- if (memcmp(field_str(stats, ST_F_STATUS), "DOWN", 4) == 0 &&
- stats[ST_F_AGENT_STATUS].type && !stats[ST_F_AGENT_HEALTH].u.u32) {
- chunk_appendf(&trash,
- "</td><td class=ac><u> %s",
- field_str(stats, ST_F_AGENT_STATUS));
+ if (sv->check.status >= HCHK_STATUS_L57DATA)
+ stats[ST_F_CHECK_CODE] = mkf_u32(FN_OUTPUT, sv->check.code);
- if (stats[ST_F_AGENT_CODE].type)
- chunk_appendf(&trash, "/%d", stats[ST_F_AGENT_CODE].u.u32);
+ if (sv->check.status >= HCHK_STATUS_CHECKED)
+ stats[ST_F_CHECK_DURATION] = mkf_u64(FN_DURATION, sv->check.duration);
- if (stats[ST_F_AGENT_DURATION].type && stats[ST_F_AGENT_DURATION].u.u64 >= 0)
- chunk_appendf(&trash, " in %lums", (long)stats[ST_F_AGENT_DURATION].u.u64);
+ stats[ST_F_CHECK_DESC] = mkf_str(FN_OUTPUT, get_check_status_description(sv->check.status));
+ stats[ST_F_LAST_CHK] = mkf_str(FN_OUTPUT, sv->check.desc);
+ stats[ST_F_CHECK_RISE] = mkf_u32(FO_CONFIG|FS_SERVICE, ref->check.rise);
+ stats[ST_F_CHECK_FALL] = mkf_u32(FO_CONFIG|FS_SERVICE, ref->check.fall);
+ stats[ST_F_CHECK_HEALTH] = mkf_u32(FO_CONFIG|FS_SERVICE, ref->check.health);
+ }
- chunk_appendf(&trash, "<div class=tips>%s", field_str(stats, ST_F_AGENT_DESC));
+ if ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) {
+ const char *fld_chksts;
- if (*field_str(stats, ST_F_LAST_AGT)) {
- chunk_appendf(&trash, ": ");
- chunk_initstr(&src, field_str(stats, ST_F_LAST_AGT));
- chunk_htmlencode(&trash, &src);
- }
- chunk_appendf(&trash, "</div></u>");
- }
- else if (stats[ST_F_CHECK_STATUS].type) {
- chunk_appendf(&trash,
- "</td><td class=ac><u> %s",
- field_str(stats, ST_F_CHECK_STATUS));
+ fld_chksts = chunk_newstr(out);
+ chunk_strcat(out, "* "); // for check in progress
+ chunk_strcat(out, get_check_status_info(sv->agent.status));
+ if (!(sv->agent.state & CHK_ST_INPROGRESS))
+ fld_chksts += 2; // skip "* "
+ stats[ST_F_AGENT_STATUS] = mkf_str(FN_OUTPUT, fld_chksts);
- if (stats[ST_F_CHECK_CODE].type)
- chunk_appendf(&trash, "/%d", stats[ST_F_CHECK_CODE].u.u32);
+ if (sv->agent.status >= HCHK_STATUS_L57DATA)
+ stats[ST_F_AGENT_CODE] = mkf_u32(FN_OUTPUT, sv->agent.code);
- if (stats[ST_F_CHECK_DURATION].type && stats[ST_F_CHECK_DURATION].u.u64 >= 0)
- chunk_appendf(&trash, " in %lums", (long)stats[ST_F_CHECK_DURATION].u.u64);
+ if (sv->agent.status >= HCHK_STATUS_CHECKED)
+ stats[ST_F_AGENT_DURATION] = mkf_u64(FN_DURATION, sv->agent.duration);
- chunk_appendf(&trash, "<div class=tips>%s", field_str(stats, ST_F_CHECK_DESC));
+ stats[ST_F_AGENT_DESC] = mkf_str(FN_OUTPUT, get_check_status_description(sv->agent.status));
+ stats[ST_F_LAST_AGT] = mkf_str(FN_OUTPUT, sv->agent.desc);
+ stats[ST_F_AGENT_RISE] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->agent.rise);
+ stats[ST_F_AGENT_FALL] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->agent.fall);
+ stats[ST_F_AGENT_HEALTH] = mkf_u32(FO_CONFIG|FS_SERVICE, sv->agent.health);
+ }
- if (*field_str(stats, ST_F_LAST_CHK)) {
- chunk_appendf(&trash, ": ");
- chunk_initstr(&src, field_str(stats, ST_F_LAST_CHK));
- chunk_htmlencode(&trash, &src);
- }
- chunk_appendf(&trash, "</div></u>");
- }
- else
- chunk_appendf(&trash, "</td><td>");
+ /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
+ if (px->mode == PR_MODE_HTTP) {
+ stats[ST_F_HRSP_1XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[1]);
+ stats[ST_F_HRSP_2XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[2]);
+ stats[ST_F_HRSP_3XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[3]);
+ stats[ST_F_HRSP_4XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[4]);
+ stats[ST_F_HRSP_5XX] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[5]);
+ stats[ST_F_HRSP_OTHER] = mkf_u64(FN_COUNTER, sv->counters.p.http.rsp[0]);
+ }
- chunk_appendf(&trash,
- /* weight */
- "</td><td class=ac>%d</td>"
- /* act, bck */
- "<td class=ac>%s</td><td class=ac>%s</td>"
- "",
- stats[ST_F_WEIGHT].u.u32,
- stats[ST_F_BCK].u.u32 ? "-" : "Y",
- stats[ST_F_BCK].u.u32 ? "Y" : "-");
+ if (ref->observe)
+ stats[ST_F_HANAFAIL] = mkf_u64(FN_COUNTER, sv->counters.failed_hana);
- /* check failures: unique, fatal, down time */
- if (stats[ST_F_CHKFAIL].type) {
- chunk_appendf(&trash, "<td><u>%lld", (long long)stats[ST_F_CHKFAIL].u.u64);
+ stats[ST_F_CLI_ABRT] = mkf_u64(FN_COUNTER, sv->counters.cli_aborts);
+ stats[ST_F_SRV_ABRT] = mkf_u64(FN_COUNTER, sv->counters.srv_aborts);
+ stats[ST_F_LASTSESS] = mkf_s32(FN_AGE, srv_lastsession(sv));
- if (stats[ST_F_HANAFAIL].type)
- chunk_appendf(&trash, "/%lld", (long long)stats[ST_F_HANAFAIL].u.u64);
+ stats[ST_F_QTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES));
+ stats[ST_F_CTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES));
+ stats[ST_F_RTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES));
+ stats[ST_F_TTIME] = mkf_u32(FN_AVG, swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES));
- chunk_appendf(&trash,
- "<div class=tips>Failed Health Checks%s</div></u></td>"
- "<td>%lld</td><td>%s</td>"
- "",
- stats[ST_F_HANAFAIL].type ? "/Health Analyses" : "",
- (long long)stats[ST_F_CHKDOWN].u.u64, human_time(stats[ST_F_DOWNTIME].u.u32, 1));
- }
- else if (strcmp(field_str(stats, ST_F_STATUS), "MAINT") != 0 && field_format(stats, ST_F_TRACKED) == FF_STR) {
- /* tracking a server (hence inherited maint would appear as "MAINT (via...)" */
- chunk_appendf(&trash,
- "<td class=ac colspan=3><a class=lfsb href=\"#%s\">via %s</a></td>",
- field_str(stats, ST_F_TRACKED), field_str(stats, ST_F_TRACKED));
+ if (flags & ST_SHLGNDS) {
+ switch (addr_to_str(&sv->addr, str, sizeof(str))) {
+ case AF_INET:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
+ chunk_appendf(out, "%s:%d", str, get_host_port(&sv->addr));
+ break;
+ case AF_INET6:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
+ chunk_appendf(out, "[%s]:%d", str, get_host_port(&sv->addr));
+ break;
+ case AF_UNIX:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, "unix");
+ break;
+ case -1:
+ stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, chunk_newstr(out));
+ chunk_strcat(out, strerror(errno));
+ break;
+ default: /* address family not supported */
+ break;
}
- else
- chunk_appendf(&trash, "<td colspan=3></td>");
- /* throttle */
- if (stats[ST_F_THROTTLE].type)
- chunk_appendf(&trash, "<td class=ac>%d %%</td></tr>\n", stats[ST_F_THROTTLE].u.u32);
- else
- chunk_appendf(&trash, "<td class=ac>-</td></tr>\n");
+ if (sv->cookie)
+ stats[ST_F_COOKIE] = mkf_str(FO_CONFIG|FN_NAME|FS_SERVICE, sv->cookie);
+ }
+
+ if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
+ int admin;
+
+ admin = (px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN);
+ stats_dump_fields_html(stats, admin, flags, px);
}
else { /* CSV mode */
/* dump everything */