]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: stats: convert stats_dump_sv_stats() to use stats_dump_fields_csv()
authorWilly Tarreau <w@1wt.eu>
Wed, 6 Jan 2016 18:25:38 +0000 (19:25 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 11 Mar 2016 16:08:04 +0000 (17:08 +0100)
This function now only fills the relevant fields with raw values and
calls stats_dump_fields_csv() for the CSV part. The output remains
exactly the same for now.

Some limits are only emitted if set, so the HTML part will have to
check for these being set.

A number of fields had to be built using printf-format strings, so
instead of allocating strings that risk not being freed, we use
chunk_newstr() and chunk_appendf().

Text strings are now copied verbatim in the stats fields so that only
the CSV dump encodes them as CSV. A single "out" chunk is used and cut
into multiple substrings using chunk_newstr() so that we don't need
distinct chunks for each stats field holding a string. The total amount
of data being emitted at once will never overflow the "out" chunk since
only a small part of it goes into the trash buffer which is the same size
and will thus overflow first.

One point of care is that failed_checks and down_trans were logged as
64-bit quantities on servers but they're 32-bit on proxies. This may
have to be changed later to unify them.

src/dumpstats.c

index b87e7fcdb3f61acf0fbfa6de9fd5825039765ffb..500e56f162e08eb2ebd0d63f3be0d5d5c4598440 100644 (file)
@@ -3547,6 +3547,20 @@ enum srv_stats_state {
        SRV_STATS_STATE_COUNT, /* Must be last */
 };
 
+static const char *srv_hlt_st[SRV_STATS_STATE_COUNT] = {
+       [SRV_STATS_STATE_DOWN]                  = "DOWN",
+       [SRV_STATS_STATE_DOWN_AGENT]            = "DOWN (agent)",
+       [SRV_STATS_STATE_GOING_UP]              = "DOWN %d/%d",
+       [SRV_STATS_STATE_UP_GOING_DOWN]         = "UP %d/%d",
+       [SRV_STATS_STATE_UP]                    = "UP",
+       [SRV_STATS_STATE_NOLB_GOING_DOWN]       = "NOLB %d/%d",
+       [SRV_STATS_STATE_NOLB]                  = "NOLB",
+       [SRV_STATS_STATE_DRAIN_GOING_DOWN]      = "DRAIN %d/%d",
+       [SRV_STATS_STATE_DRAIN]                 = "DRAIN",
+       [SRV_STATS_STATE_DRAIN_AGENT]           = "DRAIN (agent)",
+       [SRV_STATS_STATE_NO_CHECK]              = "no check"
+};
+
 enum srv_stats_colour {
        SRV_STATS_COLOUR_DOWN = 0,
        SRV_STATS_COLOUR_GOING_UP,
@@ -3581,8 +3595,8 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
        struct server *via, *ref;
        char str[INET6_ADDRSTRLEN];
        struct chunk src;
-       int i;
-
+       struct chunk *out = get_trash_chunk();
+       char *fld_status;
        /* we have "via" which is the tracked server as described in the configuration,
         * and "ref" which is the checked server and the end of the chain.
         */
@@ -3591,6 +3605,116 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
        while (ref->track)
                ref = ref->track;
 
+       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, sv->id);
+       stats[ST_F_QCUR]     = mkf_u32(0, sv->nbpend);
+       stats[ST_F_QMAX]     = mkf_u32(FN_MAX, sv->counters.nbpend_max);
+       stats[ST_F_SCUR]     = mkf_u32(0, sv->cur_sess);
+       stats[ST_F_SMAX]     = mkf_u32(FN_MAX, sv->counters.cur_sess_max);
+
+       if (sv->maxconn)
+               stats[ST_F_SLIM] = mkf_u32(FO_CONFIG|FN_LIMIT, sv->maxconn);
+
+       stats[ST_F_STOT]     = mkf_u64(FN_COUNTER, sv->counters.cum_sess);
+       stats[ST_F_BIN]      = mkf_u64(FN_COUNTER, sv->counters.bytes_in);
+       stats[ST_F_BOUT]     = mkf_u64(FN_COUNTER, sv->counters.bytes_out);
+       stats[ST_F_DRESP]    = mkf_u64(FN_COUNTER, sv->counters.failed_secu);
+       stats[ST_F_ECON]     = mkf_u64(FN_COUNTER, sv->counters.failed_conns);
+       stats[ST_F_ERESP]    = mkf_u64(FN_COUNTER, sv->counters.failed_resp);
+       stats[ST_F_WRETR]    = mkf_u64(FN_COUNTER, sv->counters.retries);
+       stats[ST_F_WREDIS]   = mkf_u64(FN_COUNTER, sv->counters.redispatches);
+
+       /* status */
+       fld_status = chunk_newstr(out);
+       if (sv->admin & SRV_ADMF_IMAINT)
+               chunk_appendf(out, "MAINT (via %s/%s)", via->proxy->id, via->id);
+       else if (sv->admin & SRV_ADMF_MAINT)
+               chunk_appendf(out, "MAINT");
+       else
+               chunk_appendf(out,
+                             srv_hlt_st[state],
+                             (ref->state != SRV_ST_STOPPED) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
+                             (ref->state != SRV_ST_STOPPED) ? (ref->check.fall) : (ref->check.rise));
+
+       stats[ST_F_STATUS]   = mkf_str(FO_STATUS, fld_status);
+       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_LASTCHG]  = mkf_u32(FN_AGE, now.tv_sec - sv->last_change);
+               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) {
+               const char *fld_chksts;
+
+               fld_chksts = chunk_newstr(out);
+               chunk_strcat(out, get_check_status_info(sv->check.status));
+               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);
+       }
+
+       /* 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]);
+       }
+
+       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));
+
+       if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED)
+               stats[ST_F_LAST_CHK] = mkf_str(FN_OUTPUT, sv->check.desc);
+
+       if ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED)
+               stats[ST_F_LAST_AGT] = mkf_str(FN_OUTPUT, sv->agent.desc);
+
+       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 (appctx->ctx.stats.flags & STAT_FMT_HTML) {
                static char *srv_hlt_st[SRV_STATS_STATE_COUNT] = {
                        [SRV_STATS_STATE_DOWN]                  = "DOWN",
@@ -3686,6 +3810,7 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
                /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
                if (px->mode == PR_MODE_HTTP) {
                        unsigned long long tot;
+                       int i;
                        for (tot = i = 0; i < 6; i++)
                                tot += sv->counters.p.http.rsp[i];
 
@@ -3847,161 +3972,8 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
                        chunk_appendf(&trash, "<td class=ac>-</td></tr>\n");
        }
        else { /* CSV mode */
-               struct chunk *out = get_trash_chunk();
-               static char *srv_hlt_st[SRV_STATS_STATE_COUNT] = {
-                       [SRV_STATS_STATE_DOWN]                  = "DOWN,",
-                       [SRV_STATS_STATE_DOWN_AGENT]            = "DOWN (agent),",
-                       [SRV_STATS_STATE_GOING_UP]              = "DOWN %d/%d,",
-                       [SRV_STATS_STATE_UP_GOING_DOWN]         = "UP %d/%d,",
-                       [SRV_STATS_STATE_UP]                    = "UP,",
-                       [SRV_STATS_STATE_NOLB_GOING_DOWN]       = "NOLB %d/%d,",
-                       [SRV_STATS_STATE_NOLB]                  = "NOLB,",
-                       [SRV_STATS_STATE_DRAIN_GOING_DOWN]      = "DRAIN %d/%d,",
-                       [SRV_STATS_STATE_DRAIN]                 = "DRAIN,",
-                       [SRV_STATS_STATE_DRAIN_AGENT]           = "DRAIN (agent),",
-                       [SRV_STATS_STATE_NO_CHECK]              = "no check,"
-               };
-
-               chunk_appendf(&trash,
-                             /* pxid, name */
-                             "%s,%s,"
-                             /* queue : current, max */
-                             "%d,%d,"
-                             /* sessions : current, max, limit, total */
-                             "%d,%d,%s,%lld,"
-                             /* bytes : in, out */
-                             "%lld,%lld,"
-                             /* denied: req, resp */
-                             ",%lld,"
-                             /* errors : request, connect, response */
-                             ",%lld,%lld,"
-                             /* warnings: retries, redispatches */
-                             "%lld,%lld,"
-                             "",
-                             px->id, sv->id,
-                             sv->nbpend, sv->counters.nbpend_max,
-                             sv->cur_sess, sv->counters.cur_sess_max, LIM2A(sv->maxconn, ""), sv->counters.cum_sess,
-                             sv->counters.bytes_in, sv->counters.bytes_out,
-                             sv->counters.failed_secu,
-                             sv->counters.failed_conns, sv->counters.failed_resp,
-                             sv->counters.retries, sv->counters.redispatches);
-
-               /* status */
-               if (sv->admin & SRV_ADMF_IMAINT)
-                       chunk_appendf(&trash, "MAINT (via %s/%s),", via->proxy->id, via->id);
-               else if (sv->admin & SRV_ADMF_MAINT)
-                       chunk_appendf(&trash, "MAINT,");
-               else
-                       chunk_appendf(&trash,
-                                     srv_hlt_st[state],
-                                     (ref->state != SRV_ST_STOPPED) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
-                                     (ref->state != SRV_ST_STOPPED) ? (ref->check.fall) : (ref->check.rise));
-
-               chunk_appendf(&trash,
-                             /* weight, active, backup */
-                             "%d,%d,%d,"
-                             "",
-                             (sv->eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
-                             (sv->flags & SRV_F_BACKUP) ? 0 : 1,
-                             (sv->flags & SRV_F_BACKUP) ? 1 : 0);
-
-               /* check failures: unique, fatal; last change, total downtime */
-               if (sv->check.state & CHK_ST_ENABLED)
-                       chunk_appendf(&trash,
-                                     "%lld,%lld,%d,%d,",
-                                     sv->counters.failed_checks, sv->counters.down_trans,
-                                     (int)(now.tv_sec - sv->last_change), srv_downtime(sv));
-               else
-                       chunk_appendf(&trash, ",,,,");
-
-               /* queue limit, pid, iid, sid, */
-               chunk_appendf(&trash,
-                             "%s,"
-                             "%d,%d,%d,",
-                             LIM2A(sv->maxqueue, ""),
-                             relative_pid, px->uuid, sv->puid);
-
-               /* throttle */
-               if (sv->state == SRV_ST_STARTING && !server_is_draining(sv))
-                       chunk_appendf(&trash, "%d", server_throttle_rate(sv));
-
-               /* sessions: lbtot */
-               chunk_appendf(&trash, ",%lld,", sv->counters.cum_lbconn);
-
-               /* tracked */
-               if (sv->track)
-                       chunk_appendf(&trash, "%s/%s,",
-                                     sv->track->proxy->id, sv->track->id);
-               else
-                       chunk_appendf(&trash, ",");
-
-               /* type */
-               chunk_appendf(&trash, "%d,", STATS_TYPE_SV);
-
-               /* rate */
-               chunk_appendf(&trash, "%u,,%u,",
-                             read_freq_ctr(&sv->sess_per_sec),
-                             sv->counters.sps_max);
-
-               if (sv->check.state & CHK_ST_ENABLED) {
-                       /* check_status */
-                       chunk_appendf(&trash, "%s,", csv_enc(get_check_status_info(sv->check.status), 1, out));
-
-                       /* check_code */
-                       if (sv->check.status >= HCHK_STATUS_L57DATA)
-                               chunk_appendf(&trash, "%u,", sv->check.code);
-                       else
-                               chunk_appendf(&trash, ",");
-
-                       /* check_duration */
-                       if (sv->check.status >= HCHK_STATUS_CHECKED)
-                               chunk_appendf(&trash, "%lu,", sv->check.duration);
-                       else
-                               chunk_appendf(&trash, ",");
-
-               }
-               else
-                       chunk_appendf(&trash, ",,,");
-
-               /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
-               if (px->mode == PR_MODE_HTTP) {
-                       for (i=1; i<6; i++)
-                               chunk_appendf(&trash, "%lld,", sv->counters.p.http.rsp[i]);
-
-                       chunk_appendf(&trash, "%lld,", sv->counters.p.http.rsp[0]);
-               }
-               else
-                       chunk_appendf(&trash, ",,,,,,");
-
-               /* failed health analyses */
-               chunk_appendf(&trash, "%lld,",  sv->counters.failed_hana);
-
-               /* requests : req_rate, req_rate_max, req_tot, */
-               chunk_appendf(&trash, ",,,");
-
-               /* errors: cli_aborts, srv_aborts */
-               chunk_appendf(&trash, "%lld,%lld,",
-                             sv->counters.cli_aborts, sv->counters.srv_aborts);
-
-               /* compression: in, out, bypassed, comp_rsp */
-               chunk_appendf(&trash, ",,,,");
-
-               /* lastsess */
-               chunk_appendf(&trash, "%d,", srv_lastsession(sv));
-
-               /* capture of last check and agent statuses */
-               chunk_appendf(&trash, "%s,", ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) ? csv_enc(cstr(sv->check.desc), 1, out) : "");
-               chunk_appendf(&trash, "%s,", ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) ? csv_enc(cstr(sv->agent.desc), 1, out) : "");
-
-               /* qtime, ctime, rtime, ttime, */
-               chunk_appendf(&trash, "%u,%u,%u,%u,",
-                             swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES),
-                             swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES),
-                             swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES),
-                             swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES));
-
-               /* finish with EOL */
-               chunk_appendf(&trash, "\n");
+               /* dump everything */
+               stats_dump_fields_csv(&trash, stats);
        }
        return 1;
 }