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.
This commit is contained in:
Amaury Denoyelle 2020-10-05 11:49:39 +02:00 committed by Christopher Faulet
parent 72b16e5173
commit 50660a894d
2 changed files with 32 additions and 9 deletions

View File

@ -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 do not insert any column before these ones in order not to break tools which
use hard-coded column positions. use hard-coded column positions.
In brackets after each field name are the types which may have a value for For proxy statistics, after each field name, the types which may have a value
that field. The types are L (Listeners), F (Frontends), B (Backends), and for that field are specified in brackets. The types are L (Listeners), F
S (Servers). (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 0. pxname [LFBS]: proxy name
1. svname [LFBS]: service name (FRONTEND for frontend, BACKEND for backend, 1. svname [LFBS]: service name (FRONTEND for frontend, BACKEND for backend,
any name for server/listener) any name for server/listener)
@ -1122,6 +1126,9 @@ S (Servers).
93. ttime_max [..BS]: the maximum observed total session time in ms 93. ttime_max [..BS]: the maximum observed total session time in ms
94. eint [LFBS]: cumulative number of internal errors 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 9.2) Typed output format
------------------------ ------------------------

View File

@ -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, * 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. * 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; int field;
chunk_appendf(&trash, "# "); 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); 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"); 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 <stats> into <out> using CSV format */ /* Dump all fields from <stats> into <out> using CSV format */
static int stats_dump_fields_csv(struct buffer *out, static int stats_dump_fields_csv(struct buffer *out,
const struct field *stats, size_t stats_count, const struct field *stats, size_t stats_count,
unsigned int flags) unsigned int flags,
enum stats_domain domain)
{ {
int field; 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])) if (!stats_emit_raw_data_field(out, &stats[field]))
return 0; return 0;
if (!chunk_strcat(out, ",")) if (!chunk_strcat(out, ","))
return 0; 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"); chunk_strcat(out, "\n");
return 1; 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) 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); ret = stats_dump_fields_json(&trash, stats, stats_count, appctx->ctx.stats.flags, appctx->ctx.stats.domain);
else 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) if (ret)
appctx->ctx.stats.flags |= STAT_STARTED; 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) else if (appctx->ctx.stats.flags & STAT_FMT_JSON)
stats_dump_json_header(); stats_dump_json_header();
else if (!(appctx->ctx.stats.flags & STAT_FMT_TYPED)) 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)) if (!stats_putchk(rep, htx, &trash))
goto full; goto full;