diff --git a/docs/source/formats.rst b/docs/source/formats.rst index 36b573d9..633eab67 100644 --- a/docs/source/formats.rst +++ b/docs/source/formats.rst @@ -101,10 +101,18 @@ should be another object with the following fields: [ { "field": "ts" }, " ", { "field": "msg" } ] - :field: The name of the message field that should be inserted at this - point in the message. The special "__timestamp__" field name can be - used to insert a human-readable timestamp. The "__level__" field can - be used to insert the level name as defined by lnav. + :field: The name or `JSON-Pointer `_ + of the message field that should be inserted at this point in the + message. The special :code:`__timestamp__` field name can be used to + insert a human-readable timestamp. The :code:`__level__` field can be + used to insert the level name as defined by lnav. + + .. tip:: + + Use a JSON-Pointer to reference nested fields. For example, to include + a "procname" property that is nested in a "details" object, you would + write the field reference as :code:`/details/procname`. + :min-width: The minimum width for the field. If the value for the field in a given log message is shorter, padding will be added as needed to meet the minimum-width requirement. (v0.8.2+) diff --git a/src/log_format.cc b/src/log_format.cc index 5f8b41c0..de4173ae 100644 --- a/src/log_format.cc +++ b/src/log_format.cc @@ -1881,6 +1881,9 @@ void external_log_format::build(std::vector &errors) { static const intern_string_t level_field = intern_string::lookup("__level__"); json_format_element &jfe = *iter; + if (startswith(jfe.jfe_value.get(), "/")) { + jfe.jfe_value = intern_string::lookup(jfe.jfe_value.get() + 1); + } if (!jfe.jfe_ts_format.empty()) { if (!jfe.jfe_value.empty() && jfe.jfe_value != ts) { log_warning("%s:line-format[%d]:ignoring field '%s' since " diff --git a/src/log_format_loader.cc b/src/log_format_loader.cc index 1b60e11b..1927ace7 100644 --- a/src/log_format_loader.cc +++ b/src/log_format_loader.cc @@ -216,8 +216,10 @@ static int read_format_int(yajlpp_parse_context *ypc, long long val) static int read_format_field(yajlpp_parse_context *ypc, const unsigned char *str, size_t len) { auto elf = (external_log_format *) ypc->ypc_obj_stack.top(); - string value = string((const char *)str, len); - string field_name = ypc->get_path_fragment(1); + auto leading_slash = len > 0 && str[0] == '/'; + auto value = string((const char *) (leading_slash ? str + 1 : str), + leading_slash ? len - 1 : len); + auto field_name = ypc->get_path_fragment(1); if (field_name == "file-pattern") { elf->elf_file_pattern = value; diff --git a/test/formats/nestedjson/format.json b/test/formats/nestedjson/format.json index f89b7415..3a28b4eb 100644 --- a/test/formats/nestedjson/format.json +++ b/test/formats/nestedjson/format.json @@ -7,11 +7,11 @@ "line-format" : [ { "field" : "ts" }, " ", - { "field" : "@fields/lvl" }, + { "field" : "/@fields/lvl" }, " ", { "field" : "@fields/msg" } ], - "level-field" : "@fields/lvl", + "level-field" : "/@fields/lvl", "timestamp-field": "ts", "body-field" : "@fields/msg", "value" : {