BUG/MINOR: stats: fix show stat json buffer limitation

json output type is a lot more verbose than other output types.
Because of this and the increasing number of metrics implemented within
haproxy, we are starting to reach max bufsize limit (defaults to 16k)
when dumping stats to json since 2.6-dev1.
This results in stats output being truncated with
    "[{"errorStr":"output buffer too short"}]"

This was reported by Gabriel in #1964.

Thanks to "MINOR: stats: introduce stats field ctx", we can now make
multipart (using multiple buffers) dumping, in case a single buffer is not big
enough to hold the complete stat line.
For now, only stats_dump_fields_json() makes use of it as it is by
far the most verbose stats output type.
(csv, typed and html outputs should be good for a while and may use this
capability if the need arises in some distant future)

--

It could be backported to 2.6 and 2.7.
This commit depends on:
  - MINOR: stats: provide ctx for dumping functions
  - MINOR: stats: introduce stats field ctx
This commit is contained in:
Aurelien DARRAGON 2022-12-15 14:17:09 +01:00 committed by Willy Tarreau
parent 5594184190
commit 42b18fb645

View File

@ -753,16 +753,17 @@ static int stats_dump_fields_json(struct buffer *out,
{
int flags = ctx->flags;
int domain = ctx->domain;
int field;
int started = 0;
int started = (ctx->field) ? 1 : 0;
int ready_data = 0;
if ((flags & STAT_STARTED) && !chunk_strcat(out, ","))
if (!started && (flags & STAT_STARTED) && !chunk_strcat(out, ","))
return 0;
if (!chunk_strcat(out, "["))
if (!started && !chunk_strcat(out, "["))
return 0;
for (field = 0; field < stats_count; field++) {
for (; ctx->field < stats_count; ctx->field++) {
int old_len;
int field = ctx->field;
if (!stats[field].type)
continue;
@ -797,19 +798,27 @@ static int stats_dump_fields_json(struct buffer *out,
if (!chunk_strcat(out, "}"))
goto err;
ready_data = out->data;
}
if (!chunk_strcat(out, "]"))
goto err;
ctx->field = 0; /* we're done */
return 1;
err:
chunk_reset(out);
if (flags & STAT_STARTED)
chunk_strcat(out, ",");
chunk_appendf(out, "{\"errorStr\":\"output buffer too short\"}");
return 0;
if (!ready_data) {
/* not enough buffer space for a single entry.. */
chunk_reset(out);
if (ctx->flags & STAT_STARTED)
chunk_strcat(out, ",");
chunk_appendf(out, "{\"errorStr\":\"output buffer too short\"}");
return 0; /* hard error */
}
/* push ready data and wait for a new buffer to complete the dump */
out->data = ready_data;
return 1;
}
/* Dump all fields from <stats> into <out> using the HTML format. A column is