Skip to content

NDJSON

Uses a non-console output and a single JSON object for each line, with each record type declared once (custom) to provide custom member fields.

e.g.

  NDJSON_DEFINE(test_result, “test”, “result”, 1,                  NDJSON_STR(name),                  NDJSON_STR(status),                  NDJSON_U64(duration_ms));

  ndjson_emit(test_result, .name = t->name, .status = “pass”,               .duration_ms = took);

Omitted fields are left as zero

struct ndjson_field (3 fields) source
§ const char *name
§ enum ndjson_type type
§ uint16_t offset

into the generated argument struct

struct ndjson_record (5 fields) source
§ const char *section
§ const char *kind
§ uint16_t version
§ uint16_t nfields
§ const struct ndjson_field *fields cc_counted_by(nfields)
enum ndjson_type : uint8_t (5 variants) source
§ NDJSON_TYPE_U64
§ NDJSON_TYPE_I64
§ NDJSON_TYPE_BOOL
§ NDJSON_TYPE_STR
§ NDJSON_TYPE_HEX

emitted as “0x..”

void ndjson_emit_impl(
    const struct ndjson_record *rec,
    const void *args
)
source
void ndjson_bye(uint64_t code, const char *reason)
source

Terminator, and signals that the kernel run ended, used so the logs know that something failed/hung when it is absent

void ndjson_early_init(void)
source
void ndjson_init(void)
source
bool ndjson_carrier_online(void)
source
void ndjson_carrier_init(uint16_t port)
source
void ndjson_carrier_disable(void)
source
void ndjson_enter_panic(void)
source
#define NDJSON_KEY_SECTION "s"
source
#define NDJSON_KEY_KIND "k"
source
#define NDJSON_KEY_VERSION "v"
source
#define NDJSON_KEY_TIME "t"
source
#define NDJSON_KEY_CPU "c"
source
#define NDJSON_KEY_TRUNCATED "_trunc"
source
#define NDJSON_SECTION_NDJSON "ndjson"
source
#define NDJSON_SECTION_TEST "test"
source
#define NDJSON_SECTION_PANIC "panic"
source
#define NDJSON_SECTION_ASAN "asan"
source
#define NDJSON_SECTION_SELFTEST "selftest"
source
#define NDJSON_SECTION_NIGHTMARE "nightmare"
source
#define NDJSON_SECTION_LOCK_CHK "lock_chk"
source
#define NDJSON_SECTION_LOG "log"
source
#define NDJSON_KIND_SCHEMA "schema"
source
#define NDJSON_KIND_BYE "bye"
source
#define NDJSON_KIND_BEGIN "begin"
source
#define NDJSON_KIND_RESULT "result"
source
#define NDJSON_KIND_GROUP_START "group_start"
source
#define NDJSON_KIND_GROUP_END "group_end"
source
#define NDJSON_KIND_TOTALS "totals"
source
#define NDJSON_KIND_VERDICT "verdict"
source
#define NDJSON_KIND_EXIT "exit"
source
#define NDJSON_KIND_AT "at"
source
#define NDJSON_KIND_FAULT "fault"
source
#define NDJSON_KIND_FRAME "frame"
source
#define NDJSON_KIND_PEER "peer"
source
#define NDJSON_KIND_OWNER "owner"
source
#define NDJSON_KIND_BOOT "boot"
source
#define NDJSON_KIND_STAT "stat"
source
#define NDJSON_KIND_QUIESCE "quiesce"
source
#define NDJSON_KIND_FINDING "finding"
source
#define NDJSON_KIND_MESSAGE "msg"
source
#define NDJSON_TYPE_NAME_U64 "u64"
source
#define NDJSON_TYPE_NAME_I64 "i64"
source
#define NDJSON_TYPE_NAME_BOOL "bool"
source
#define NDJSON_TYPE_NAME_STR "str"
source
#define NDJSON_TYPE_NAME_HEX "hex"
source
#define NDJSON_CTYPE_U64 uint64_t
source
#define NDJSON_CTYPE_I64 int64_t
source
#define NDJSON_CTYPE_BOOL bool
source
#define NDJSON_CTYPE_STR const char *
source
#define NDJSON_CTYPE_HEX uint64_t
source

NDJSON_DEFINE uses this

#define NDJSON_U64(n)
source
Expansion
#define NDJSON_U64(n) (U64, n)
#define NDJSON_I64(n)
source
Expansion
#define NDJSON_I64(n) (I64, n)
#define NDJSON_BOOL(n)
source
Expansion
#define NDJSON_BOOL(n) (BOOL, n)
#define NDJSON_STR(n)
source
Expansion
#define NDJSON_STR(n) (STR, n)
#define NDJSON_HEX(n)
source
Expansion
#define NDJSON_HEX(n) (HEX, n)
#define NDJSON_UNTUPLE(...)
source
Expansion
#define NDJSON_UNTUPLE(...) __VA_ARGS__
#define NDJSON_MEMBER(id, spec)
source
Expansion
#define NDJSON_MEMBER(id, spec) NDJSON_MEMBER_(id, NDJSON_UNTUPLE spec)
#define NDJSON_MEMBER_(id, ...)
source
Expansion
#define NDJSON_MEMBER_(id, ...) NDJSON_MEMBER__(id, __VA_ARGS__)
#define NDJSON_MEMBER__(id, t, n)
source
Expansion
#define NDJSON_MEMBER__(id, t, n) NDJSON_CTYPE_##t n;
#define NDJSON_DESC(id, spec)
source
Expansion
#define NDJSON_DESC(id, spec) NDJSON_DESC_(id, NDJSON_UNTUPLE spec)
#define NDJSON_DESC_(id, ...)
source
Expansion
#define NDJSON_DESC_(id, ...) NDJSON_DESC__(id, __VA_ARGS__)
#define NDJSON_DESC__(id, t, n)
source
Expansion
#define NDJSON_DESC__(id, t, n) \
    {.name = #n, \
     .type = NDJSON_TYPE_##t, \
     .offset = (uint16_t) ci_offsetof(struct __ndjson_args_##id, n)},
#define NDJSON_MAP_1(f, a, x)
source

Apply f(a, x) to each x with constant a

Expansion
#define NDJSON_MAP_1(f, a, x) f(a, x)
#define NDJSON_MAP_2(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_2(f, a, x, ...) f(a, x) NDJSON_MAP_1(f, a, __VA_ARGS__)
#define NDJSON_MAP_3(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_3(f, a, x, ...) f(a, x) NDJSON_MAP_2(f, a, __VA_ARGS__)
#define NDJSON_MAP_4(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_4(f, a, x, ...) f(a, x) NDJSON_MAP_3(f, a, __VA_ARGS__)
#define NDJSON_MAP_5(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_5(f, a, x, ...) f(a, x) NDJSON_MAP_4(f, a, __VA_ARGS__)
#define NDJSON_MAP_6(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_6(f, a, x, ...) f(a, x) NDJSON_MAP_5(f, a, __VA_ARGS__)
#define NDJSON_MAP_7(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_7(f, a, x, ...) f(a, x) NDJSON_MAP_6(f, a, __VA_ARGS__)
#define NDJSON_MAP_8(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_8(f, a, x, ...) f(a, x) NDJSON_MAP_7(f, a, __VA_ARGS__)
#define NDJSON_MAP_9(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_9(f, a, x, ...) f(a, x) NDJSON_MAP_8(f, a, __VA_ARGS__)
#define NDJSON_MAP_10(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_10(f, a, x, ...) f(a, x) NDJSON_MAP_9(f, a, __VA_ARGS__)
#define NDJSON_MAP_11(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_11(f, a, x, ...) f(a, x) NDJSON_MAP_10(f, a, __VA_ARGS__)
#define NDJSON_MAP_12(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_12(f, a, x, ...) f(a, x) NDJSON_MAP_11(f, a, __VA_ARGS__)
#define NDJSON_MAP_13(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_13(f, a, x, ...) f(a, x) NDJSON_MAP_12(f, a, __VA_ARGS__)
#define NDJSON_MAP_14(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_14(f, a, x, ...) f(a, x) NDJSON_MAP_13(f, a, __VA_ARGS__)
#define NDJSON_MAP_15(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_15(f, a, x, ...) f(a, x) NDJSON_MAP_14(f, a, __VA_ARGS__)
#define NDJSON_MAP_16(f, a, x, ...)
source
Expansion
#define NDJSON_MAP_16(f, a, x, ...) f(a, x) NDJSON_MAP_15(f, a, __VA_ARGS__)
#define NDJSON_MAP(f, a, ...)
source
Expansion
#define NDJSON_MAP(f, a, ...) \
    PP_OVERLOAD(NDJSON_MAP, __VA_ARGS__)(f, a, __VA_ARGS__)
#define NDJSON_MAX_FIELDS 16
source
#define NDJSON_DEFINE(id, section_, kind_, version_, ...)
source
Expansion
#define NDJSON_DEFINE(id, section_, kind_, version_, ...) \
    struct __ndjson_args_##id { \
        NDJSON_MAP(NDJSON_MEMBER, id, __VA_ARGS__) \
    }; \
    static const struct ndjson_field __ndjson_fields_##id[] = { \
        NDJSON_MAP(NDJSON_DESC, id, __VA_ARGS__)}; \
    LINKER_SECTION_OBJECT(struct ndjson_record, ndjson_records) \
    __ndjson_rec_##id = {.section = (section_), \
                         .kind = (kind_), \
                         .version = (version_), \
                         .nfields = PP_NARG(__VA_ARGS__), \
                         .fields = __ndjson_fields_##id}; \
    static_assert(PP_NARG(__VA_ARGS__) <= NDJSON_MAX_FIELDS, \
                  "ndjson record " #id " has too many fields")
#define NDJSON(id)
source
Expansion
#define NDJSON(id) (&__ndjson_rec_##id)
#define NDJSON_EXTERN(id)
source
Expansion
#define NDJSON_EXTERN(id) extern struct ndjson_record __ndjson_rec_##id
#define ndjson_emit(id, ...)
source
Expansion
#define ndjson_emit(id, ...) \
    ndjson_emit_impl(NDJSON(id), \
                     &(const struct __ndjson_args_##id) {__VA_ARGS__})
#define NDJSON_STR_MAX 512
source