summaryrefslogtreecommitdiffstats
path: root/src/log_search_table.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 17:44:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 17:44:55 +0000
commit5068d34c08f951a7ea6257d305a1627b09a95817 (patch)
tree08213e2be853396a3b07ce15dbe222644dcd9a89 /src/log_search_table.cc
parentInitial commit. (diff)
downloadlnav-5068d34c08f951a7ea6257d305a1627b09a95817.tar.xz
lnav-5068d34c08f951a7ea6257d305a1627b09a95817.zip
Adding upstream version 0.11.1.upstream/0.11.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/log_search_table.cc')
-rw-r--r--src/log_search_table.cc270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/log_search_table.cc b/src/log_search_table.cc
new file mode 100644
index 0000000..8c9d3c9
--- /dev/null
+++ b/src/log_search_table.cc
@@ -0,0 +1,270 @@
+/**
+ * Copyright (c) 2020, Timothy Stack
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Timothy Stack nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "log_search_table.hh"
+
+#include "base/ansi_scrubber.hh"
+#include "column_namer.hh"
+#include "config.h"
+#include "sql_util.hh"
+
+const static std::string MATCH_INDEX = "match_index";
+static auto match_index_name = intern_string::lookup("match_index");
+
+log_search_table::log_search_table(std::shared_ptr<lnav::pcre2pp::code> code,
+ intern_string_t table_name)
+ : log_vtab_impl(table_name), lst_regex(code),
+ lst_match_data(this->lst_regex->create_match_data())
+{
+}
+
+void
+log_search_table::get_columns_int(std::vector<vtab_column>& cols) const
+{
+ column_namer cn{column_namer::language::SQL};
+
+ if (this->lst_format != nullptr) {
+ this->lst_column_metas = this->lst_format->get_value_metadata();
+ this->lst_format_column_count = this->lst_column_metas.size();
+ cols.resize(this->lst_column_metas.size());
+ for (const auto& meta : this->lst_column_metas) {
+ if (meta.lvm_column == -1) {
+ continue;
+ }
+ auto type_pair
+ = log_vtab_impl::logline_value_to_sqlite_type(meta.lvm_kind);
+ cols[meta.lvm_column].vc_name = meta.lvm_name.to_string();
+ cols[meta.lvm_column].vc_type = type_pair.first;
+ cols[meta.lvm_column].vc_subtype = type_pair.second;
+ }
+ }
+
+ this->lst_column_metas.emplace_back(
+ match_index_name, value_kind_t::VALUE_INTEGER, cols.size());
+ cols.emplace_back(MATCH_INDEX, SQLITE_INTEGER);
+ cn.add_column(string_fragment::from_const("__all__"));
+ auto captures = this->lst_regex->get_captures();
+ for (int lpc = 0; lpc < this->lst_regex->get_capture_count(); lpc++) {
+ std::string collator;
+ int sqlite_type = SQLITE3_TEXT;
+
+ auto colname
+ = cn.add_column(string_fragment::from_c_str(
+ this->lst_regex->get_name_for_capture(lpc + 1)))
+ .to_string();
+ if (captures.size() == (size_t) this->lst_regex->get_capture_count()) {
+ auto cap_re = captures[lpc].to_string();
+ sqlite_type = guess_type_from_pcre(cap_re, collator);
+ switch (sqlite_type) {
+ case SQLITE_FLOAT:
+ this->lst_column_metas.emplace_back(
+ intern_string::lookup(colname),
+ value_kind_t::VALUE_FLOAT,
+ cols.size());
+ break;
+ case SQLITE_INTEGER:
+ this->lst_column_metas.emplace_back(
+ intern_string::lookup(colname),
+ value_kind_t::VALUE_INTEGER,
+ cols.size());
+ break;
+ default:
+ this->lst_column_metas.emplace_back(
+ intern_string::lookup(colname),
+ value_kind_t::VALUE_TEXT,
+ cols.size());
+ break;
+ }
+ }
+ cols.emplace_back(colname, sqlite_type, collator);
+ }
+}
+
+void
+log_search_table::get_foreign_keys(std::vector<std::string>& keys_inout) const
+{
+ log_vtab_impl::get_foreign_keys(keys_inout);
+ keys_inout.emplace_back(MATCH_INDEX);
+}
+
+bool
+log_search_table::next(log_cursor& lc, logfile_sub_source& lss)
+{
+ this->vi_attrs.clear();
+ this->lst_line_values_cache.lvv_values.clear();
+
+ if (this->lst_match_index >= 0) {
+ auto match_res = this->lst_regex->capture_from(this->lst_content)
+ .at(this->lst_remaining)
+ .into(this->lst_match_data)
+ .matches(PCRE2_NO_UTF_CHECK)
+ .ignore_error();
+
+ if (match_res) {
+#if 0
+ log_debug("matched within line: %d",
+ this->lst_match_context.get_count());
+#endif
+ this->lst_remaining = match_res->f_remaining;
+ this->lst_match_index += 1;
+ return true;
+ }
+
+ // log_debug("done matching message");
+ this->lst_remaining.clear();
+ this->lst_match_index = -1;
+ return false;
+ }
+
+ this->lst_match_index = -1;
+
+ if (lc.is_eof()) {
+ return true;
+ }
+
+ if (!this->is_valid(lc, lss)) {
+ return false;
+ }
+
+ auto cl = lss.at(lc.lc_curr_line);
+ auto* lf = lss.find_file_ptr(cl);
+
+ auto lf_iter = lf->begin() + cl;
+
+ if (!lf_iter->is_message()) {
+ return false;
+ }
+
+ if (this->lst_mismatch_bitmap.is_bit_set(lc.lc_curr_line)) {
+ // log_debug("%d: mismatch, aborting", (int) lc.lc_curr_line);
+ return false;
+ }
+
+ // log_debug("%d: doing message", (int) lc.lc_curr_line);
+ auto& sbr = this->lst_line_values_cache.lvv_sbr;
+ lf->read_full_message(lf_iter, sbr);
+ sbr.erase_ansi();
+ lf->get_format()->annotate(
+ cl, this->vi_attrs, this->lst_line_values_cache, false);
+ this->lst_content
+ = this->lst_line_values_cache.lvv_sbr.to_string_fragment();
+
+ auto match_res = this->lst_regex->capture_from(this->lst_content)
+ .into(this->lst_match_data)
+ .matches(PCRE2_NO_UTF_CHECK)
+ .ignore_error();
+
+ if (!match_res) {
+ this->lst_mismatch_bitmap.set_bit(lc.lc_curr_line);
+ return false;
+ }
+
+ this->lst_remaining = match_res->f_remaining;
+ this->lst_match_index = 0;
+
+ return true;
+}
+
+void
+log_search_table::extract(logfile* lf,
+ uint64_t line_number,
+ logline_value_vector& values)
+{
+ auto& line = values.lvv_sbr;
+ if (this->lst_format != nullptr) {
+ values = this->lst_line_values_cache;
+ }
+ values.lvv_values.emplace_back(
+ this->lst_column_metas[this->lst_format_column_count],
+ this->lst_match_index);
+ for (int lpc = 0; lpc < this->lst_regex->get_capture_count(); lpc++) {
+ const auto cap = this->lst_match_data[lpc + 1];
+ if (cap) {
+ values.lvv_values.emplace_back(
+ this->lst_column_metas[this->lst_format_column_count + 1 + lpc],
+ line,
+ to_line_range(cap.value()));
+ } else {
+ values.lvv_values.emplace_back(
+ this->lst_column_metas[this->lst_format_column_count + 1
+ + lpc]);
+ }
+ }
+}
+
+void
+log_search_table::get_primary_keys(std::vector<std::string>& keys_out) const
+{
+ keys_out.emplace_back("log_line");
+ keys_out.emplace_back("match_index");
+}
+
+void
+log_search_table::filter(log_cursor& lc, logfile_sub_source& lss)
+{
+ if (this->lst_format != nullptr) {
+ lc.lc_format_name = this->lst_format->get_name();
+ }
+ if (!this->lst_log_path_glob.empty()) {
+ lc.lc_log_path.emplace_back(SQLITE_INDEX_CONSTRAINT_GLOB,
+ this->lst_log_path_glob);
+ }
+ if (this->lst_log_level) {
+ lc.lc_level_constraint = log_cursor::level_constraint{
+ SQLITE_INDEX_CONSTRAINT_EQ,
+ this->lst_log_level.value(),
+ };
+ }
+ this->lst_match_index = -1;
+
+ if (lss.lss_index_generation != this->lst_index_generation) {
+ log_debug("%s:index generation changed from %d to %d, resetting...",
+ this->vi_name.c_str(),
+ this->lst_index_generation,
+ lss.lss_index_generation);
+ this->lst_mismatch_bitmap
+ = auto_buffer::alloc_bitmap(lss.text_line_count());
+ this->lst_index_generation = lss.lss_index_generation;
+ }
+
+ if (this->lst_mismatch_bitmap.bitmap_size() < lss.text_line_count()) {
+ this->lst_mismatch_bitmap.expand_bitmap_to(lss.text_line_count());
+ this->lst_mismatch_bitmap.resize_bitmap(lss.text_line_count());
+#if 1
+ log_debug("%s:bitmap resize %d:%d",
+ this->vi_name.c_str(),
+ this->lst_mismatch_bitmap.size(),
+ this->lst_mismatch_bitmap.capacity());
+#endif
+ }
+ if (!lc.lc_indexed_lines.empty()) {
+ lc.lc_curr_line = lc.lc_indexed_lines.back();
+ lc.lc_indexed_lines.pop_back();
+ }
+}