From: Amaury Denoyelle Date: Mon, 5 Oct 2020 09:49:39 +0000 (+0200) Subject: MEDIUM: stats: add delimiter for static proxy stats on csv X-Git-Tag: v2.3-dev6~102 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=50660a894d533e7ed448df87acbe74c978de8db4;p=thirdparty%2Fhaproxy.git MEDIUM: stats: add delimiter for static proxy stats on csv Use the character '-' to mark the end of static statistics on proxy domain. After this marker, the order of the fields is not guaranteed and should be parsed with care. --- diff --git a/doc/management.txt b/doc/management.txt index 9a749e48a3..151c96ed8d 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -961,10 +961,14 @@ text is doubled ('""'), which is the format that most tools recognize. Please do not insert any column before these ones in order not to break tools which use hard-coded column positions. -In brackets after each field name are the types which may have a value for -that field. The types are L (Listeners), F (Frontends), B (Backends), and -S (Servers). - +For proxy statistics, after each field name, the types which may have a value +for that field are specified in brackets. The types are L (Listeners), F +(Frontends), B (Backends), and S (Servers). There is a fixed set of static +fields that are always available in the same order. A column containing the +character '-' delimits the end of the static fields, after which presence or +order of the fields are not guaranteed. + +Here is the list of static fields using the proxy statistics domain: 0. pxname [LFBS]: proxy name 1. svname [LFBS]: service name (FRONTEND for frontend, BACKEND for backend, any name for server/listener) @@ -1122,6 +1126,9 @@ S (Servers). 93. ttime_max [..BS]: the maximum observed total session time in ms 94. eint [LFBS]: cumulative number of internal errors +For all other statistics domains, the presence or the order of the fields are +not guaranteed. In this case, the header line should always be used to parse +the CSV data. 9.2) Typed output format ------------------------ diff --git a/src/stats.c b/src/stats.c index 6ab1c06c58..ed0abc7b29 100644 --- a/src/stats.c +++ b/src/stats.c @@ -324,14 +324,21 @@ static const char *stats_scope_ptr(struct appctx *appctx, struct stream_interfac * NOTE: Some tools happen to rely on the field position instead of its name, * so please only append new fields at the end, never in the middle. */ -static void stats_dump_csv_header() +static void stats_dump_csv_header(enum stats_domain domain) { int field; chunk_appendf(&trash, "# "); - for (field = 0; field < ST_F_TOTAL_FIELDS; field++) + for (field = 0; field < ST_F_TOTAL_FIELDS; field++) { chunk_appendf(&trash, "%s,", stat_fields[field].name); + /* print special delimiter on proxy stats to mark end of + static fields */ + if (domain == STATS_DOMAIN_PROXY && field + 1 == ST_F_TOTAL_FIELDS) { + chunk_appendf(&trash, "-,"); + } + } + chunk_appendf(&trash, "\n"); } @@ -523,16 +530,25 @@ int stats_emit_json_field_tags(struct buffer *out, const struct field *f) /* Dump all fields from into using CSV format */ static int stats_dump_fields_csv(struct buffer *out, const struct field *stats, size_t stats_count, - unsigned int flags) + unsigned int flags, + enum stats_domain domain) { int field; - for (field = 0; field < stats_count; field++) { + for (field = 0; field < stats_count; ++field) { if (!stats_emit_raw_data_field(out, &stats[field])) return 0; if (!chunk_strcat(out, ",")) return 0; + + /* print special delimiter on proxy stats to mark end of + static fields */ + if (domain == STATS_DOMAIN_PROXY && field + 1 == ST_F_TOTAL_FIELDS) { + if (!chunk_strcat(out, "-,")) + return 0; + } } + chunk_strcat(out, "\n"); return 1; } @@ -1435,7 +1451,7 @@ int stats_dump_one_line(const struct field *stats, size_t stats_count, else if (appctx->ctx.stats.flags & STAT_FMT_JSON) ret = stats_dump_fields_json(&trash, stats, stats_count, appctx->ctx.stats.flags, appctx->ctx.stats.domain); else - ret = stats_dump_fields_csv(&trash, stats, stats_count, appctx->ctx.stats.flags); + ret = stats_dump_fields_csv(&trash, stats, stats_count, appctx->ctx.stats.flags, appctx->ctx.stats.domain); if (ret) appctx->ctx.stats.flags |= STAT_STARTED; @@ -2837,7 +2853,7 @@ static int stats_dump_stat_to_buffer(struct stream_interface *si, struct htx *ht else if (appctx->ctx.stats.flags & STAT_FMT_JSON) stats_dump_json_header(); else if (!(appctx->ctx.stats.flags & STAT_FMT_TYPED)) - stats_dump_csv_header(); + stats_dump_csv_header(appctx->ctx.stats.domain); if (!stats_putchk(rep, htx, &trash)) goto full;