[loader] add line numbers for parse errors

Fixes #442
This commit is contained in:
Timothy Stack 2017-04-24 06:18:04 -07:00
parent ceb4fe7721
commit 9764cb1a93
8 changed files with 105 additions and 22 deletions

View File

@ -461,6 +461,7 @@ static struct json_path_handler value_def_handlers[] = {
.for_field(&nullobj<external_log_format::value_def>()->vd_collate),
json_path_handler("unit/")
.with_description("Unit definitions for this field")
.with_children(unit_handlers),
json_path_handler("identifier")
@ -679,8 +680,9 @@ std::vector<intern_string_t> load_format_file(const string &filename, std::vecto
char errmsg[1024];
snprintf(errmsg, sizeof(errmsg),
"error: unable to open format file -- %s",
filename.c_str());
"error:unable to open format file '%s' -- %s",
filename.c_str(),
strerror(errno));
errors.push_back(errmsg);
}
else {
@ -699,9 +701,11 @@ std::vector<intern_string_t> load_format_file(const string &filename, std::vecto
break;
}
else if (rc == -1) {
errors.push_back(filename +
":unable to read file -- " +
string(strerror(errno)));
errors.push_back(
"error:" +
filename +
":unable to read file -- " +
string(strerror(errno)));
break;
}
if (offset == 0 && (rc > 2) &&
@ -710,18 +714,26 @@ std::vector<intern_string_t> load_format_file(const string &filename, std::vecto
buffer[0] = buffer[1] = '/';
}
if (ypc.parse((const unsigned char *)buffer, rc) != yajl_status_ok) {
errors.push_back(filename +
": invalid json -- " +
string((char *)yajl_get_error(handle, 1, (unsigned char *)buffer, rc)));
errors.push_back(
"error:" +
filename +
":" +
to_string(ypc.get_line_number()) +
":invalid json -- " +
string((char *)yajl_get_error(handle, 1, (unsigned char *)buffer, rc)));
break;
}
offset += rc;
}
if (rc == 0) {
if (ypc.complete_parse() != yajl_status_ok) {
errors.push_back(filename +
": invalid json -- " +
string((char *)yajl_get_error(handle, 0, NULL, 0)));
errors.push_back(
"error:" +
filename +
":" +
to_string(ypc.get_line_number()) +
":invalid json -- " +
string((char *)yajl_get_error(handle, 0, NULL, 0)));
}
}
}
@ -912,7 +924,11 @@ static void exec_sql_in_path(sqlite3 *db, const string &path, std::vector<string
sql_execute_script(db, filename.c_str(), content.c_str(), errors);
}
else {
errors.push_back("Unable to read file: " + filename);
errors.push_back(
"error:unable to read file '" +
filename +
"' -- " +
string(strerror(errno)));
}
}
}

View File

@ -553,6 +553,8 @@ void yajlpp_parse_context::update_callbacks(const json_path_handler_base *orig_h
return;
}
this->ypc_sibling_handlers = orig_handlers;
pcre_input pi(&this->ypc_path[0], 0, this->ypc_path.size() - 1);
this->ypc_callbacks = DEFAULT_CALLBACKS;
@ -731,10 +733,20 @@ int yajlpp_parse_context::handle_unused(void *ctx)
}
if (handler == NULL) {
const json_path_handler_base *accepted_handlers;
if (ypc->ypc_sibling_handlers) {
accepted_handlers = ypc->ypc_sibling_handlers;
} else {
accepted_handlers = ypc->ypc_handlers;
}
fprintf(stderr, " accepted paths --\n");
for (int lpc = 0; ypc->ypc_handlers[lpc].jph_path[0]; lpc++) {
fprintf(stderr, " %s\n",
ypc->ypc_handlers[lpc].jph_path);
for (int lpc = 0; accepted_handlers[lpc].jph_path[0]; lpc++) {
fprintf(stderr, " %s %s -- %s\n",
accepted_handlers[lpc].jph_path,
accepted_handlers[lpc].jph_synopsis,
accepted_handlers[lpc].jph_description);
}
}

View File

@ -383,7 +383,8 @@ public:
ypc_handle(NULL),
ypc_json_text(NULL),
ypc_ignore_unused(false),
ypc_current_handler(NULL),
ypc_sibling_handlers(nullptr),
ypc_current_handler(nullptr),
ypc_error_reporter(nullptr)
{
this->ypc_path.reserve(4096);
@ -467,7 +468,8 @@ public:
this->ypc_array_index.clear();
this->ypc_callbacks = DEFAULT_CALLBACKS;
memset(&this->ypc_alt_callbacks, 0, sizeof(this->ypc_alt_callbacks));
this->ypc_current_handler = NULL;
this->ypc_sibling_handlers = nullptr;
this->ypc_current_handler = nullptr;
while (!this->ypc_obj_stack.empty()) {
this->ypc_obj_stack.pop();
}
@ -511,11 +513,9 @@ public:
yajl_status retval = yajl_parse(this->ypc_handle, jsonText, jsonTextLen);
if (retval == yajl_status_ok) {
size_t consumed = yajl_get_bytes_consumed(this->ypc_handle);
size_t consumed = yajl_get_bytes_consumed(this->ypc_handle);
this->ypc_line_number += std::count(&jsonText[0], &jsonText[consumed], '\n');
}
this->ypc_line_number += std::count(&jsonText[0], &jsonText[consumed], '\n');
this->ypc_json_text = NULL;
return retval;
@ -531,7 +531,7 @@ public:
return this->ypc_line_number + current_count;
}
else {
return 0;
return this->ypc_line_number;
}
};
@ -567,6 +567,7 @@ public:
std::vector<int> ypc_array_index;
pcre_context_static<30> ypc_pcre_context;
bool ypc_ignore_unused;
const struct json_path_handler_base *ypc_sibling_handlers;
const struct json_path_handler_base *ypc_current_handler;
std::set<std::string> ypc_active_paths;
error_reporter_t ypc_error_reporter;

View File

@ -251,6 +251,8 @@ dist_noinst_DATA = \
bad-config/formats/invalid-sample/format.json \
bad-config/formats/invalid-sql/init.sql \
bad-config/formats/no-samples/format.json \
bad-config-json/formats/invalid-json/format.json \
bad-config-json/formats/invalid-json/format2.json \
datafile_simple.0 \
datafile_simple.1 \
datafile_simple.2 \

View File

@ -0,0 +1,5 @@
{
"foobar_log": {
"abc"
}
}

View File

@ -0,0 +1,5 @@
{
"foobaz_log" : {
"abc" : def
}
}

View File

@ -0,0 +1,9 @@
{
"invalid_key_log" : {
"value" : {
"test": {
"identifiers" : true
}
}
}
}

View File

@ -3,6 +3,39 @@
lnav_test="${top_builddir}/src/lnav-test"
run_test ${lnav_test} -C \
-I ${test_dir}/bad-config-json
sed -i "" -e "s|/.*/format|format|g" `test_err_filename`
check_error_output "invalid format not detected?" <<EOF
warning:format.json:line 5
unexpected path --
/invalid_key_log/value/test/identifiers
accepted paths --
kind string|integer|float|boolean|json|quoted -- The type of data in the field
collate <function> -- The collating function to use for this column
unit/ -- Unit definitions for this field
identifier <bool> -- Indicates whether or not this field contains an identifier that should be highlighted
foreign-key <bool> -- Indicates whether or not this field should be treated as a foreign key for row in another table
hidden <bool> -- Indicates whether or not this field should be hidden
action-list# <string> -- Actions to execute when this field is clicked on
rewriter <command> -- A command that will rewrite this field when pretty-printing
description <string> -- A description of the field
error:format.json:4:invalid json -- parse error: object key and value must be separated by a colon (':')
ar_log": { "abc" } }
(right here) ------^
error:format2.json:3:invalid json -- lexical error: invalid char in json text.
baz_log" : { "abc" : def } }
(right here) ------^
error:foobar_log: no regexes specified for format
error:foobar_log:no sample logs provided, all formats must have samples
error:foobaz_log: no regexes specified for format
error:foobaz_log:no sample logs provided, all formats must have samples
error:invalid_key_log: no regexes specified for format
error:invalid_key_log:no sample logs provided, all formats must have samples
EOF
run_test ${lnav_test} -C \
-I ${test_dir}/bad-config