This may be used to output the JSON schema which describes the output of show info json and show stats json.
The JSON output is without any extra whitespace in order to reduce the volume of output. For human consumption passing the output through a pretty printer may be helpful. e.g.: $ echo "show schema json" | socat /var/run/haproxy.stat stdio | \ python -m json.tool The implementation does not generate the schema. Some consideration could be given to integrating the output of the schema with the output of typed and json info and stats. In particular the types (u32, s64, etc...) and tags. A sample verification of show info json and show stats json using the schema is as follows. It uses the jsonschema python module: cat > jschema.py << __EOF__ import json from jsonschema import validate from jsonschema.validators import Draft3Validator with open('schema.txt', 'r') as f: schema = json.load(f) Draft3Validator.check_schema(schema) with open('instance.txt', 'r') as f: instance = json.load(f) validate(instance, schema, Draft3Validator) __EOF__ $ echo "show schema json" | socat /var/run/haproxy.stat stdio > schema.txt $ echo "show info json" | socat /var/run/haproxy.stat stdio > instance.txt python ./jschema.py $ echo "show stats json" | socat /var/run/haproxy.stat stdio > instance.txt python ./jschema.py Signed-off-by: Simon Horman <ho...@verge.net.au> --- In this case the pretty printer increases the size of the output by about 200% illustrating the value of output without whitespace. $ echo "show schema json" | socat /var/run/haproxy.stat stdio | wc -c 2690 $ echo "show schema json" | socat /var/run/haproxy.stat stdio | \ python -m json.tool | wc -c 8587 Changes since RFC: * Add errors to schema and use in the case where output exceeds available buffer space * Document that consideration should be given to updating schema function if struct field is updated * Correct typos * Register "show", "schema", json" rather than "show", "schema". This allows the parse callback to be omitted and some simplification of the dump callback. * Limit integer values to the range [-(2**53)+1, (2**53)-1] as per the recommendation for interoperable integers in section 6 of RFC 7159. --- doc/management.txt | 33 ++++++- include/types/stats.h | 5 +- src/stats.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+), 4 deletions(-) diff --git a/doc/management.txt b/doc/management.txt index 623ac6375552..70af03b07271 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -1849,7 +1849,14 @@ show info [typed|json] (...) The format of JSON output is described in a schema which may be output - using "show schema json" (to be implemented). + using "show schema json". + + The JSON output contains no extra whitespace in order to reduce the + volume of output. For human consumption passing the output through a + pretty printer may be helpful. Example : + + $ echo "show info json" | socat /var/run/haproxy.sock stdio | \ + python -m json.tool The JSON output contains no extra whitespace in order to reduce the volume of output. For human consumption passing the output through a @@ -2128,7 +2135,14 @@ show stat [{<iid>|<proxy>} <type> <sid>] [typed|json] (...) The format of JSON output is described in a schema which may be output - using "show schema json" (to be implemented). + using "show schema json". + + The JSON output contains no extra whitespace in order to reduce the + volume of output. For human consumption passing the output through a + pretty printer may be helpful. Example : + + $ echo "show stat json" | socat /var/run/haproxy.sock stdio | \ + python -m json.tool The JSON output contains no extra whitespace in order to reduce the volume of output. For human consumption passing the output through a @@ -2237,6 +2251,21 @@ show tls-keys [id|*] specified as parameter, it will dump the tickets, using * it will dump every keys from every references. +show schema json + Dump the schema used for the output of "show info json" and "show stat json". + + The contains no extra whitespace in order to reduce the volume of output. + For human consumption passing the output through a pretty printer may be + helpful. Example : + + $ echo "show schema json" | socat /var/run/haproxy.sock stdio | \ + python -m json.tool + + The schema follows "JSON Schema" (json-schema.org) and accordingly + verifiers may be used to verify the output of "show info json" and "show + stat json" against the schema. + + shutdown frontend <frontend> Completely delete the specified frontend. All the ports it was bound to will be released. It will not be possible to enable the frontend anymore after diff --git a/include/types/stats.h b/include/types/stats.h index aad694c203c3..70224687123b 100644 --- a/include/types/stats.h +++ b/include/types/stats.h @@ -215,8 +215,9 @@ enum field_scope { FS_MASK = 0xFF000000, }; -/* Please consider updating stats_dump_fields_*() and - * stats_dump_.*_info_fields() when modifying struct field or related enums. +/* Please consider updating stats_dump_fields_*(), + * stats_dump_.*_info_fields() and stats_*_schema() + * when modifying struct field or related enums. */ struct field { uint32_t type; diff --git a/src/stats.c b/src/stats.c index 0f226fca2c2e..1038f76f073e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -3299,6 +3299,234 @@ static int stats_dump_info_to_buffer(struct stream_interface *si) return 1; } +/* This function dumps the schema onto the stream interface's read buffer. + * It returns 0 as long as it does not complete, non-zero upon completion. + * No state is used. + * + * Integer values bouned 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 chunk *out) +{ + + int old_len = out->len; + + chunk_strcat(out, + "{" + "\"$schema\":\"http://json-schema.org/draft-04/schema#\"," + "\"oneOf\":[" + "{" + "\"title\":\"Info\"," + "\"type\":\"array\"," + "\"items\":{" + "\"properties\":{" + "\"title\":\"InfoItem\"," + "\"type\":\"object\"," + "\"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->len) { + chunk_reset(out); + chunk_appendf(out, + "{\"errorStr\":\"output buffer too short\"}"); + } +} + +/* This function dumps the schema onto the stream interface'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 stream_interface *si) +{ + chunk_reset(&trash); + + stats_dump_json_schema(&trash); + + if (bi_putchk(si_ic(si), &trash) == -1) { + si_applet_cant_put(si); + return 0; + } + + return 1; +} + static int cli_parse_clear_counters(char **args, struct appctx *appctx, void *private) { struct proxy *px; @@ -3420,11 +3648,17 @@ static int cli_io_handler_dump_stat(struct appctx *appctx) return stats_dump_stat_to_buffer(appctx->owner, NULL); } +static int cli_io_handler_dump_json_schema(struct appctx *appctx) +{ + return stats_dump_json_schema_to_buffer(appctx->owner); +} + /* register cli keywords */ static struct cli_kw_list cli_kws = {{ },{ { { "clear", "counters", NULL }, "clear counters : clear max statistics counters (add 'all' for all counters)", cli_parse_clear_counters, NULL, NULL }, { { "show", "info", NULL }, "show info : report information about the running process", cli_parse_show_info, cli_io_handler_dump_info, NULL }, { { "show", "stat", NULL }, "show stat : report counters for each proxy and server", cli_parse_show_stat, cli_io_handler_dump_stat, NULL }, + { { "show", "schema", "json", NULL }, "show schema json : report schema used for stats", NULL, cli_io_handler_dump_json_schema, NULL }, {{},} }}; -- 2.7.0.rc3.207.g0ac5344