From: Willy Tarreau Date: Fri, 8 Jan 2016 16:23:28 +0000 (+0100) Subject: REORG: stats: dump the server stats via the generic function X-Git-Tag: v1.7-dev2~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=362eaeb9bcfb7efacc1bb259ff5242e309fbcde5;p=thirdparty%2Fhaproxy.git 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 00c9bfeed7..83cd86a13e 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -3254,6 +3254,8 @@ static int stats_dump_fields_csv(struct chunk *out, const struct field *stats) */ 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 @@ static int stats_dump_fields_html(const struct field *stats, int admin, unsigned 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 and uses - * the state from stream interface . 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, ""); + else + chunk_appendf(&trash, + "", + (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, + "", + 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, + "%s" + "%s" + "", + field_str(stats, ST_F_PXNAME), field_str(stats, ST_F_SVNAME), + (flags & ST_SHLGNDS) ? "" : "", + 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, "
"); - /* 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 and proxy to the trash and uses the state - * from stream interface , and stats 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, "
"); + } - chunk_reset(out); - memset(&stats, 0, sizeof(stats)); + chunk_appendf(&trash, + /* queue : current, max, limit */ + "%s%s%s%s" + /* sessions rate : current, max, limit */ + "%s%s" + "", + (flags & ST_SHLGNDS) ? "
" : "", + 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 */ + "%s%s%s" + "%s
" + "" + "", + 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, + "" + "" + "" + "" + "" + "" + "" + "", + 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, ""); + chunk_appendf(&trash, "", U2H(stats[ST_F_QTIME].u.u32)); + chunk_appendf(&trash, "", U2H(stats[ST_F_CTIME].u.u32)); + if (px->mode == PR_MODE_HTTP) + chunk_appendf(&trash, "", U2H(stats[ST_F_RTIME].u.u32)); + chunk_appendf(&trash, "", 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, + "
Cum. sessions:%s
Cum. HTTP responses:%s
- HTTP 1xx responses:%s(%d%%)
- HTTP 2xx responses:%s(%d%%)
- HTTP 3xx responses:%s(%d%%)
- HTTP 4xx responses:%s(%d%%)
- HTTP 5xx responses:%s(%d%%)
- other responses:%s(%d%%)
Avg over last 1024 success. conn.
- Queue time:%sms
- Connect time:%sms
- Response time:%sms
- Total time:%sms
" + /* sessions: lbtot, last */ + "%s%s", + 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 */ + "%s%s" + /* denied: req, resp */ + "%s" + /* errors : request, connect */ + "%s" + /* errors : response */ + "%s
Connection resets during transfers: %lld client, %lld server
" + /* warnings: retries, redispatches */ + "%lld%lld" + "", + 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, ""); + + /* 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, "no check"); + } + 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, + " %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, "
%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, "
"); + } + else if (stats[ST_F_CHECK_STATUS].type) { + chunk_appendf(&trash, + " %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, "
%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, "
"); + } + else + chunk_appendf(&trash, ""); + + chunk_appendf(&trash, + /* weight */ + "%d" + /* act, bck */ + "%s%s" + "", + 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, "%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, + "
Failed Health Checks%s
" + "%lld%s" + "", + 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, + "via %s", + field_str(stats, ST_F_TRACKED), field_str(stats, ST_F_TRACKED)); + } + else + chunk_appendf(&trash, ""); + + /* throttle */ + if (stats[ST_F_THROTTLE].type) + chunk_appendf(&trash, "%d %%\n", stats[ST_F_THROTTLE].u.u32); + else + chunk_appendf(&trash, "-\n"); + } + return 1; +} + +/* Dumps a frontend's line to the trash for the current proxy and uses + * the state from stream interface . 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 and proxy to the trash and uses the state + * from stream interface , and stats 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 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in 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 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in (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, ""); - else - chunk_appendf(&trash, - "", - (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, - "", - field_str(stats, ST_F_SVNAME)); - - chunk_appendf(&trash, - "%s" - "%s" - "", - field_str(stats, ST_F_PXNAME), field_str(stats, ST_F_SVNAME), - (flags & ST_SHLGNDS) ? "" : "", - 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, "
"); - - 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, "
"); - } - - chunk_appendf(&trash, - /* queue : current, max, limit */ - "%s%s%s%s" - /* sessions rate : current, max, limit */ - "%s%s" - "", - (flags & ST_SHLGNDS) ? "
" : "", - 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 */ - "%s%s%s" - "%s
" - "" - "", - 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, - "" - "" - "" - "" - "" - "" - "" - "", - 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, ""); - chunk_appendf(&trash, "", U2H(stats[ST_F_QTIME].u.u32)); - chunk_appendf(&trash, "", U2H(stats[ST_F_CTIME].u.u32)); - if (px->mode == PR_MODE_HTTP) - chunk_appendf(&trash, "", U2H(stats[ST_F_RTIME].u.u32)); - chunk_appendf(&trash, "", 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, - "
Cum. sessions:%s
Cum. HTTP responses:%s
- HTTP 1xx responses:%s(%d%%)
- HTTP 2xx responses:%s(%d%%)
- HTTP 3xx responses:%s(%d%%)
- HTTP 4xx responses:%s(%d%%)
- HTTP 5xx responses:%s(%d%%)
- other responses:%s(%d%%)
Avg over last 1024 success. conn.
- Queue time:%sms
- Connect time:%sms
- Response time:%sms
- Total time:%sms
" - /* sessions: lbtot, last */ - "%s%s", - 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 */ - "%s%s" - /* denied: req, resp */ - "%s" - /* errors : request, connect */ - "%s" - /* errors : response */ - "%s
Connection resets during transfers: %lld client, %lld server
" - /* warnings: retries, redispatches */ - "%lld%lld" - "", - 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, ""); + 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, "no check"); - } - 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, - " %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, "
%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, "
"); - } - else if (stats[ST_F_CHECK_STATUS].type) { - chunk_appendf(&trash, - " %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, "
%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, "
"); - } - else - chunk_appendf(&trash, ""); + /* 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 */ - "%d" - /* act, bck */ - "%s%s" - "", - 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, "%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, - "
Failed Health Checks%s
" - "%lld%s" - "", - 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, - "via %s", - 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, ""); - /* throttle */ - if (stats[ST_F_THROTTLE].type) - chunk_appendf(&trash, "%d %%\n", stats[ST_F_THROTTLE].u.u32); - else - chunk_appendf(&trash, "-\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 */