diff options
Diffstat (limited to '')
-rw-r--r-- | src/log_vtab_impl.cc | 568 |
1 files changed, 334 insertions, 234 deletions
diff --git a/src/log_vtab_impl.cc b/src/log_vtab_impl.cc index 7325675..0f905fc 100644 --- a/src/log_vtab_impl.cc +++ b/src/log_vtab_impl.cc @@ -33,7 +33,9 @@ #include "base/itertools.hh" #include "base/lnav_log.hh" #include "base/string_util.hh" +#include "bookmarks.json.hh" #include "config.h" +#include "hasher.hh" #include "lnav_util.hh" #include "logfile_sub_source.hh" #include "sql_util.hh" @@ -53,21 +55,22 @@ static struct log_cursor log_cursor_latest; thread_local _log_vtab_data log_vtab_data; static const char* LOG_COLUMNS = R"( ( - log_line INTEGER, -- The line number for the log message - log_part TEXT COLLATE naturalnocase, -- The partition the message is in + log_line INTEGER, -- The line number for the log message log_time DATETIME, -- The adjusted timestamp for the log message - log_actual_time DATETIME HIDDEN, -- The timestamp from the original log file for this message - log_idle_msecs INTEGER, -- The difference in time between this messages and the previous log_level TEXT COLLATE loglevel, -- The log message level - log_mark BOOLEAN, -- True if the log message was marked - log_comment TEXT, -- The comment for this message - log_tags TEXT, -- A JSON list of tags for this message - log_filters TEXT, -- A JSON list of filter IDs that matched this message -- BEGIN Format-specific fields: )"; static const char* LOG_FOOTER_COLUMNS = R"( -- END Format-specific fields + log_part TEXT COLLATE naturalnocase, -- The partition the message is in + log_actual_time DATETIME HIDDEN, -- The timestamp from the original log file for this message + log_idle_msecs INTEGER, -- The difference in time between this messages and the previous + log_mark BOOLEAN, -- True if the log message was marked + log_comment TEXT, -- The comment for this message + log_tags TEXT, -- A JSON list of tags for this message + log_annotations TEXT, -- A JSON object of annotations for this messages + log_filters TEXT, -- A JSON list of filter IDs that matched this message log_opid TEXT HIDDEN, -- The message's OPID log_format TEXT HIDDEN, -- The name of the log file format log_format_regex TEXT HIDDEN, -- The name of the regex used to parse this log message @@ -81,6 +84,14 @@ static const char* LOG_FOOTER_COLUMNS = R"( )"; enum class log_footer_columns : uint32_t { + partition, + actual_time, + idle_msecs, + mark, + comment, + tags, + annotations, + filters, opid, format, format_regex, @@ -108,8 +119,6 @@ log_vtab_impl::get_table_statement() max_name_len = std::max(max_name_len, iter->vc_name.length()); } for (iter = cols.begin(); iter != cols.end(); iter++) { - auto_mem<char, sqlite3_free> coldecl; - auto_mem<char, sqlite3_free> colname; std::string comment; require(!iter->vc_name.empty()); @@ -118,8 +127,8 @@ log_vtab_impl::get_table_statement() comment.append(" -- ").append(iter->vc_comment); } - colname = sql_quote_ident(iter->vc_name.c_str()); - coldecl = sqlite3_mprintf( + auto colname = sql_quote_ident(iter->vc_name.c_str()); + auto coldecl = lnav::sql::mprintf( " %-*s %-7s %s COLLATE %-15Q,%s\n", max_name_len, colname.in(), @@ -154,7 +163,7 @@ log_vtab_impl::get_table_statement() oss << ");\n"; - log_debug("log_vtab_impl.get_table_statement() -> %s", oss.str().c_str()); + log_trace("log_vtab_impl.get_table_statement() -> %s", oss.str().c_str()); return oss.str(); } @@ -206,6 +215,7 @@ log_vtab_impl::get_foreign_keys(std::vector<std::string>& keys_inout) const keys_inout.emplace_back("log_mark"); keys_inout.emplace_back("log_time_msecs"); keys_inout.emplace_back("log_top_line()"); + keys_inout.emplace_back("log_msg_line()"); } void @@ -291,6 +301,12 @@ struct log_vtab { textview_curses* tc{nullptr}; logfile_sub_source* lss{nullptr}; std::shared_ptr<log_vtab_impl> vi; + + size_t footer_index(log_footer_columns col) const + { + return VT_COL_MAX + this->vi->vi_column_count + + lnav::enums::to_underlying(col); + } }; struct vtab_cursor { @@ -458,7 +474,8 @@ populate_indexed_columns(vtab_cursor* vc, log_vtab* vt) vt->vi->extract(lf, line_number, vc->line_values); } - int sub_col = ic.cc_column - VT_COL_MAX; + auto sub_col = logline_value_meta::table_column{ + (size_t) (ic.cc_column - VT_COL_MAX)}; auto lv_iter = find_if(vc->line_values.lvv_values.begin(), vc->line_values.lvv_values.end(), logline_value_cmp(nullptr, sub_col)); @@ -622,37 +639,6 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) break; } - case VT_COL_PARTITION: { - auto& vb = vt->tc->get_bookmarks(); - const auto& bv = vb[&textview_curses::BM_META]; - - if (bv.empty()) { - sqlite3_result_null(ctx); - } else { - vis_line_t curr_line(vc->log_cursor.lc_curr_line); - auto iter = lower_bound(bv.begin(), bv.end(), curr_line + 1_vl); - - if (iter != bv.begin()) { - --iter; - auto line_meta_opt = vt->lss->find_bookmark_metadata(*iter); - if (line_meta_opt - && !line_meta_opt.value()->bm_name.empty()) - { - sqlite3_result_text( - ctx, - line_meta_opt.value()->bm_name.c_str(), - line_meta_opt.value()->bm_name.size(), - SQLITE_TRANSIENT); - } else { - sqlite3_result_null(ctx); - } - } else { - sqlite3_result_null(ctx); - } - } - break; - } - case VT_COL_LOG_TIME: { char buffer[64]; @@ -662,63 +648,6 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) break; } - case VT_COL_LOG_ACTUAL_TIME: { - char buffer[64]; - - if (ll->is_time_skewed()) { - if (vc->line_values.lvv_values.empty()) { - vc->cache_msg(lf, ll); - require(vc->line_values.lvv_sbr.get_data() != nullptr); - vt->vi->extract(lf, line_number, vc->line_values); - } - - struct line_range time_range; - - time_range = find_string_attr_range(vt->vi->vi_attrs, - &logline::L_TIMESTAMP); - - const auto* time_src - = vc->line_values.lvv_sbr.get_data() + time_range.lr_start; - struct timeval actual_tv; - struct exttm tm; - - if (lf->get_format()->lf_date_time.scan( - time_src, - time_range.length(), - lf->get_format()->get_timestamp_formats(), - &tm, - actual_tv, - false)) - { - sql_strftime(buffer, sizeof(buffer), actual_tv); - } - } else { - sql_strftime( - buffer, sizeof(buffer), ll->get_time(), ll->get_millis()); - } - sqlite3_result_text(ctx, buffer, strlen(buffer), SQLITE_TRANSIENT); - break; - } - - case VT_COL_IDLE_MSECS: - if (vc->log_cursor.lc_curr_line == 0) { - sqlite3_result_int64(ctx, 0); - } else { - content_line_t prev_cl( - vt->lss->at(vis_line_t(vc->log_cursor.lc_curr_line - 1))); - auto prev_lf = vt->lss->find(prev_cl); - auto prev_ll = prev_lf->begin() + prev_cl; - uint64_t prev_time, curr_line_time; - - prev_time = prev_ll->get_time() * 1000ULL; - prev_time += prev_ll->get_millis(); - curr_line_time = ll->get_time() * 1000ULL; - curr_line_time += ll->get_millis(); - // require(curr_line_time >= prev_time); - sqlite3_result_int64(ctx, curr_line_time - prev_time); - } - break; - case VT_COL_LEVEL: { const char* level_name = ll->get_level_name(); @@ -727,91 +656,208 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) break; } - case VT_COL_MARK: { - sqlite3_result_int(ctx, ll->is_marked()); - break; - } + default: + if (col > (VT_COL_MAX + vt->vi->vi_column_count - 1)) { + auto footer_column = static_cast<log_footer_columns>( + col - (VT_COL_MAX + vt->vi->vi_column_count - 1) - 1); - case VT_COL_LOG_COMMENT: { - auto line_meta_opt - = vt->lss->find_bookmark_metadata(vc->log_cursor.lc_curr_line); - if (!line_meta_opt || line_meta_opt.value()->bm_comment.empty()) { - sqlite3_result_null(ctx); - } else { - const auto& meta = *(line_meta_opt.value()); - sqlite3_result_text(ctx, - meta.bm_comment.c_str(), - meta.bm_comment.length(), - SQLITE_TRANSIENT); - } - break; - } + switch (footer_column) { + case log_footer_columns::partition: { + auto& vb = vt->tc->get_bookmarks(); + const auto& bv = vb[&textview_curses::BM_PARTITION]; - case VT_COL_LOG_TAGS: { - auto line_meta_opt - = vt->lss->find_bookmark_metadata(vc->log_cursor.lc_curr_line); - if (!line_meta_opt || line_meta_opt.value()->bm_tags.empty()) { - sqlite3_result_null(ctx); - } else { - const auto& meta = *(line_meta_opt.value()); + if (bv.empty()) { + sqlite3_result_null(ctx); + } else { + vis_line_t curr_line(vc->log_cursor.lc_curr_line); + auto iter = lower_bound( + bv.begin(), bv.end(), curr_line + 1_vl); + + if (iter != bv.begin()) { + --iter; + auto line_meta_opt + = vt->lss->find_bookmark_metadata(*iter); + if (line_meta_opt + && !line_meta_opt.value()->bm_name.empty()) + { + sqlite3_result_text( + ctx, + line_meta_opt.value()->bm_name.c_str(), + line_meta_opt.value()->bm_name.size(), + SQLITE_TRANSIENT); + } else { + sqlite3_result_null(ctx); + } + } else { + sqlite3_result_null(ctx); + } + } + break; + } + case log_footer_columns::actual_time: { + char buffer[64]; + + if (ll->is_time_skewed()) { + if (vc->line_values.lvv_values.empty()) { + vc->cache_msg(lf, ll); + require(vc->line_values.lvv_sbr.get_data() + != nullptr); + vt->vi->extract( + lf, line_number, vc->line_values); + } - yajlpp_gen gen; + struct line_range time_range; - yajl_gen_config(gen, yajl_gen_beautify, false); + time_range = find_string_attr_range( + vt->vi->vi_attrs, &logline::L_TIMESTAMP); - { - yajlpp_array arr(gen); + const auto* time_src + = vc->line_values.lvv_sbr.get_data() + + time_range.lr_start; + struct timeval actual_tv; + struct exttm tm; - for (const auto& str : meta.bm_tags) { - arr.gen(str); + if (lf->get_format()->lf_date_time.scan( + time_src, + time_range.length(), + lf->get_format()->get_timestamp_formats(), + &tm, + actual_tv, + false)) + { + sql_strftime(buffer, sizeof(buffer), actual_tv); + } + } else { + sql_strftime(buffer, + sizeof(buffer), + ll->get_time(), + ll->get_millis()); + } + sqlite3_result_text( + ctx, buffer, strlen(buffer), SQLITE_TRANSIENT); + break; } - } - - to_sqlite(ctx, json_string(gen)); - } - break; - } + case log_footer_columns::idle_msecs: { + if (vc->log_cursor.lc_curr_line == 0) { + sqlite3_result_int64(ctx, 0); + } else { + content_line_t prev_cl(vt->lss->at( + vis_line_t(vc->log_cursor.lc_curr_line - 1))); + auto prev_lf = vt->lss->find(prev_cl); + auto prev_ll = prev_lf->begin() + prev_cl; + uint64_t prev_time, curr_line_time; + + prev_time = prev_ll->get_time() * 1000ULL; + prev_time += prev_ll->get_millis(); + curr_line_time = ll->get_time() * 1000ULL; + curr_line_time += ll->get_millis(); + // require(curr_line_time >= prev_time); + sqlite3_result_int64(ctx, + curr_line_time - prev_time); + } + break; + } + case log_footer_columns::mark: { + sqlite3_result_int(ctx, ll->is_marked()); + break; + } + case log_footer_columns::comment: { + auto line_meta_opt = vt->lss->find_bookmark_metadata( + vc->log_cursor.lc_curr_line); + if (!line_meta_opt + || line_meta_opt.value()->bm_comment.empty()) + { + sqlite3_result_null(ctx); + } else { + const auto& meta = *(line_meta_opt.value()); + sqlite3_result_text(ctx, + meta.bm_comment.c_str(), + meta.bm_comment.length(), + SQLITE_TRANSIENT); + } + break; + } + case log_footer_columns::tags: { + auto line_meta_opt = vt->lss->find_bookmark_metadata( + vc->log_cursor.lc_curr_line); + if (!line_meta_opt + || line_meta_opt.value()->bm_tags.empty()) + { + sqlite3_result_null(ctx); + } else { + const auto& meta = *(line_meta_opt.value()); - case VT_COL_FILTERS: { - const auto& filter_mask - = (*ld)->ld_filter_state.lfo_filter_state.tfs_mask; + yajlpp_gen gen; - if (!filter_mask[line_number]) { - sqlite3_result_null(ctx); - } else { - const auto& filters = vt->lss->get_filters(); - yajlpp_gen gen; + yajl_gen_config(gen, yajl_gen_beautify, false); - yajl_gen_config(gen, yajl_gen_beautify, false); + { + yajlpp_array arr(gen); - { - yajlpp_array arr(gen); + for (const auto& str : meta.bm_tags) { + arr.gen(str); + } + } - for (const auto& filter : filters) { - if (filter->lf_deleted) { - continue; + to_sqlite(ctx, json_string(gen)); + } + break; + } + case log_footer_columns::annotations: { + if (sqlite3_vtab_nochange(ctx)) { + return SQLITE_OK; } - uint32_t mask = (1UL << filter->get_index()); - - if (filter_mask[line_number] & mask) { - arr.gen(filter->get_index()); + auto line_meta_opt = vt->lss->find_bookmark_metadata( + vc->log_cursor.lc_curr_line); + if (!line_meta_opt + || line_meta_opt.value() + ->bm_annotations.la_pairs.empty()) + { + sqlite3_result_null(ctx); + } else { + const auto& meta = *(line_meta_opt.value()); + to_sqlite( + ctx, + logmsg_annotations_handlers.to_json_string( + meta.bm_annotations)); } + break; } - } + case log_footer_columns::filters: { + const auto& filter_mask + = (*ld)->ld_filter_state.lfo_filter_state.tfs_mask; - to_sqlite(ctx, gen.to_string_fragment()); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } - break; - } + if (!filter_mask[line_number]) { + sqlite3_result_null(ctx); + } else { + const auto& filters = vt->lss->get_filters(); + yajlpp_gen gen; - default: - if (col > (VT_COL_MAX + vt->vi->vi_column_count - 1)) { - auto footer_column = static_cast<log_footer_columns>( - col - (VT_COL_MAX + vt->vi->vi_column_count - 1) - 1); + yajl_gen_config(gen, yajl_gen_beautify, false); - switch (footer_column) { + { + yajlpp_array arr(gen); + + for (const auto& filter : filters) { + if (filter->lf_deleted) { + continue; + } + + uint32_t mask + = (1UL << filter->get_index()); + + if (filter_mask[line_number] & mask) { + arr.gen(filter->get_index()); + } + } + } + + to_sqlite(ctx, gen.to_string_fragment()); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); + } + break; + } case log_footer_columns::opid: { if (vc->line_values.lvv_values.empty()) { vc->cache_msg(lf, ll); @@ -820,16 +866,9 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) vt->vi->extract(lf, line_number, vc->line_values); } - auto opid_opt = get_string_attr(vt->vi->vi_attrs, - logline::L_OPID); - if (opid_opt) { - auto opid_range - = opid_opt.value().saw_string_attr->sa_range; - - to_sqlite( - ctx, - vc->line_values.lvv_sbr.to_string_fragment( - opid_range.lr_start, opid_range.length())); + if (vc->line_values.lvv_opid_value) { + to_sqlite(ctx, + vc->line_values.lvv_opid_value.value()); } else { sqlite3_result_null(ctx); } @@ -859,15 +898,19 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) case log_footer_columns::path: { const auto& fn = lf->get_filename(); - sqlite3_result_text( - ctx, fn.c_str(), fn.length(), SQLITE_STATIC); + sqlite3_result_text(ctx, + fn.c_str(), + fn.native().length(), + SQLITE_STATIC); break; } case log_footer_columns::unique_path: { const auto& fn = lf->get_unique_path(); - sqlite3_result_text( - ctx, fn.c_str(), fn.length(), SQLITE_STATIC); + sqlite3_result_text(ctx, + fn.c_str(), + fn.native().length(), + SQLITE_STATIC); break; } case log_footer_columns::text: { @@ -958,7 +1001,8 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col) vt->vi->extract(lf, line_number, vc->line_values); } - int sub_col = col - VT_COL_MAX; + auto sub_col = logline_value_meta::table_column{ + (size_t) (col - VT_COL_MAX)}; auto lv_iter = find_if(vc->line_values.lvv_values.begin(), vc->line_values.lvv_values.end(), logline_value_cmp(nullptr, sub_col)); @@ -1179,7 +1223,7 @@ log_cursor::update(unsigned char op, vis_line_t vl, constraint_t cons) case SQLITE_INDEX_CONSTRAINT_LE: if (vl < 0_vl) { this->lc_curr_line = this->lc_end_line; - } else { + } else if (vl < this->lc_end_line) { this->lc_end_line = vl + (cons == constraint_t::unique ? 1_vl : 0_vl); } @@ -1187,7 +1231,7 @@ log_cursor::update(unsigned char op, vis_line_t vl, constraint_t cons) case SQLITE_INDEX_CONSTRAINT_LT: if (vl <= 0_vl) { this->lc_curr_line = this->lc_end_line; - } else { + } else if (vl < this->lc_end_line) { this->lc_end_line = vl; } break; @@ -1250,19 +1294,19 @@ log_cursor::string_constraint::matches(const std::string& sf) const } } -struct time_range { - nonstd::optional<timeval> tr_begin; - nonstd::optional<timeval> tr_end; +struct vtab_time_range { + nonstd::optional<timeval> vtr_begin; + nonstd::optional<timeval> vtr_end; - bool empty() const { return !this->tr_begin && !this->tr_end; } + bool empty() const { return !this->vtr_begin && !this->vtr_end; } void add(const timeval& tv) { - if (!this->tr_begin || tv < this->tr_begin) { - this->tr_begin = tv; + if (!this->vtr_begin || tv < this->vtr_begin) { + this->vtr_begin = tv; } - if (!this->tr_end || this->tr_end < tv) { - this->tr_end = tv; + if (!this->vtr_end || this->vtr_end < tv) { + this->vtr_end = tv; } } }; @@ -1310,7 +1354,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, p_cur->log_cursor.lc_curr_line = 0_vl; p_cur->log_cursor.lc_end_line = vis_line_t(vt->lss->text_line_count()); - nonstd::optional<time_range> log_time_range; + nonstd::optional<vtab_time_range> log_time_range; nonstd::optional<log_cursor::opid_hash> opid_val; std::vector<log_cursor::string_constraint> log_path_constraints; std::vector<log_cursor::string_constraint> log_unique_path_constraints; @@ -1363,23 +1407,23 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, case SQLITE_INDEX_CONSTRAINT_EQ: case SQLITE_INDEX_CONSTRAINT_IS: if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } log_time_range->add(tv); break; case SQLITE_INDEX_CONSTRAINT_GT: case SQLITE_INDEX_CONSTRAINT_GE: if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } - log_time_range->tr_begin = tv; + log_time_range->vtr_begin = tv; break; case SQLITE_INDEX_CONSTRAINT_LT: case SQLITE_INDEX_CONSTRAINT_LE: if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } - log_time_range->tr_end = tv; + log_time_range->vtr_end = tv; break; } } @@ -1407,23 +1451,23 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, case SQLITE_INDEX_CONSTRAINT_EQ: case SQLITE_INDEX_CONSTRAINT_IS: if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } log_time_range->add(tv); break; case SQLITE_INDEX_CONSTRAINT_GT: case SQLITE_INDEX_CONSTRAINT_GE: if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } - log_time_range->tr_begin = tv; + log_time_range->vtr_begin = tv; break; case SQLITE_INDEX_CONSTRAINT_LT: case SQLITE_INDEX_CONSTRAINT_LE: if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } - log_time_range->tr_end = tv; + log_time_range->vtr_end = tv; break; } break; @@ -1455,21 +1499,24 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, auto opid = from_sqlite<string_fragment>()( argc, argv, lpc); if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } for (const auto& file_data : *vt->lss) { if (file_data->get_file_ptr() == nullptr) { continue; } - safe::ReadAccess<logfile::safe_opid_map> + safe::ReadAccess<logfile::safe_opid_state> r_opid_map( file_data->get_file_ptr()->get_opids()); - const auto& iter = r_opid_map->find(opid); - if (iter == r_opid_map->end()) { + const auto& iter + = r_opid_map->los_opid_ranges.find(opid); + if (iter == r_opid_map->los_opid_ranges.end()) { continue; } - log_time_range->add(iter->second.otr_begin); - log_time_range->add(iter->second.otr_end); + log_time_range->add( + iter->second.otr_range.tr_begin); + log_time_range->add( + iter->second.otr_range.tr_end); } opid_val = log_cursor::opid_hash{ @@ -1489,7 +1536,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, auto found = false; if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } for (const auto& file_data : *vt->lss) { auto* lf = file_data->get_file_ptr(); @@ -1522,7 +1569,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, auto found = false; if (!log_time_range) { - log_time_range = time_range{}; + log_time_range = vtab_time_range{}; } for (const auto& file_data : *vt->lss) { auto* lf = file_data->get_file_ptr(); @@ -1545,6 +1592,14 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, } break; } + case log_footer_columns::partition: + case log_footer_columns::actual_time: + case log_footer_columns::idle_msecs: + case log_footer_columns::mark: + case log_footer_columns::comment: + case log_footer_columns::tags: + case log_footer_columns::annotations: + case log_footer_columns::filters: case log_footer_columns::text: case log_footer_columns::body: case log_footer_columns::raw_text: @@ -1654,25 +1709,25 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, } else if (log_time_range->empty()) { p_cur->log_cursor.lc_curr_line = p_cur->log_cursor.lc_end_line; } else { - if (log_time_range->tr_begin) { + if (log_time_range->vtr_begin) { auto vl_opt - = vt->lss->row_for_time(log_time_range->tr_begin.value()); + = vt->lss->row_for_time(log_time_range->vtr_begin.value()); if (!vl_opt) { p_cur->log_cursor.lc_curr_line = p_cur->log_cursor.lc_end_line; } else { p_cur->log_cursor.lc_curr_line = vl_opt.value(); } } - if (log_time_range->tr_end) { + if (log_time_range->vtr_end) { auto vl_max_opt - = vt->lss->row_for_time(log_time_range->tr_end.value()); + = vt->lss->row_for_time(log_time_range->vtr_end.value()); if (vl_max_opt) { p_cur->log_cursor.lc_end_line = vl_max_opt.value(); for (const auto& msg_info : vt->lss->window_at(vl_max_opt.value(), vis_line_t(vt->lss->text_line_count()))) { - if (log_time_range->tr_end.value() + if (log_time_range->vtr_end.value() < msg_info.get_logline().get_timeval()) { break; @@ -1829,6 +1884,14 @@ vt_best_index(sqlite3_vtab* tab, sqlite3_index_info* p_info) sql_constraint_op_name(op))); break; } + case log_footer_columns::partition: + case log_footer_columns::actual_time: + case log_footer_columns::idle_msecs: + case log_footer_columns::mark: + case log_footer_columns::comment: + case log_footer_columns::tags: + case log_footer_columns::annotations: + case log_footer_columns::filters: case log_footer_columns::text: case log_footer_columns::body: case log_footer_columns::raw_text: @@ -1911,13 +1974,18 @@ vt_update(sqlite3_vtab* tab, && sqlite3_value_int64(argv[0]) == sqlite3_value_int64(argv[1])) { int64_t rowid = sqlite3_value_int64(argv[0]) >> 8; - int val = sqlite3_value_int(argv[2 + VT_COL_MARK]); + int val = sqlite3_value_int( + argv[2 + vt->footer_index(log_footer_columns::mark)]); vis_line_t vrowid(rowid); - const auto* part_name = sqlite3_value_text(argv[2 + VT_COL_PARTITION]); - const auto* log_comment - = sqlite3_value_text(argv[2 + VT_COL_LOG_COMMENT]); - const auto* log_tags = sqlite3_value_text(argv[2 + VT_COL_LOG_TAGS]); + const auto* part_name = sqlite3_value_text( + argv[2 + vt->footer_index(log_footer_columns::partition)]); + const auto* log_comment = sqlite3_value_text( + argv[2 + vt->footer_index(log_footer_columns::comment)]); + const auto log_tags = from_sqlite<nonstd::optional<string_fragment>>()( + argc, argv, 2 + vt->footer_index(log_footer_columns::tags)); + const auto log_annos = from_sqlite<nonstd::optional<string_fragment>>()( + argc, argv, 2 + vt->footer_index(log_footer_columns::annotations)); bookmark_metadata tmp_bm; if (log_tags) { @@ -1936,7 +2004,7 @@ vt_update(sqlite3_vtab* tab, errors.emplace_back(msg); }) .with_obj(tmp_bm); - ypc.parse_doc(string_fragment{log_tags}); + ypc.parse_doc(log_tags.value()); if (!errors.empty()) { auto top_error = lnav::console::user_message::error( attr_line_t("invalid value for ") @@ -1945,30 +2013,53 @@ vt_update(sqlite3_vtab* tab, .append_quoted(lnav::roles::symbol( vt->vi->get_name().to_string()))) .with_reason(errors[0].to_attr_line({})); - auto json_error = lnav::to_json(top_error); - tab->zErrMsg - = sqlite3_mprintf("lnav-error:%s", json_error.c_str()); + set_vtable_errmsg(tab, top_error); + return SQLITE_ERROR; + } + } + if (log_annos) { + static const intern_string_t SRC + = intern_string::lookup("log_annotations"); + + auto parse_res = logmsg_annotations_handlers.parser_for(SRC).of( + log_annos.value()); + if (parse_res.isErr()) { + set_vtable_errmsg(tab, parse_res.unwrapErr()[0]); return SQLITE_ERROR; } + + tmp_bm.bm_annotations = parse_res.unwrap(); } - auto& bv = vt->tc->get_bookmarks()[&textview_curses::BM_META]; - bool has_meta = part_name != nullptr || log_comment != nullptr - || log_tags != nullptr; + auto& bv_meta = vt->tc->get_bookmarks()[&textview_curses::BM_META]; + bool has_meta = log_comment != nullptr || log_tags.has_value() + || log_annos.has_value(); - if (binary_search(bv.begin(), bv.end(), vrowid) && !has_meta) { + if (std::binary_search(bv_meta.begin(), bv_meta.end(), vrowid) + && !has_meta) + { vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, false); - vt->lss->erase_bookmark_metadata(vrowid); vt->lss->set_line_meta_changed(); } + if (!has_meta && part_name == nullptr) { + vt->lss->erase_bookmark_metadata(vrowid); + } + + if (part_name) { + auto& line_meta = vt->lss->get_bookmark_metadata(vrowid); + line_meta.bm_name = std::string((const char*) part_name); + vt->tc->set_user_mark(&textview_curses::BM_PARTITION, vrowid, true); + } else { + vt->tc->set_user_mark( + &textview_curses::BM_PARTITION, vrowid, false); + } + if (has_meta) { auto& line_meta = vt->lss->get_bookmark_metadata(vrowid); vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, true); - if (part_name) { - line_meta.bm_name = std::string((const char*) part_name); - } else { + if (part_name == nullptr) { line_meta.bm_name.clear(); } if (log_comment) { @@ -1988,6 +2079,15 @@ vt_update(sqlite3_vtab* tab, } else { line_meta.bm_tags.clear(); } + if (log_annos) { + line_meta.bm_annotations = std::move(tmp_bm.bm_annotations); + } else if (!sqlite3_value_nochange( + argv[2 + + vt->footer_index( + log_footer_columns::annotations)])) + { + line_meta.bm_annotations.la_pairs.clear(); + } vt->lss->set_line_meta_changed(); } |