]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: stats: extract JSON related functions
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 16 Apr 2024 12:57:54 +0000 (14:57 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 18 Apr 2024 15:04:08 +0000 (17:04 +0200)
This commit is similar to the previous one. This time it deals with
functions related to stats JSON output.

Makefile
include/haproxy/stats-json.h [new file with mode: 0644]
include/haproxy/stats.h
src/stats-json.c [new file with mode: 0644]
src/stats.c

index b97d69b7bd2ac7b13a7d529a844a216ee334689d..57be1b145b4b0adc1f9dc31ccb27cf0684d17a1f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -975,7 +975,7 @@ OBJS += src/mux_h2.o src/mux_fcgi.o src/mux_h1.o src/tcpcheck.o               \
         src/dynbuf.o src/wdt.o src/pipe.o src/init.o src/http_acl.o           \
         src/hpack-huff.o src/hpack-enc.o src/dict.o src/freq_ctr.o            \
         src/ebtree.o src/hash.o src/dgram.o src/version.o src/proto_rhttp.o   \
-        src/guid.o src/stats-html.o
+        src/guid.o src/stats-html.o src/stats-json.o
 
 ifneq ($(TRACE),)
   OBJS += src/calltrace.o
diff --git a/include/haproxy/stats-json.h b/include/haproxy/stats-json.h
new file mode 100644 (file)
index 0000000..d6c4382
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _HAPROXY_STATS_JSON_H
+#define _HAPROXY_STATS_JSON_H
+
+#include <haproxy/applet-t.h>
+#include <haproxy/buf-t.h>
+#include <haproxy/stats-t.h>
+
+void stats_dump_json_header(struct buffer *out);
+
+int stats_dump_fields_json(struct buffer *out,
+                           const struct field *stats, size_t stats_count,
+                           struct show_stat_ctx *ctx);
+
+void stats_dump_json_end(struct buffer *out);
+
+int stats_dump_json_info_fields(struct buffer *out,
+                                const struct field *info,
+                                struct show_stat_ctx *ctx);
+
+void stats_dump_json_schema(struct buffer *out);
+
+int stats_dump_json_schema_to_buffer(struct appctx *appctx);
+
+#endif /* _HAPROXY_STATS_JSON_H */
index 6affd5e95f4e151f0334ecec6cac4b40bc0eb201..e86c1299d0a7c566702d797f4195277b05a6f7ca 100644 (file)
@@ -45,6 +45,7 @@ extern struct applet http_stats_applet;
 extern struct list stats_module_list[];
 extern THREAD_LOCAL struct field info[];
 extern THREAD_LOCAL struct field *stat_l[];
+extern struct name_desc *stat_f[STATS_DOMAIN_COUNT];
 
 struct htx;
 int stats_putchk(struct appctx *appctx, struct buffer *buf, struct htx *htx);
diff --git a/src/stats-json.c b/src/stats-json.c
new file mode 100644 (file)
index 0000000..454e018
--- /dev/null
@@ -0,0 +1,533 @@
+#include <haproxy/stats-json.h>
+
+#include <stdio.h>
+
+#include <haproxy/applet.h>
+#include <haproxy/buf.h>
+#include <haproxy/chunk.h>
+#include <haproxy/stats.h>
+
+/* Emits an encoding of the field type as JSON.
+  * Returns non-zero on success, 0 if the buffer is full.
+  */
+static int stats_emit_json_field_tags(struct buffer *out, const struct field *f)
+{
+       const char *origin, *nature, *scope;
+       int old_len;
+
+       switch (field_origin(f, 0)) {
+       case FO_METRIC:  origin = "Metric";  break;
+       case FO_STATUS:  origin = "Status";  break;
+       case FO_KEY:     origin = "Key";     break;
+       case FO_CONFIG:  origin = "Config";  break;
+       case FO_PRODUCT: origin = "Product"; break;
+       default:         origin = "Unknown"; break;
+       }
+
+       switch (field_nature(f, 0)) {
+       case FN_GAUGE:    nature = "Gauge";    break;
+       case FN_LIMIT:    nature = "Limit";    break;
+       case FN_MIN:      nature = "Min";      break;
+       case FN_MAX:      nature = "Max";      break;
+       case FN_RATE:     nature = "Rate";     break;
+       case FN_COUNTER:  nature = "Counter";  break;
+       case FN_DURATION: nature = "Duration"; break;
+       case FN_AGE:      nature = "Age";      break;
+       case FN_TIME:     nature = "Time";     break;
+       case FN_NAME:     nature = "Name";     break;
+       case FN_OUTPUT:   nature = "Output";   break;
+       case FN_AVG:      nature = "Avg";      break;
+       default:          nature = "Unknown";  break;
+       }
+
+       switch (field_scope(f, 0)) {
+       case FS_PROCESS: scope = "Process"; break;
+       case FS_SERVICE: scope = "Service"; break;
+       case FS_SYSTEM:  scope = "System";  break;
+       case FS_CLUSTER: scope = "Cluster"; break;
+       default:         scope = "Unknown"; break;
+       }
+
+       old_len = out->data;
+       chunk_appendf(out, "\"tags\":{"
+                           "\"origin\":\"%s\","
+                           "\"nature\":\"%s\","
+                           "\"scope\":\"%s\""
+                          "}", origin, nature, scope);
+       return !(old_len == out->data);
+}
+
+/* Limit JSON integer values to the range [-(2**53)+1, (2**53)-1] as per
+ * the recommendation for interoperable integers in section 6 of RFC 7159.
+ */
+#define JSON_INT_MAX ((1ULL << 53) - 1)
+#define JSON_INT_MIN (0 - JSON_INT_MAX)
+
+/* Emits a stats field value and its type in JSON.
+ * Returns non-zero on success, 0 on error.
+ */
+static int stats_emit_json_data_field(struct buffer *out, const struct field *f)
+{
+       int old_len;
+       char buf[20];
+       const char *type, *value = buf, *quote = "";
+
+       switch (field_format(f, 0)) {
+       case FF_EMPTY: return 1;
+       case FF_S32:   type = "\"s32\"";
+                      snprintf(buf, sizeof(buf), "%d", f->u.s32);
+                      break;
+       case FF_U32:   type = "\"u32\"";
+                      snprintf(buf, sizeof(buf), "%u", f->u.u32);
+                      break;
+       case FF_S64:   type = "\"s64\"";
+                      if (f->u.s64 < JSON_INT_MIN || f->u.s64 > JSON_INT_MAX)
+                              return 0;
+                      type = "\"s64\"";
+                      snprintf(buf, sizeof(buf), "%lld", (long long)f->u.s64);
+                      break;
+       case FF_U64:   if (f->u.u64 > JSON_INT_MAX)
+                              return 0;
+                      type = "\"u64\"";
+                      snprintf(buf, sizeof(buf), "%llu",
+                               (unsigned long long) f->u.u64);
+                      break;
+       case FF_FLT:   type = "\"flt\"";
+                      flt_trim(buf, 0, snprintf(buf, sizeof(buf), "%f", f->u.flt));
+                      break;
+       case FF_STR:   type = "\"str\"";
+                      value = field_str(f, 0);
+                      quote = "\"";
+                      break;
+       default:       snprintf(buf, sizeof(buf), "%u", f->type);
+                      type = buf;
+                      value = "unknown";
+                      quote = "\"";
+                      break;
+       }
+
+       old_len = out->data;
+       chunk_appendf(out, ",\"value\":{\"type\":%s,\"value\":%s%s%s}",
+                     type, quote, value, quote);
+       return !(old_len == out->data);
+}
+
+static void stats_print_proxy_field_json(struct buffer *out,
+                                         const struct field *stat,
+                                         const char *name,
+                                         int pos,
+                                         uint32_t field_type,
+                                         uint32_t iid,
+                                         uint32_t sid,
+                                         uint32_t pid)
+{
+       const char *obj_type;
+       switch (field_type) {
+               case STATS_TYPE_FE: obj_type = "Frontend"; break;
+               case STATS_TYPE_BE: obj_type = "Backend";  break;
+               case STATS_TYPE_SO: obj_type = "Listener"; break;
+               case STATS_TYPE_SV: obj_type = "Server";   break;
+               default:            obj_type = "Unknown";  break;
+       }
+
+       chunk_appendf(out,
+                     "{"
+                     "\"objType\":\"%s\","
+                     "\"proxyId\":%u,"
+                     "\"id\":%u,"
+                     "\"field\":{\"pos\":%d,\"name\":\"%s\"},"
+                     "\"processNum\":%u,",
+                     obj_type, iid, sid, pos, name, pid);
+}
+
+static void stats_print_rslv_field_json(struct buffer *out,
+                                        const struct field *stat,
+                                        const char *name,
+                                        int pos)
+{
+       chunk_appendf(out,
+                     "{"
+                     "\"field\":{\"pos\":%d,\"name\":\"%s\"},",
+                     pos, name);
+}
+
+
+/* Dumps the stats JSON header to <out> buffer. The caller is responsible for
+ * clearing it if needed.
+ */
+void stats_dump_json_header(struct buffer *out)
+{
+       chunk_strcat(out, "[");
+}
+
+/* Dump all fields from <stats> into <out> using a typed "field:desc:type:value" format */
+int stats_dump_fields_json(struct buffer *out,
+                           const struct field *stats, size_t stats_count,
+                           struct show_stat_ctx *ctx)
+{
+       int flags = ctx->flags;
+       int domain = ctx->domain;
+       int started = (ctx->field) ? 1 : 0;
+       int ready_data = 0;
+
+       if (!started && (flags & STAT_STARTED) && !chunk_strcat(out, ","))
+               return 0;
+       if (!started && !chunk_strcat(out, "["))
+               return 0;
+
+       for (; ctx->field < stats_count; ctx->field++) {
+               int old_len;
+               int field = ctx->field;
+
+               if (!stats[field].type)
+                       continue;
+
+               if (started && !chunk_strcat(out, ","))
+                       goto err;
+               started = 1;
+
+               old_len = out->data;
+               if (domain == STATS_DOMAIN_PROXY) {
+                       stats_print_proxy_field_json(out, &stats[field],
+                                                    stat_f[domain][field].name,
+                                                    field,
+                                                    stats[ST_F_TYPE].u.u32,
+                                                    stats[ST_F_IID].u.u32,
+                                                    stats[ST_F_SID].u.u32,
+                                                    stats[ST_F_PID].u.u32);
+               } else if (domain == STATS_DOMAIN_RESOLVERS) {
+                       stats_print_rslv_field_json(out, &stats[field],
+                                                   stat_f[domain][field].name,
+                                                   field);
+               }
+
+               if (old_len == out->data)
+                       goto err;
+
+               if (!stats_emit_json_field_tags(out, &stats[field]))
+                       goto err;
+
+               if (!stats_emit_json_data_field(out, &stats[field]))
+                       goto err;
+
+               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:
+       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;
+}
+
+/* Dumps the JSON stats trailer block to <out> buffer. The caller is
+ * responsible for clearing it if needed.
+ */
+void stats_dump_json_end(struct buffer *out)
+{
+       chunk_strcat(out, "]\n");
+}
+
+/* Dump all fields from <stats> into <out> using the "show info json" format */
+int stats_dump_json_info_fields(struct buffer *out,
+                                const struct field *info,
+                                struct show_stat_ctx *ctx)
+{
+       int started = (ctx->field) ? 1 : 0;
+       int ready_data = 0;
+
+       if (!started && !chunk_strcat(out, "["))
+               return 0;
+
+       for (; ctx->field < INF_TOTAL_FIELDS; ctx->field++) {
+               int old_len;
+               int field = ctx->field;
+
+               if (!field_format(info, field))
+                       continue;
+
+               if (started && !chunk_strcat(out, ","))
+                       goto err;
+               started = 1;
+
+               old_len = out->data;
+               chunk_appendf(out,
+                             "{\"field\":{\"pos\":%d,\"name\":\"%s\"},"
+                             "\"processNum\":%u,",
+                             field, info_fields[field].name,
+                             info[INF_PROCESS_NUM].u.u32);
+               if (old_len == out->data)
+                       goto err;
+
+               if (!stats_emit_json_field_tags(out, &info[field]))
+                       goto err;
+
+               if (!stats_emit_json_data_field(out, &info[field]))
+                       goto err;
+
+               if (!chunk_strcat(out, "}"))
+                       goto err;
+               ready_data = out->data;
+       }
+
+       if (!chunk_strcat(out, "]\n"))
+               goto err;
+       ctx->field = 0; /* we're done */
+       return 1;
+
+err:
+       if (!ready_data) {
+               /* not enough buffer space for a single entry.. */
+               chunk_reset(out);
+               chunk_appendf(out, "{\"errorStr\":\"output buffer too short\"}\n");
+               return 0; /* hard error */
+       }
+       /* push ready data and wait for a new buffer to complete the dump */
+       out->data = ready_data;
+       return 1;
+}
+
+/* This function dumps the schema onto the stream connector's read buffer.
+ * It returns 0 as long as it does not complete, non-zero upon completion.
+ * No state is used.
+ *
+ * Integer values bounded to the range [-(2**53)+1, (2**53)-1] as
+ * per the recommendation for interoperable integers in section 6 of RFC 7159.
+ */
+void stats_dump_json_schema(struct buffer *out)
+{
+
+       int old_len = out->data;
+
+       chunk_strcat(out,
+                    "{"
+                     "\"$schema\":\"http://json-schema.org/draft-04/schema#\","
+                     "\"oneOf\":["
+                      "{"
+                       "\"title\":\"Info\","
+                       "\"type\":\"array\","
+                       "\"items\":{"
+                        "\"title\":\"InfoItem\","
+                        "\"type\":\"object\","
+                        "\"properties\":{"
+                         "\"field\":{\"$ref\":\"#/definitions/field\"},"
+                         "\"processNum\":{\"$ref\":\"#/definitions/processNum\"},"
+                         "\"tags\":{\"$ref\":\"#/definitions/tags\"},"
+                         "\"value\":{\"$ref\":\"#/definitions/typedValue\"}"
+                        "},"
+                        "\"required\":[\"field\",\"processNum\",\"tags\","
+                                      "\"value\"]"
+                       "}"
+                      "},"
+                      "{"
+                       "\"title\":\"Stat\","
+                       "\"type\":\"array\","
+                       "\"items\":{"
+                        "\"title\":\"InfoItem\","
+                        "\"type\":\"object\","
+                        "\"properties\":{"
+                         "\"objType\":{"
+                          "\"enum\":[\"Frontend\",\"Backend\",\"Listener\","
+                                    "\"Server\",\"Unknown\"]"
+                         "},"
+                         "\"proxyId\":{"
+                          "\"type\":\"integer\","
+                          "\"minimum\":0"
+                         "},"
+                         "\"id\":{"
+                          "\"type\":\"integer\","
+                          "\"minimum\":0"
+                         "},"
+                         "\"field\":{\"$ref\":\"#/definitions/field\"},"
+                         "\"processNum\":{\"$ref\":\"#/definitions/processNum\"},"
+                         "\"tags\":{\"$ref\":\"#/definitions/tags\"},"
+                         "\"typedValue\":{\"$ref\":\"#/definitions/typedValue\"}"
+                        "},"
+                        "\"required\":[\"objType\",\"proxyId\",\"id\","
+                                      "\"field\",\"processNum\",\"tags\","
+                                      "\"value\"]"
+                       "}"
+                      "},"
+                      "{"
+                       "\"title\":\"Error\","
+                       "\"type\":\"object\","
+                       "\"properties\":{"
+                        "\"errorStr\":{"
+                         "\"type\":\"string\""
+                        "}"
+                       "},"
+                       "\"required\":[\"errorStr\"]"
+                      "}"
+                     "],"
+                     "\"definitions\":{"
+                      "\"field\":{"
+                       "\"type\":\"object\","
+                       "\"pos\":{"
+                        "\"type\":\"integer\","
+                        "\"minimum\":0"
+                       "},"
+                       "\"name\":{"
+                        "\"type\":\"string\""
+                       "},"
+                       "\"required\":[\"pos\",\"name\"]"
+                      "},"
+                      "\"processNum\":{"
+                       "\"type\":\"integer\","
+                       "\"minimum\":1"
+                      "},"
+                      "\"tags\":{"
+                       "\"type\":\"object\","
+                       "\"origin\":{"
+                        "\"type\":\"string\","
+                        "\"enum\":[\"Metric\",\"Status\",\"Key\","
+                                  "\"Config\",\"Product\",\"Unknown\"]"
+                       "},"
+                       "\"nature\":{"
+                        "\"type\":\"string\","
+                        "\"enum\":[\"Gauge\",\"Limit\",\"Min\",\"Max\","
+                                  "\"Rate\",\"Counter\",\"Duration\","
+                                  "\"Age\",\"Time\",\"Name\",\"Output\","
+                                  "\"Avg\", \"Unknown\"]"
+                       "},"
+                       "\"scope\":{"
+                        "\"type\":\"string\","
+                        "\"enum\":[\"Cluster\",\"Process\",\"Service\","
+                                  "\"System\",\"Unknown\"]"
+                       "},"
+                       "\"required\":[\"origin\",\"nature\",\"scope\"]"
+                      "},"
+                      "\"typedValue\":{"
+                       "\"type\":\"object\","
+                       "\"oneOf\":["
+                        "{\"$ref\":\"#/definitions/typedValue/definitions/s32Value\"},"
+                        "{\"$ref\":\"#/definitions/typedValue/definitions/s64Value\"},"
+                        "{\"$ref\":\"#/definitions/typedValue/definitions/u32Value\"},"
+                        "{\"$ref\":\"#/definitions/typedValue/definitions/u64Value\"},"
+                        "{\"$ref\":\"#/definitions/typedValue/definitions/strValue\"}"
+                       "],"
+                       "\"definitions\":{"
+                        "\"s32Value\":{"
+                         "\"properties\":{"
+                          "\"type\":{"
+                           "\"type\":\"string\","
+                           "\"enum\":[\"s32\"]"
+                          "},"
+                          "\"value\":{"
+                           "\"type\":\"integer\","
+                           "\"minimum\":-2147483648,"
+                           "\"maximum\":2147483647"
+                          "}"
+                         "},"
+                         "\"required\":[\"type\",\"value\"]"
+                        "},"
+                        "\"s64Value\":{"
+                         "\"properties\":{"
+                          "\"type\":{"
+                           "\"type\":\"string\","
+                           "\"enum\":[\"s64\"]"
+                          "},"
+                          "\"value\":{"
+                           "\"type\":\"integer\","
+                           "\"minimum\":-9007199254740991,"
+                           "\"maximum\":9007199254740991"
+                          "}"
+                         "},"
+                         "\"required\":[\"type\",\"value\"]"
+                        "},"
+                        "\"u32Value\":{"
+                         "\"properties\":{"
+                          "\"type\":{"
+                           "\"type\":\"string\","
+                           "\"enum\":[\"u32\"]"
+                          "},"
+                          "\"value\":{"
+                           "\"type\":\"integer\","
+                           "\"minimum\":0,"
+                           "\"maximum\":4294967295"
+                          "}"
+                         "},"
+                         "\"required\":[\"type\",\"value\"]"
+                        "},"
+                        "\"u64Value\":{"
+                         "\"properties\":{"
+                          "\"type\":{"
+                           "\"type\":\"string\","
+                           "\"enum\":[\"u64\"]"
+                          "},"
+                          "\"value\":{"
+                           "\"type\":\"integer\","
+                           "\"minimum\":0,"
+                           "\"maximum\":9007199254740991"
+                          "}"
+                         "},"
+                         "\"required\":[\"type\",\"value\"]"
+                        "},"
+                        "\"strValue\":{"
+                         "\"properties\":{"
+                          "\"type\":{"
+                           "\"type\":\"string\","
+                           "\"enum\":[\"str\"]"
+                          "},"
+                          "\"value\":{\"type\":\"string\"}"
+                         "},"
+                         "\"required\":[\"type\",\"value\"]"
+                        "},"
+                        "\"unknownValue\":{"
+                         "\"properties\":{"
+                          "\"type\":{"
+                           "\"type\":\"integer\","
+                           "\"minimum\":0"
+                          "},"
+                          "\"value\":{"
+                           "\"type\":\"string\","
+                           "\"enum\":[\"unknown\"]"
+                          "}"
+                         "},"
+                         "\"required\":[\"type\",\"value\"]"
+                        "}"
+                       "}"
+                      "}"
+                     "}"
+                    "}");
+
+       if (old_len == out->data) {
+               chunk_reset(out);
+               chunk_appendf(out,
+                             "{\"errorStr\":\"output buffer too short\"}");
+       }
+       chunk_appendf(out, "\n");
+}
+
+/* This function dumps the schema onto the stream connector's read buffer.
+ * It returns 0 as long as it does not complete, non-zero upon completion.
+ * No state is used.
+ */
+int stats_dump_json_schema_to_buffer(struct appctx *appctx)
+{
+       struct show_stat_ctx *ctx = appctx->svcctx;
+       struct buffer *chk = &ctx->chunk;
+
+       chunk_reset(chk);
+
+       stats_dump_json_schema(chk);
+
+       if (applet_putchk(appctx, chk) == -1)
+               return 0;
+
+       return 1;
+}
index fa035f016decd9adf834748337e9b5f7c724c5c6..df87c45b1f62d6a9f998cff080bb699e60661b32 100644 (file)
@@ -58,6 +58,7 @@
 #include <haproxy/session.h>
 #include <haproxy/stats.h>
 #include <haproxy/stats-html.h>
+#include <haproxy/stats-json.h>
 #include <haproxy/stconn.h>
 #include <haproxy/stream.h>
 #include <haproxy/task.h>
@@ -283,7 +284,7 @@ const struct name_desc stat_fields[ST_F_TOTAL_FIELDS] = {
 THREAD_LOCAL struct field info[INF_TOTAL_FIELDS];
 
 /* description of statistics (static and dynamic) */
-static struct name_desc *stat_f[STATS_DOMAIN_COUNT];
+struct name_desc *stat_f[STATS_DOMAIN_COUNT];
 static size_t stat_count[STATS_DOMAIN_COUNT];
 
 /* one line for stats */
@@ -298,8 +299,6 @@ struct list stats_module_list[STATS_DOMAIN_COUNT] = {
 THREAD_LOCAL void *trash_counters;
 
 
-static void stats_dump_json_schema(struct buffer *out);
-
 int stats_putchk(struct appctx *appctx, struct buffer *buf, struct htx *htx)
 {
        struct show_stat_ctx *ctx = appctx->svcctx;
@@ -458,61 +457,6 @@ int stats_emit_typed_data_field(struct buffer *out, const struct field *f)
        }
 }
 
-/* Limit JSON integer values to the range [-(2**53)+1, (2**53)-1] as per
- * the recommendation for interoperable integers in section 6 of RFC 7159.
- */
-#define JSON_INT_MAX ((1ULL << 53) - 1)
-#define JSON_INT_MIN (0 - JSON_INT_MAX)
-
-/* Emits a stats field value and its type in JSON.
- * Returns non-zero on success, 0 on error.
- */
-int stats_emit_json_data_field(struct buffer *out, const struct field *f)
-{
-       int old_len;
-       char buf[20];
-       const char *type, *value = buf, *quote = "";
-
-       switch (field_format(f, 0)) {
-       case FF_EMPTY: return 1;
-       case FF_S32:   type = "\"s32\"";
-                      snprintf(buf, sizeof(buf), "%d", f->u.s32);
-                      break;
-       case FF_U32:   type = "\"u32\"";
-                      snprintf(buf, sizeof(buf), "%u", f->u.u32);
-                      break;
-       case FF_S64:   type = "\"s64\"";
-                      if (f->u.s64 < JSON_INT_MIN || f->u.s64 > JSON_INT_MAX)
-                              return 0;
-                      type = "\"s64\"";
-                      snprintf(buf, sizeof(buf), "%lld", (long long)f->u.s64);
-                      break;
-       case FF_U64:   if (f->u.u64 > JSON_INT_MAX)
-                              return 0;
-                      type = "\"u64\"";
-                      snprintf(buf, sizeof(buf), "%llu",
-                               (unsigned long long) f->u.u64);
-                      break;
-       case FF_FLT:   type = "\"flt\"";
-                      flt_trim(buf, 0, snprintf(buf, sizeof(buf), "%f", f->u.flt));
-                      break;
-       case FF_STR:   type = "\"str\"";
-                      value = field_str(f, 0);
-                      quote = "\"";
-                      break;
-       default:       snprintf(buf, sizeof(buf), "%u", f->type);
-                      type = buf;
-                      value = "unknown";
-                      quote = "\"";
-                      break;
-       }
-
-       old_len = out->data;
-       chunk_appendf(out, ",\"value\":{\"type\":%s,\"value\":%s%s%s}",
-                     type, quote, value, quote);
-       return !(old_len == out->data);
-}
-
 /* Emits an encoding of the field type on 3 characters followed by a delimiter.
  * Returns non-zero on success, 0 if the buffer is full.
  */
@@ -557,56 +501,6 @@ int stats_emit_field_tags(struct buffer *out, const struct field *f,
        return chunk_appendf(out, "%c%c%c%c", origin, nature, scope, delim);
 }
 
-/* Emits an encoding of the field type as JSON.
-  * Returns non-zero on success, 0 if the buffer is full.
-  */
-int stats_emit_json_field_tags(struct buffer *out, const struct field *f)
-{
-       const char *origin, *nature, *scope;
-       int old_len;
-
-       switch (field_origin(f, 0)) {
-       case FO_METRIC:  origin = "Metric";  break;
-       case FO_STATUS:  origin = "Status";  break;
-       case FO_KEY:     origin = "Key";     break;
-       case FO_CONFIG:  origin = "Config";  break;
-       case FO_PRODUCT: origin = "Product"; break;
-       default:         origin = "Unknown"; break;
-       }
-
-       switch (field_nature(f, 0)) {
-       case FN_GAUGE:    nature = "Gauge";    break;
-       case FN_LIMIT:    nature = "Limit";    break;
-       case FN_MIN:      nature = "Min";      break;
-       case FN_MAX:      nature = "Max";      break;
-       case FN_RATE:     nature = "Rate";     break;
-       case FN_COUNTER:  nature = "Counter";  break;
-       case FN_DURATION: nature = "Duration"; break;
-       case FN_AGE:      nature = "Age";      break;
-       case FN_TIME:     nature = "Time";     break;
-       case FN_NAME:     nature = "Name";     break;
-       case FN_OUTPUT:   nature = "Output";   break;
-       case FN_AVG:      nature = "Avg";      break;
-       default:          nature = "Unknown";  break;
-       }
-
-       switch (field_scope(f, 0)) {
-       case FS_PROCESS: scope = "Process"; break;
-       case FS_SERVICE: scope = "Service"; break;
-       case FS_SYSTEM:  scope = "System";  break;
-       case FS_CLUSTER: scope = "Cluster"; break;
-       default:         scope = "Unknown"; break;
-       }
-
-       old_len = out->data;
-       chunk_appendf(out, "\"tags\":{"
-                           "\"origin\":\"%s\","
-                           "\"nature\":\"%s\","
-                           "\"scope\":\"%s\""
-                          "}", origin, nature, scope);
-       return !(old_len == out->data);
-}
-
 /* Dump all fields from <stats> into <out> using CSV format */
 static int stats_dump_fields_csv(struct buffer *out,
                                  const struct field *stats, size_t stats_count,
@@ -686,179 +580,6 @@ static int stats_dump_fields_typed(struct buffer *out,
        return 1;
 }
 
-/* Dump all fields from <stats> into <out> using the "show info json" format */
-static int stats_dump_json_info_fields(struct buffer *out,
-                                       const struct field *info,
-                                       struct show_stat_ctx *ctx)
-{
-       int started = (ctx->field) ? 1 : 0;
-       int ready_data = 0;
-
-       if (!started && !chunk_strcat(out, "["))
-               return 0;
-
-       for (; ctx->field < INF_TOTAL_FIELDS; ctx->field++) {
-               int old_len;
-               int field = ctx->field;
-
-               if (!field_format(info, field))
-                       continue;
-
-               if (started && !chunk_strcat(out, ","))
-                       goto err;
-               started = 1;
-
-               old_len = out->data;
-               chunk_appendf(out,
-                             "{\"field\":{\"pos\":%d,\"name\":\"%s\"},"
-                             "\"processNum\":%u,",
-                             field, info_fields[field].name,
-                             info[INF_PROCESS_NUM].u.u32);
-               if (old_len == out->data)
-                       goto err;
-
-               if (!stats_emit_json_field_tags(out, &info[field]))
-                       goto err;
-
-               if (!stats_emit_json_data_field(out, &info[field]))
-                       goto err;
-
-               if (!chunk_strcat(out, "}"))
-                       goto err;
-               ready_data = out->data;
-       }
-
-       if (!chunk_strcat(out, "]\n"))
-               goto err;
-       ctx->field = 0; /* we're done */
-       return 1;
-
-err:
-       if (!ready_data) {
-               /* not enough buffer space for a single entry.. */
-               chunk_reset(out);
-               chunk_appendf(out, "{\"errorStr\":\"output buffer too short\"}\n");
-               return 0; /* hard error */
-       }
-       /* push ready data and wait for a new buffer to complete the dump */
-       out->data = ready_data;
-       return 1;
-}
-
-static void stats_print_proxy_field_json(struct buffer *out,
-                                         const struct field *stat,
-                                         const char *name,
-                                         int pos,
-                                         uint32_t field_type,
-                                         uint32_t iid,
-                                         uint32_t sid,
-                                         uint32_t pid)
-{
-       const char *obj_type;
-       switch (field_type) {
-               case STATS_TYPE_FE: obj_type = "Frontend"; break;
-               case STATS_TYPE_BE: obj_type = "Backend";  break;
-               case STATS_TYPE_SO: obj_type = "Listener"; break;
-               case STATS_TYPE_SV: obj_type = "Server";   break;
-               default:            obj_type = "Unknown";  break;
-       }
-
-       chunk_appendf(out,
-                     "{"
-                     "\"objType\":\"%s\","
-                     "\"proxyId\":%u,"
-                     "\"id\":%u,"
-                     "\"field\":{\"pos\":%d,\"name\":\"%s\"},"
-                     "\"processNum\":%u,",
-                     obj_type, iid, sid, pos, name, pid);
-}
-
-static void stats_print_rslv_field_json(struct buffer *out,
-                                        const struct field *stat,
-                                        const char *name,
-                                        int pos)
-{
-       chunk_appendf(out,
-                     "{"
-                     "\"field\":{\"pos\":%d,\"name\":\"%s\"},",
-                     pos, name);
-}
-
-
-/* Dump all fields from <stats> into <out> using a typed "field:desc:type:value" format */
-static int stats_dump_fields_json(struct buffer *out,
-                                  const struct field *stats, size_t stats_count,
-                                  struct show_stat_ctx *ctx)
-{
-       int flags = ctx->flags;
-       int domain = ctx->domain;
-       int started = (ctx->field) ? 1 : 0;
-       int ready_data = 0;
-
-       if (!started && (flags & STAT_STARTED) && !chunk_strcat(out, ","))
-               return 0;
-       if (!started && !chunk_strcat(out, "["))
-               return 0;
-
-       for (; ctx->field < stats_count; ctx->field++) {
-               int old_len;
-               int field = ctx->field;
-
-               if (!stats[field].type)
-                       continue;
-
-               if (started && !chunk_strcat(out, ","))
-                       goto err;
-               started = 1;
-
-               old_len = out->data;
-               if (domain == STATS_DOMAIN_PROXY) {
-                       stats_print_proxy_field_json(out, &stats[field],
-                                                    stat_f[domain][field].name,
-                                                    field,
-                                                    stats[ST_F_TYPE].u.u32,
-                                                    stats[ST_F_IID].u.u32,
-                                                    stats[ST_F_SID].u.u32,
-                                                    stats[ST_F_PID].u.u32);
-               } else if (domain == STATS_DOMAIN_RESOLVERS) {
-                       stats_print_rslv_field_json(out, &stats[field],
-                                                   stat_f[domain][field].name,
-                                                   field);
-               }
-
-               if (old_len == out->data)
-                       goto err;
-
-               if (!stats_emit_json_field_tags(out, &stats[field]))
-                       goto err;
-
-               if (!stats_emit_json_data_field(out, &stats[field]))
-                       goto err;
-
-               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:
-       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;
-}
 
 int stats_dump_one_line(const struct field *stats, size_t stats_count,
                         struct appctx *appctx)
@@ -2408,23 +2129,6 @@ more:
        return 0;
 }
 
-/* Dumps the stats JSON header to <out> buffer. The caller is responsible for
- * clearing it if needed.
- */
-static void stats_dump_json_header(struct buffer *out)
-{
-       chunk_strcat(out, "[");
-}
-
-
-/* Dumps the JSON stats trailer block to <out> buffer. The caller is
- * responsible for clearing it if needed.
- */
-static void stats_dump_json_end(struct buffer *out)
-{
-       chunk_strcat(out, "]\n");
-}
-
 /* Uses <appctx.ctx.stats.obj1> as a pointer to the current proxy and <obj2> as
  * a pointer to the current server/listener.
  */
@@ -2793,236 +2497,6 @@ more:
        return 1;
 }
 
-/* This function dumps the schema onto the stream connector's read buffer.
- * It returns 0 as long as it does not complete, non-zero upon completion.
- * No state is used.
- *
- * Integer values bounded to the range [-(2**53)+1, (2**53)-1] as
- * per the recommendation for interoperable integers in section 6 of RFC 7159.
- */
-static void stats_dump_json_schema(struct buffer *out)
-{
-
-       int old_len = out->data;
-
-       chunk_strcat(out,
-                    "{"
-                     "\"$schema\":\"http://json-schema.org/draft-04/schema#\","
-                     "\"oneOf\":["
-                      "{"
-                       "\"title\":\"Info\","
-                       "\"type\":\"array\","
-                       "\"items\":{"
-                        "\"title\":\"InfoItem\","
-                        "\"type\":\"object\","
-                        "\"properties\":{"
-                         "\"field\":{\"$ref\":\"#/definitions/field\"},"
-                         "\"processNum\":{\"$ref\":\"#/definitions/processNum\"},"
-                         "\"tags\":{\"$ref\":\"#/definitions/tags\"},"
-                         "\"value\":{\"$ref\":\"#/definitions/typedValue\"}"
-                        "},"
-                        "\"required\":[\"field\",\"processNum\",\"tags\","
-                                      "\"value\"]"
-                       "}"
-                      "},"
-                      "{"
-                       "\"title\":\"Stat\","
-                       "\"type\":\"array\","
-                       "\"items\":{"
-                        "\"title\":\"InfoItem\","
-                        "\"type\":\"object\","
-                        "\"properties\":{"
-                         "\"objType\":{"
-                          "\"enum\":[\"Frontend\",\"Backend\",\"Listener\","
-                                    "\"Server\",\"Unknown\"]"
-                         "},"
-                         "\"proxyId\":{"
-                          "\"type\":\"integer\","
-                          "\"minimum\":0"
-                         "},"
-                         "\"id\":{"
-                          "\"type\":\"integer\","
-                          "\"minimum\":0"
-                         "},"
-                         "\"field\":{\"$ref\":\"#/definitions/field\"},"
-                         "\"processNum\":{\"$ref\":\"#/definitions/processNum\"},"
-                         "\"tags\":{\"$ref\":\"#/definitions/tags\"},"
-                         "\"typedValue\":{\"$ref\":\"#/definitions/typedValue\"}"
-                        "},"
-                        "\"required\":[\"objType\",\"proxyId\",\"id\","
-                                      "\"field\",\"processNum\",\"tags\","
-                                      "\"value\"]"
-                       "}"
-                      "},"
-                      "{"
-                       "\"title\":\"Error\","
-                       "\"type\":\"object\","
-                       "\"properties\":{"
-                        "\"errorStr\":{"
-                         "\"type\":\"string\""
-                        "}"
-                       "},"
-                       "\"required\":[\"errorStr\"]"
-                      "}"
-                     "],"
-                     "\"definitions\":{"
-                      "\"field\":{"
-                       "\"type\":\"object\","
-                       "\"pos\":{"
-                        "\"type\":\"integer\","
-                        "\"minimum\":0"
-                       "},"
-                       "\"name\":{"
-                        "\"type\":\"string\""
-                       "},"
-                       "\"required\":[\"pos\",\"name\"]"
-                      "},"
-                      "\"processNum\":{"
-                       "\"type\":\"integer\","
-                       "\"minimum\":1"
-                      "},"
-                      "\"tags\":{"
-                       "\"type\":\"object\","
-                       "\"origin\":{"
-                        "\"type\":\"string\","
-                        "\"enum\":[\"Metric\",\"Status\",\"Key\","
-                                  "\"Config\",\"Product\",\"Unknown\"]"
-                       "},"
-                       "\"nature\":{"
-                        "\"type\":\"string\","
-                        "\"enum\":[\"Gauge\",\"Limit\",\"Min\",\"Max\","
-                                  "\"Rate\",\"Counter\",\"Duration\","
-                                  "\"Age\",\"Time\",\"Name\",\"Output\","
-                                  "\"Avg\", \"Unknown\"]"
-                       "},"
-                       "\"scope\":{"
-                        "\"type\":\"string\","
-                        "\"enum\":[\"Cluster\",\"Process\",\"Service\","
-                                  "\"System\",\"Unknown\"]"
-                       "},"
-                       "\"required\":[\"origin\",\"nature\",\"scope\"]"
-                      "},"
-                      "\"typedValue\":{"
-                       "\"type\":\"object\","
-                       "\"oneOf\":["
-                        "{\"$ref\":\"#/definitions/typedValue/definitions/s32Value\"},"
-                        "{\"$ref\":\"#/definitions/typedValue/definitions/s64Value\"},"
-                        "{\"$ref\":\"#/definitions/typedValue/definitions/u32Value\"},"
-                        "{\"$ref\":\"#/definitions/typedValue/definitions/u64Value\"},"
-                        "{\"$ref\":\"#/definitions/typedValue/definitions/strValue\"}"
-                       "],"
-                       "\"definitions\":{"
-                        "\"s32Value\":{"
-                         "\"properties\":{"
-                          "\"type\":{"
-                           "\"type\":\"string\","
-                           "\"enum\":[\"s32\"]"
-                          "},"
-                          "\"value\":{"
-                           "\"type\":\"integer\","
-                           "\"minimum\":-2147483648,"
-                           "\"maximum\":2147483647"
-                          "}"
-                         "},"
-                         "\"required\":[\"type\",\"value\"]"
-                        "},"
-                        "\"s64Value\":{"
-                         "\"properties\":{"
-                          "\"type\":{"
-                           "\"type\":\"string\","
-                           "\"enum\":[\"s64\"]"
-                          "},"
-                          "\"value\":{"
-                           "\"type\":\"integer\","
-                           "\"minimum\":-9007199254740991,"
-                           "\"maximum\":9007199254740991"
-                          "}"
-                         "},"
-                         "\"required\":[\"type\",\"value\"]"
-                        "},"
-                        "\"u32Value\":{"
-                         "\"properties\":{"
-                          "\"type\":{"
-                           "\"type\":\"string\","
-                           "\"enum\":[\"u32\"]"
-                          "},"
-                          "\"value\":{"
-                           "\"type\":\"integer\","
-                           "\"minimum\":0,"
-                           "\"maximum\":4294967295"
-                          "}"
-                         "},"
-                         "\"required\":[\"type\",\"value\"]"
-                        "},"
-                        "\"u64Value\":{"
-                         "\"properties\":{"
-                          "\"type\":{"
-                           "\"type\":\"string\","
-                           "\"enum\":[\"u64\"]"
-                          "},"
-                          "\"value\":{"
-                           "\"type\":\"integer\","
-                           "\"minimum\":0,"
-                           "\"maximum\":9007199254740991"
-                          "}"
-                         "},"
-                         "\"required\":[\"type\",\"value\"]"
-                        "},"
-                        "\"strValue\":{"
-                         "\"properties\":{"
-                          "\"type\":{"
-                           "\"type\":\"string\","
-                           "\"enum\":[\"str\"]"
-                          "},"
-                          "\"value\":{\"type\":\"string\"}"
-                         "},"
-                         "\"required\":[\"type\",\"value\"]"
-                        "},"
-                        "\"unknownValue\":{"
-                         "\"properties\":{"
-                          "\"type\":{"
-                           "\"type\":\"integer\","
-                           "\"minimum\":0"
-                          "},"
-                          "\"value\":{"
-                           "\"type\":\"string\","
-                           "\"enum\":[\"unknown\"]"
-                          "}"
-                         "},"
-                         "\"required\":[\"type\",\"value\"]"
-                        "}"
-                       "}"
-                      "}"
-                     "}"
-                    "}");
-
-       if (old_len == out->data) {
-               chunk_reset(out);
-               chunk_appendf(out,
-                             "{\"errorStr\":\"output buffer too short\"}");
-       }
-       chunk_appendf(out, "\n");
-}
-
-/* This function dumps the schema onto the stream connector's read buffer.
- * It returns 0 as long as it does not complete, non-zero upon completion.
- * No state is used.
- */
-static int stats_dump_json_schema_to_buffer(struct appctx *appctx)
-{
-       struct show_stat_ctx *ctx = appctx->svcctx;
-       struct buffer *chk = &ctx->chunk;
-
-       chunk_reset(chk);
-
-       stats_dump_json_schema(chk);
-
-       if (applet_putchk(appctx, chk) == -1)
-               return 0;
-
-       return 1;
-}
-
 static int cli_parse_clear_counters(char **args, char *payload, struct appctx *appctx, void *private)
 {
        struct proxy *px;