From 42b18fb64522a20f58997782ccddc310c09958d8 Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Thu, 15 Dec 2022 14:17:09 +0100 Subject: [PATCH] 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 --- src/stats.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/stats.c b/src/stats.c index 1a9f26325..ff49d15b8 100644 --- a/src/stats.c +++ b/src/stats.c @@ -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 into using the HTML format. A column is