mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
libutil/util_fmt: Introduce JSON Lines text format
JSON Lines text format (JSONL) [1] is a line-delimited JSON format where objects are separated by the new line character (\n, LF) as opposed to the JSON Sequence text format (json-seq) where JSON text is encapsulated in an ASCII Record Separator (0x1E, RS) and ASCII Line Feed character (0x0A, LF). Whilst JSONL is also used for data streaming, this simpler format is better suited for logging and works also well with traditional line-oriented Unix tooling (e.g. grep or sed). Add this format to util_fmt so that users have more choice and control over formats that are required for their usecases. Add helper functions that let the user determine whether a given format type is JSON in general or a JSON streaming format (such as json-seq or jsonl). For better readability and more clarity use the helper function util_fmt_is_json_stream() where the same decision is made for both JSON streaming formats FMT_JSONSEQ and FMT_JSONL. [1] https://jsonlines.org/ Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
@@ -45,12 +45,13 @@
|
||||
#define FMT_DEFAULT 0
|
||||
|
||||
/* Names of supported output format types. */
|
||||
#define FMT_TYPE_NAMES "json json-seq pairs csv"
|
||||
#define FMT_TYPE_NAMES "json json-seq jsonl pairs csv"
|
||||
|
||||
/**
|
||||
* enum util_fmt_t - Output format types.
|
||||
* @FMT_JSON: JavaScript Object Notation output data structure
|
||||
* @FMT_JSONSEQ: Sequence of JSON data structures according to RFC7464
|
||||
* @FMT_JSONL: Line-delimited JSON
|
||||
* @FMT_PAIRS: Textual key=value pairs
|
||||
* @FMT_CSV: Comma-separated-values output
|
||||
*
|
||||
@@ -59,6 +60,7 @@
|
||||
enum util_fmt_t {
|
||||
FMT_JSON,
|
||||
FMT_JSONSEQ,
|
||||
FMT_JSONL,
|
||||
FMT_PAIRS,
|
||||
FMT_CSV,
|
||||
};
|
||||
@@ -232,4 +234,23 @@ void util_fmt_obj_end(void);
|
||||
*/
|
||||
void util_fmt_pair(unsigned int mflags, const char *key, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* util_fmt_is_json() - Determine whether format is JSON.
|
||||
* @type: Format type identifier.
|
||||
*
|
||||
* Return: %true if type is JSON, %false otherwise.
|
||||
*/
|
||||
bool util_fmt_is_json(enum util_fmt_t type);
|
||||
|
||||
/**
|
||||
* util_fmt_is_json_stream() - Determine whether format is JSON stream.
|
||||
* @type: Format type identifier.
|
||||
*
|
||||
* Determine whether a given format @type represents a JSON streaming format
|
||||
* such as json-seq (@FMT_JSONSEQ) or jsonl (@FMT_JSONL).
|
||||
*
|
||||
* Return: %true if type is either @FMT_JSONSEQ or @FMT_JSONL, %false otherwise.
|
||||
*/
|
||||
bool util_fmt_is_json_stream(enum util_fmt_t type);
|
||||
|
||||
#endif /* LIB_UTIL_FMT_H */
|
||||
|
||||
@@ -91,6 +91,7 @@ static const struct {
|
||||
} formats[] = {
|
||||
{ "json", FMT_JSON },
|
||||
{ "json-seq", FMT_JSONSEQ },
|
||||
{ "jsonl", FMT_JSONL },
|
||||
{ "pairs", FMT_PAIRS },
|
||||
{ "csv", FMT_CSV },
|
||||
};
|
||||
@@ -111,6 +112,29 @@ bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool util_fmt_is_json(enum util_fmt_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case FMT_JSON:
|
||||
case FMT_JSONSEQ:
|
||||
case FMT_JSONL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool util_fmt_is_json_stream(enum util_fmt_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case FMT_JSONSEQ:
|
||||
case FMT_JSONL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void safe_write(const char *str)
|
||||
{
|
||||
size_t done, todo;
|
||||
@@ -129,7 +153,7 @@ static void _indent(unsigned int off, bool safe)
|
||||
{
|
||||
unsigned int num, i;
|
||||
|
||||
if (f.type == FMT_JSONSEQ)
|
||||
if (util_fmt_is_json_stream(f.type))
|
||||
return;
|
||||
num = f.ind_base + off;
|
||||
if (f.type == FMT_JSON && f.lvl > 0)
|
||||
@@ -408,8 +432,8 @@ static void emit_meta_object(void)
|
||||
util_fmt_pair(quoted, "time", "%s", date);
|
||||
_util_fmt_obj_end();
|
||||
|
||||
if (f.type == FMT_JSONSEQ) {
|
||||
/* Tool meta-data is a separate object for JSONSEQ. */
|
||||
if (util_fmt_is_json_stream(f.type)) {
|
||||
/* Tool meta-data is a separate object for JSON streams. */
|
||||
util_fmt_obj_end();
|
||||
}
|
||||
}
|
||||
@@ -478,7 +502,7 @@ void util_fmt_obj_end(void)
|
||||
{
|
||||
_util_fmt_obj_end();
|
||||
|
||||
if (f.lvl == 1 && f.meta_done && f.type != FMT_JSONSEQ) {
|
||||
if (f.lvl == 1 && f.meta_done && !util_fmt_is_json_stream(f.type)) {
|
||||
/* Emit closure for top-level meta-container object. */
|
||||
util_fmt_obj_end();
|
||||
}
|
||||
@@ -737,7 +761,7 @@ void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
|
||||
f.do_warn = (flags & FMT_WARN);
|
||||
f.handle_int = (flags & FMT_HANDLEINT);
|
||||
f.api_level = api_level;
|
||||
if (type == FMT_JSONSEQ)
|
||||
if (util_fmt_is_json_stream(type))
|
||||
f.nl = "";
|
||||
else
|
||||
f.nl = "\n";
|
||||
@@ -750,6 +774,7 @@ void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
|
||||
break;
|
||||
case FMT_JSON:
|
||||
case FMT_JSONSEQ:
|
||||
case FMT_JSONL:
|
||||
f.obj_start = &json_obj_start;
|
||||
f.obj_end = &json_obj_end;
|
||||
f.map = &json_map;
|
||||
|
||||
@@ -193,6 +193,9 @@ int main(int UNUSED(argc), char *UNUSED(argv[]))
|
||||
announce("JSON formatted as sequence");
|
||||
simple_example(FMT_JSONSEQ, FMT_DEFAULT);
|
||||
|
||||
announce("JSON Lines format");
|
||||
simple_example(FMT_JSONL, FMT_DEFAULT);
|
||||
|
||||
announce("Pairs output");
|
||||
simple_example(FMT_PAIRS, FMT_KEEPINVAL);
|
||||
|
||||
@@ -232,6 +235,9 @@ int main(int UNUSED(argc), char *UNUSED(argv[]))
|
||||
announce("JSON sequence output with meta-data");
|
||||
meta_example(FMT_JSONSEQ);
|
||||
|
||||
announce("JSON Lines output with meta-data");
|
||||
meta_example(FMT_JSONL);
|
||||
|
||||
announce("Pairs output with meta-data");
|
||||
meta_example(FMT_PAIRS);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user