diff --git a/include/lib/util_fmt.h b/include/lib/util_fmt.h index 957768bf..1d3b9af9 100644 --- a/include/lib/util_fmt.h +++ b/include/lib/util_fmt.h @@ -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 */ diff --git a/libutil/util_fmt.c b/libutil/util_fmt.c index c0898fbf..31bbe704 100644 --- a/libutil/util_fmt.c +++ b/libutil/util_fmt.c @@ -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; diff --git a/libutil/util_fmt_example.c b/libutil/util_fmt_example.c index a3f08fc6..cb13d182 100644 --- a/libutil/util_fmt_example.c +++ b/libutil/util_fmt_example.c @@ -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);