mirror of
https://github.com/tstack/lnav
synced 2024-11-01 21:40:34 +00:00
[bookmarks] add support for tags and comments for log lines
Initial work for #446 and #447 TODO: filtering on tags/comments Also did a bunch of clang-tidy cleanups and improvements to the online help.
This commit is contained in:
parent
b8fc956677
commit
4ccae48aea
17
NEWS
17
NEWS
@ -1,8 +1,23 @@
|
||||
|
||||
lnav v0.8.4:
|
||||
Features:
|
||||
* Added the ':comment' command that can be used to attach a comment to a
|
||||
log line. The comment will be displayed below the line, like so:
|
||||
2017-01-01T15:30:00 error: computer is on fire
|
||||
+ This is where it all went wrong
|
||||
The ':clear-comment' command will remove the attached comment. Comments
|
||||
are searchable with the standard search mechanism and they are available
|
||||
in SQL through the "log_comment" column.
|
||||
* Added the ':tag', ':untag', and ':delete-tags' commands that can be used
|
||||
to attach/detach tags on the top log line and delete all instances of
|
||||
a tag. Tags are also searchable and are available in SQL as a JSON
|
||||
array in the "log_tags" column.
|
||||
* Pressing left-arrow while viewing log messages will reveal the source
|
||||
file name for each line. Pressing again will reveal the full path.
|
||||
* Added the ":hide-unmarked-lines" and ":show-unmarked-lines" commands
|
||||
that hide/show lines based on whether they are bookmarked.
|
||||
* Added the "json_contains()" SQL function to check if a JSON value
|
||||
contains a number of a string.
|
||||
|
||||
Interface Changes:
|
||||
* When typing in a search, instead of moving the view to the first match
|
||||
@ -10,6 +25,8 @@ lnav v0.8.4:
|
||||
window.
|
||||
* The pretty-print view maintains highlighting from the log view.
|
||||
* The pretty-print view no longer tries to reverse lookup IP addresses.
|
||||
* The online help for commands and SQL functions now includes a 'See Also'
|
||||
section that lists related commands/functions.
|
||||
|
||||
Fixes:
|
||||
* The HOME key should now work in the command-prompt and move the cursor
|
||||
|
@ -29,6 +29,24 @@ with the following commands:
|
||||
* hide-lines-after <abs-time|rel-time> - Hide lines after the given time.
|
||||
* show-lines-before-and-after - Show lines that were hidden by the "hide-lines" commands.
|
||||
|
||||
Bookmarks
|
||||
---------
|
||||
|
||||
* mark - Bookmark the top line in the view.
|
||||
* partition-name <name> - Partition the log file around the top line in the
|
||||
log view and assign the given name. The top line and all that follow, up to
|
||||
the start of the next partition, will be included in the partition. The name
|
||||
of the partition for a log line is visible in the top status bar to the right
|
||||
of the time stamp. The partition name for a log line can be retrieved via
|
||||
the *log_part* field in any log table.
|
||||
* comment <text> - Attach a comment to the top line in the log view and
|
||||
bookmark that line.
|
||||
* clear-comment - Clear the comment attached to the top line in the view.
|
||||
* tag <tag1> [<tag2> ... [<tagN>]] - Attach one or more tags to a log line.
|
||||
A '#' will automatically be prepended to the tag name if it is not already there.
|
||||
* untag <tag1> [<tag2> ... [<tagN>]] - Detach one or more tags from a log line.
|
||||
* delete-tags <tag1> [<tag2> ... [<tagN>]] - Detach the given tags from all log lines.
|
||||
|
||||
Navigation
|
||||
----------
|
||||
|
||||
@ -37,7 +55,6 @@ Navigation
|
||||
relative time (e.g. 'a minute ago').
|
||||
* relative-goto <line#|N%> - Move the current view up or down by the given
|
||||
amount.
|
||||
* mark - Bookmark the top line in the view.
|
||||
* next-mark error|warning|search|user|file|partition - Move to the next
|
||||
bookmark of the given type in the current view.
|
||||
* prev-mark error|warning|search|user|file|partition - Move to the previous
|
||||
|
@ -163,11 +163,11 @@ set(diag_STAT_SRCS
|
||||
filesystem/path.h
|
||||
filesystem/resolver.h
|
||||
|
||||
../../lbuild/src/config.h
|
||||
../../lbuild-debug/src/config.h
|
||||
)
|
||||
|
||||
set(lnav_SRCS lnav.cc)
|
||||
|
||||
include_directories(../../lbuild/src /opt/local/include)
|
||||
include_directories(../../lbuild-debug/src /opt/local/include)
|
||||
include_directories(SYSTEM .)
|
||||
add_executable(lnav ${lnav_SRCS} ${diag_STAT_SRCS})
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
set<string> bookmark_metadata::KNOWN_TAGS;
|
||||
|
||||
template<typename LineType>
|
||||
LineType bookmark_vector<LineType>::next(LineType start) const
|
||||
{
|
||||
|
@ -33,6 +33,7 @@
|
||||
#define __bookmarks_hh
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
@ -41,7 +42,43 @@
|
||||
#include "listview_curses.hh"
|
||||
|
||||
struct bookmark_metadata {
|
||||
static std::set<std::string> KNOWN_TAGS;
|
||||
|
||||
std::string bm_name;
|
||||
std::string bm_comment;
|
||||
std::vector<std::string> bm_tags;
|
||||
|
||||
void add_tag(const std::string &tag) {
|
||||
if (std::find(this->bm_tags.begin(),
|
||||
this->bm_tags.end(),
|
||||
tag) == this->bm_tags.end()) {
|
||||
this->bm_tags.push_back(tag);
|
||||
}
|
||||
};
|
||||
|
||||
bool remove_tag(const std::string &tag) {
|
||||
auto iter = std::find(this->bm_tags.begin(),
|
||||
this->bm_tags.end(),
|
||||
tag);
|
||||
bool retval = false;
|
||||
|
||||
if (iter != this->bm_tags.end()) {
|
||||
this->bm_tags.erase(iter);
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
|
||||
bool empty() {
|
||||
return this->bm_name.empty() &&
|
||||
this->bm_comment.empty() &&
|
||||
this->bm_tags.empty();
|
||||
};
|
||||
|
||||
void clear() {
|
||||
this->bm_comment.clear();
|
||||
this->bm_tags.clear();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -59,7 +96,12 @@ struct bookmark_metadata {
|
||||
*/
|
||||
template<typename LineType>
|
||||
class bookmark_vector : public std::vector<LineType> {
|
||||
typedef std::vector<LineType> base_vector;
|
||||
|
||||
public:
|
||||
typedef typename base_vector::size_type size_type;
|
||||
typedef typename base_vector::iterator iterator;
|
||||
typedef typename base_vector::const_iterator const_iterator;
|
||||
|
||||
/**
|
||||
* Insert a bookmark into this vector, but only if it is not already in the
|
||||
@ -67,9 +109,9 @@ public:
|
||||
*
|
||||
* @param vl The line to bookmark.
|
||||
*/
|
||||
typename bookmark_vector::iterator insert_once(LineType vl)
|
||||
iterator insert_once(LineType vl)
|
||||
{
|
||||
typename bookmark_vector::iterator lb, retval;
|
||||
iterator lb, retval;
|
||||
|
||||
require(vl >= 0);
|
||||
|
||||
@ -85,6 +127,18 @@ public:
|
||||
return retval;
|
||||
};
|
||||
|
||||
std::pair<iterator, iterator> equal_range(LineType start, LineType stop) {
|
||||
auto lb = std::lower_bound(this->begin(), this->end(), start);
|
||||
|
||||
if (stop == LineType(-1)) {
|
||||
return std::make_pair(lb, this->end());
|
||||
} else {
|
||||
auto up = std::upper_bound(this->begin(), this->end(), stop);
|
||||
|
||||
return std::make_pair(lb, up);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param start The value to start the search for the next bookmark.
|
||||
* @return The next bookmark value in the vector or -1 if there are
|
||||
|
@ -93,10 +93,10 @@ string execute_command(exec_context &ec, const string &cmdline)
|
||||
|
||||
if ((iter = lnav_commands.find(args[0])) ==
|
||||
lnav_commands.end()) {
|
||||
msg = "error: unknown command - " + args[0];
|
||||
msg = ec.get_error_prefix() + "unknown command - " + args[0];
|
||||
}
|
||||
else {
|
||||
msg = iter->second.c_func(ec, cmdline, args);
|
||||
msg = iter->second->c_func(ec, cmdline, args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +129,11 @@ string execute_sql(exec_context &ec, const string &sql, string &alt_msg)
|
||||
}
|
||||
|
||||
ec.ec_accumulator.clear();
|
||||
sql_progress_guard progress_guard(sql_progress);
|
||||
|
||||
pair<string, int> source = ec.ec_source.top();
|
||||
sql_progress_guard progress_guard(sql_progress,
|
||||
source.first,
|
||||
source.second);
|
||||
gettimeofday(&start_tv, NULL);
|
||||
retcode = sqlite3_prepare_v2(lnav_data.ld_db.in(),
|
||||
stmt_str.c_str(),
|
||||
@ -139,7 +143,7 @@ string execute_sql(exec_context &ec, const string &sql, string &alt_msg)
|
||||
if (retcode != SQLITE_OK) {
|
||||
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
||||
|
||||
retval = "error: " + string(errmsg);
|
||||
retval = ec.get_error_prefix() + string(errmsg);
|
||||
alt_msg = "";
|
||||
}
|
||||
else if (stmt == NULL) {
|
||||
@ -244,7 +248,7 @@ string execute_sql(exec_context &ec, const string &sql, string &alt_msg)
|
||||
|
||||
log_error("sqlite3_step error code: %d", retcode);
|
||||
errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
||||
retval = "error: " + string(errmsg);
|
||||
retval = ec.get_error_prefix() + string(errmsg);
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
@ -367,12 +371,12 @@ static string execute_file_contents(exec_context &ec, const string &path, bool m
|
||||
}
|
||||
file = stdin;
|
||||
}
|
||||
else if ((file = fopen(path.c_str(), "r")) == NULL) {
|
||||
return "error: unable to open file";
|
||||
else if ((file = fopen(path.c_str(), "r")) == nullptr) {
|
||||
return ec.get_error_prefix() + "unable to open file";
|
||||
}
|
||||
|
||||
int line_number = 0, starting_line_number = 0;
|
||||
char *line = NULL;
|
||||
char *line = nullptr;
|
||||
size_t line_max_size;
|
||||
ssize_t line_size;
|
||||
string cmdline;
|
||||
@ -442,10 +446,10 @@ string execute_file(exec_context &ec, const string &path_and_args, bool multilin
|
||||
log_info("Executing file: %s", path_and_args.c_str());
|
||||
|
||||
if (!lexer.split(split_args, ec.ec_local_vars.top())) {
|
||||
retval = "error: unable to parse path";
|
||||
retval = ec.get_error_prefix() + "unable to parse path";
|
||||
}
|
||||
else if (split_args.empty()) {
|
||||
retval = "error: no script specified";
|
||||
retval = ec.get_error_prefix() + "no script specified";
|
||||
}
|
||||
else {
|
||||
ec.ec_local_vars.push(map<string, string>());
|
||||
@ -516,7 +520,8 @@ string execute_file(exec_context &ec, const string &path_and_args, bool multilin
|
||||
retval = result;
|
||||
}
|
||||
else {
|
||||
retval = "error: unknown script -- " + script_name + " -- " + open_error;
|
||||
retval = ec.get_error_prefix()
|
||||
+ "unknown script -- " + script_name + " -- " + open_error;
|
||||
}
|
||||
ec.ec_local_vars.pop();
|
||||
}
|
||||
@ -528,6 +533,7 @@ string execute_from_file(exec_context &ec, const string &path, int line_number,
|
||||
{
|
||||
string retval, alt_msg;
|
||||
|
||||
ec.ec_source.emplace(path, line_number);
|
||||
switch (mode) {
|
||||
case ':':
|
||||
retval = execute_command(ec, cmdline);
|
||||
@ -561,6 +567,8 @@ string execute_from_file(exec_context &ec, const string &path, int line_number,
|
||||
line_number,
|
||||
retval.c_str());
|
||||
|
||||
ec.ec_source.pop();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -607,6 +615,7 @@ void execute_init_commands(exec_context &ec, vector<pair<string, string> > &msgs
|
||||
}
|
||||
|
||||
db_label_source &dls = lnav_data.ld_db_row_source;
|
||||
int option_index = 1;
|
||||
|
||||
log_info("Executing initial commands");
|
||||
for (auto &cmd : lnav_data.ld_commands) {
|
||||
@ -614,6 +623,7 @@ void execute_init_commands(exec_context &ec, vector<pair<string, string> > &msgs
|
||||
|
||||
wait_for_children();
|
||||
|
||||
ec.ec_source.emplace("command-option", option_index++);
|
||||
switch (cmd.at(0)) {
|
||||
case ':':
|
||||
msg = execute_command(ec, cmd.substr(1));
|
||||
@ -639,6 +649,8 @@ void execute_init_commands(exec_context &ec, vector<pair<string, string> > &msgs
|
||||
if (rescan_files()) {
|
||||
rebuild_indexes(true);
|
||||
}
|
||||
|
||||
ec.ec_source.pop();
|
||||
}
|
||||
lnav_data.ld_commands.clear();
|
||||
|
||||
@ -732,7 +744,7 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
|
||||
lnav_data.ld_file_names[desc]
|
||||
.with_fd(pp->get_fd())
|
||||
.with_detect_format(false);
|
||||
lnav_data.ld_files_to_front.push_back(make_pair(desc, 0));
|
||||
lnav_data.ld_files_to_front.emplace_back(desc, 0);
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(
|
||||
X, "to close the file"));
|
||||
|
@ -54,7 +54,18 @@ struct exec_context {
|
||||
ec_sql_callback(sql_callback),
|
||||
ec_pipe_callback(pipe_callback) {
|
||||
this->ec_local_vars.push(std::map<std::string, std::string>());
|
||||
this->ec_path_stack.push_back(".");
|
||||
this->ec_path_stack.emplace_back(".");
|
||||
this->ec_source.emplace("unknown", 0);
|
||||
}
|
||||
|
||||
std::string get_error_prefix() {
|
||||
if (this->ec_source.size() <= 1) {
|
||||
return "error: ";
|
||||
}
|
||||
|
||||
std::pair<std::string, int> source = this->ec_source.top();
|
||||
|
||||
return "error:" + source.first + ":" + std::to_string(source.second) + ":";
|
||||
}
|
||||
|
||||
vis_line_t ec_top_line;
|
||||
@ -65,6 +76,7 @@ struct exec_context {
|
||||
std::stack<std::map<std::string, std::string> > ec_local_vars;
|
||||
std::map<std::string, std::string> ec_global_vars;
|
||||
std::vector<std::string> ec_path_stack;
|
||||
std::stack<std::pair<std::string, int>> ec_source;
|
||||
|
||||
attr_line_t ec_accumulator;
|
||||
|
||||
|
@ -432,12 +432,14 @@ public:
|
||||
};
|
||||
|
||||
bool list_value_for_overlay(const listview_curses &lv,
|
||||
vis_line_t y,
|
||||
int y, int bottom,
|
||||
vis_line_t row,
|
||||
attr_line_t &value_out)
|
||||
{
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
if (y == 0) {
|
||||
this->list_overlay_count(lv);
|
||||
std::string &line = value_out.get_string();
|
||||
db_label_source *dls = this->dos_labels;
|
||||
string_attrs_t &sa = value_out.get_attrs();
|
||||
|
@ -1756,6 +1756,7 @@ int common_extension_functions(struct FuncDef **basic_funcs,
|
||||
.with_summary("Returns the given string concatenated N times.")
|
||||
.with_parameter({"str", "The string to replicate."})
|
||||
.with_parameter({"N", "The number of times to replicate the string."})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT replicate('abc', 3)"})
|
||||
},
|
||||
{ "charindex", 2, SQLITE_UTF8, 0, charindexFunc },
|
||||
@ -1766,6 +1767,7 @@ int common_extension_functions(struct FuncDef **basic_funcs,
|
||||
.with_summary("Returns the N leftmost (UTF-8) characters in the given string.")
|
||||
.with_parameter({"str", "The string to return subset."})
|
||||
.with_parameter({"N", "The number of characters from the left side of the string to return."})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT leftstr('abc', 1)"})
|
||||
.with_example({"SELECT leftstr('abc', 10)"})
|
||||
},
|
||||
@ -1775,6 +1777,7 @@ int common_extension_functions(struct FuncDef **basic_funcs,
|
||||
.with_summary("Returns the N rightmost (UTF-8) characters in the given string.")
|
||||
.with_parameter({"str", "The string to return subset."})
|
||||
.with_parameter({"N", "The number of characters from the right side of the string to return."})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT rightstr('abc', 1)"})
|
||||
.with_example({"SELECT rightstr('abc', 10)"})
|
||||
},
|
||||
@ -1789,6 +1792,7 @@ int common_extension_functions(struct FuncDef **basic_funcs,
|
||||
.sql_function()
|
||||
.with_summary("Returns the reverse of the given string.")
|
||||
.with_parameter({"str", "The string to reverse."})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT reverse('abc')"})
|
||||
},
|
||||
{ "proper", 1, SQLITE_UTF8, 0, properFunc },
|
||||
|
@ -42,7 +42,7 @@ json_string extract(const char *str);
|
||||
void field_overlay_source::build_summary_lines(const listview_curses &lv)
|
||||
{
|
||||
textfile_sub_source &tss = lnav_data.ld_text_source;
|
||||
logfile_sub_source &lss = lnav_data.ld_log_source;
|
||||
logfile_sub_source &lss = this->fos_lss;
|
||||
|
||||
this->fos_summary_lines.clear();
|
||||
|
||||
@ -55,7 +55,7 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
|
||||
|
||||
lv.get_dimensions(height, width);
|
||||
free_rows = height - filled_rows - vis_line_t(this->fos_lines.size());
|
||||
if (free_rows < 2) {
|
||||
if (free_rows < 2 || lnav_data.ld_flags & LNF_HEADLESS) {
|
||||
this->fos_summary_lines.clear();
|
||||
}
|
||||
else {
|
||||
@ -82,10 +82,8 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
|
||||
time_t five_minutes_ago = local_now - (5 * 60 * 60);
|
||||
time_t ten_secs_ago = local_now - 10;
|
||||
|
||||
vis_line_t from_five_min_ago = lnav_data.ld_log_source.
|
||||
find_from_time(five_minutes_ago);
|
||||
vis_line_t from_ten_secs_ago = lnav_data.ld_log_source.
|
||||
find_from_time(ten_secs_ago);
|
||||
vis_line_t from_five_min_ago = lss.find_from_time(five_minutes_ago);
|
||||
vis_line_t from_ten_secs_ago = lss.find_from_time(ten_secs_ago);
|
||||
vis_bookmarks &bm = lnav_data.ld_views[LNV_LOG].get_bookmarks();
|
||||
bookmark_vector<vis_line_t> &error_bookmarks =
|
||||
bm[&logfile_sub_source::BM_ERRORS];
|
||||
@ -196,7 +194,7 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
|
||||
|
||||
void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
{
|
||||
logfile_sub_source &lss = lnav_data.ld_log_source;
|
||||
logfile_sub_source &lss = this->fos_lss;
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
this->fos_lines.clear();
|
||||
@ -220,6 +218,8 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
display = true;
|
||||
}
|
||||
|
||||
this->build_meta_line(lv, this->fos_lines, lv.get_top());
|
||||
|
||||
if (!display) {
|
||||
return;
|
||||
}
|
||||
@ -316,7 +316,7 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
}
|
||||
|
||||
if (this->fos_active || diff_tv.tv_sec > 0) {
|
||||
this->fos_lines.push_back(time_line);
|
||||
this->fos_lines.emplace_back(time_line);
|
||||
}
|
||||
|
||||
if (!this->fos_active) {
|
||||
@ -359,12 +359,12 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
int skip = pattern_str.length();
|
||||
pattern_str += lf->get_pattern_regex();
|
||||
readline_regex_highlighter(pattern_al, skip);
|
||||
this->fos_lines.push_back(pattern_al);
|
||||
this->fos_lines.emplace_back(pattern_al);
|
||||
}
|
||||
|
||||
|
||||
if (this->fos_log_helper.ldh_line_values.empty()) {
|
||||
this->fos_lines.push_back(" No known message fields");
|
||||
this->fos_lines.emplace_back(" No known message fields");
|
||||
}
|
||||
|
||||
const log_format *last_format = NULL;
|
||||
@ -376,7 +376,7 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
string str, value_str = lv.to_string();
|
||||
|
||||
if (lv.lv_format != last_format) {
|
||||
this->fos_lines.push_back(" Known message fields for table " +
|
||||
this->fos_lines.emplace_back(" Known message fields for table " +
|
||||
format_name +
|
||||
":");
|
||||
this->fos_lines.back().with_attr(string_attr(
|
||||
@ -396,7 +396,7 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
&view_curses::VC_STYLE,
|
||||
vc.attrs_for_ident(lv.lv_name.to_string())));
|
||||
|
||||
this->fos_lines.push_back(al);
|
||||
this->fos_lines.emplace_back(al);
|
||||
this->add_key_line_attrs(this->fos_known_key_size);
|
||||
|
||||
if (lv.lv_kind == logline_value::VALUE_STRUCT) {
|
||||
@ -414,7 +414,7 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
.append(this->fos_known_key_size - lv.lv_name.size() - 9 + 3, ' ')
|
||||
.append(" = ")
|
||||
.append((const char *) js.js_content, js.js_len);
|
||||
this->fos_lines.push_back(al);
|
||||
this->fos_lines.emplace_back(al);
|
||||
this->add_key_line_attrs(this->fos_known_key_size);
|
||||
}
|
||||
|
||||
@ -423,7 +423,7 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
std::map<const intern_string_t, json_ptr_walk::walk_list_t>::iterator json_iter;
|
||||
|
||||
if (!this->fos_log_helper.ldh_json_pairs.empty()) {
|
||||
this->fos_lines.push_back(" JSON fields:");
|
||||
this->fos_lines.emplace_back(" JSON fields:");
|
||||
}
|
||||
|
||||
for (json_iter = this->fos_log_helper.ldh_json_pairs.begin();
|
||||
@ -432,7 +432,8 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
json_ptr_walk::walk_list_t &jpairs = json_iter->second;
|
||||
|
||||
for (size_t lpc = 0; lpc < jpairs.size(); lpc++) {
|
||||
this->fos_lines.push_back(" " +
|
||||
this->fos_lines.emplace_back(
|
||||
" " +
|
||||
this->fos_log_helper.format_json_getter(json_iter->first, lpc) + " = " +
|
||||
jpairs[lpc].wt_value);
|
||||
this->add_key_line_attrs(0);
|
||||
@ -440,10 +441,10 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
}
|
||||
|
||||
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
|
||||
this->fos_lines.push_back(" No discovered message fields");
|
||||
this->fos_lines.emplace_back(" No discovered message fields");
|
||||
}
|
||||
else {
|
||||
this->fos_lines.push_back(" Discovered fields for logline table from message format: ");
|
||||
this->fos_lines.emplace_back(" Discovered fields for logline table from message format: ");
|
||||
this->fos_lines.back().with_attr(string_attr(
|
||||
line_range(23, 23 + 7),
|
||||
&view_curses::VC_STYLE,
|
||||
@ -474,8 +475,60 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
&view_curses::VC_STYLE,
|
||||
vc.attrs_for_ident(name)));
|
||||
|
||||
this->fos_lines.push_back(al);
|
||||
this->fos_lines.emplace_back(al);
|
||||
this->add_key_line_attrs(this->fos_unknown_key_size,
|
||||
lpc == (this->fos_log_helper.ldh_parser->dp_pairs.size() - 1));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void field_overlay_source::build_meta_line(const listview_curses &lv,
|
||||
std::vector<attr_line_t> &dst,
|
||||
vis_line_t row)
|
||||
{
|
||||
content_line_t cl = this->fos_lss.at(row);
|
||||
auto const &bm = this->fos_lss.get_user_bookmark_metadata();
|
||||
view_colors &vc = view_colors::singleton();
|
||||
auto iter = bm.find(cl);
|
||||
|
||||
if (iter != bm.end()) {
|
||||
const bookmark_metadata &line_meta = iter->second;
|
||||
|
||||
if (!line_meta.bm_comment.empty()) {
|
||||
attr_line_t al;
|
||||
|
||||
al.with_string(" + ")
|
||||
.with_attr(string_attr(
|
||||
line_range(1, 2),
|
||||
&view_curses::VC_GRAPHIC,
|
||||
line_meta.bm_tags.empty() ? ACS_LLCORNER : ACS_LTEE
|
||||
))
|
||||
.append(line_meta.bm_comment);
|
||||
dst.emplace_back(al);
|
||||
}
|
||||
if (!line_meta.bm_tags.empty()) {
|
||||
attr_line_t al;
|
||||
|
||||
al.with_string(" +")
|
||||
.with_attr(string_attr(
|
||||
line_range(1, 2),
|
||||
&view_curses::VC_GRAPHIC,
|
||||
ACS_LLCORNER
|
||||
));
|
||||
for (const auto &str : line_meta.bm_tags) {
|
||||
al.append(1, ' ')
|
||||
.append(str, &view_curses::VC_STYLE, vc.attrs_for_ident(str));
|
||||
}
|
||||
|
||||
const auto *tc = dynamic_cast<const textview_curses *>(&lv);
|
||||
if (tc) {
|
||||
const textview_curses::highlight_map_t &hm = tc->get_highlights();
|
||||
auto hl_iter = hm.find("$search");
|
||||
|
||||
if (hl_iter != hm.end()) {
|
||||
hl_iter->second.annotate(al, 2);
|
||||
}
|
||||
}
|
||||
dst.emplace_back(al);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,21 +39,10 @@
|
||||
class field_overlay_source : public list_overlay_source {
|
||||
public:
|
||||
field_overlay_source(logfile_sub_source &lss)
|
||||
: fos_active(false),
|
||||
fos_active_prev(false),
|
||||
fos_log_helper(lss),
|
||||
fos_known_key_size(0),
|
||||
fos_unknown_key_size(0) {
|
||||
: fos_lss(lss), fos_log_helper(lss) {
|
||||
|
||||
};
|
||||
|
||||
size_t list_overlay_count(const listview_curses &lv) {
|
||||
this->build_field_lines(lv);
|
||||
this->build_summary_lines(lv);
|
||||
|
||||
return this->fos_lines.size() + this->fos_summary_lines.size();
|
||||
};
|
||||
|
||||
void add_key_line_attrs(int key_size, bool last_line = false) {
|
||||
string_attrs_t &sa = this->fos_lines.back().get_attrs();
|
||||
struct line_range lr(1, 2);
|
||||
@ -61,28 +50,38 @@ public:
|
||||
|
||||
lr.lr_start = 3 + key_size + 3;
|
||||
lr.lr_end = -1;
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE, A_BOLD));
|
||||
sa.emplace_back(lr, &view_curses::VC_STYLE, A_BOLD);
|
||||
};
|
||||
|
||||
bool list_value_for_overlay(const listview_curses &lv,
|
||||
vis_line_t y,
|
||||
attr_line_t &value_out)
|
||||
{
|
||||
int y, int bottom,
|
||||
vis_line_t row,
|
||||
attr_line_t &value_out) override {
|
||||
if (y == 0) {
|
||||
this->build_field_lines(lv);
|
||||
this->build_summary_lines(lv);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (1 <= y && y <= (int)this->fos_lines.size()) {
|
||||
value_out = this->fos_lines[y - 1];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this->fos_summary_lines.empty()) {
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
|
||||
lv.get_dimensions(height, width);
|
||||
|
||||
if (y == height - 1) {
|
||||
if (!this->fos_summary_lines.empty() && y == (bottom - 1)) {
|
||||
value_out = this->fos_summary_lines[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this->fos_meta_lines.empty()) {
|
||||
value_out = this->fos_meta_lines.front();
|
||||
this->fos_meta_lines.erase(this->fos_meta_lines.begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (row < lv.get_inner_height()) {
|
||||
this->build_meta_line(lv, this->fos_meta_lines, row);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -90,14 +89,19 @@ public:
|
||||
|
||||
void build_field_lines(const listview_curses &lv);
|
||||
void build_summary_lines(const listview_curses &lv);
|
||||
void build_meta_line(const listview_curses &lv,
|
||||
std::vector<attr_line_t> &dst,
|
||||
vis_line_t row);
|
||||
|
||||
bool fos_active;
|
||||
bool fos_active_prev;
|
||||
bool fos_active{false};
|
||||
bool fos_active_prev{false};
|
||||
logfile_sub_source &fos_lss;
|
||||
log_data_helper fos_log_helper;
|
||||
int fos_known_key_size;
|
||||
int fos_unknown_key_size;
|
||||
int fos_known_key_size{0};
|
||||
int fos_unknown_key_size{0};
|
||||
std::vector<attr_line_t> fos_lines;
|
||||
std::vector<attr_line_t> fos_summary_lines;
|
||||
std::vector<attr_line_t> fos_meta_lines;
|
||||
};
|
||||
|
||||
#endif //LNAV_FIELD_OVERLAY_SOURCE_H
|
||||
|
@ -43,10 +43,8 @@ public:
|
||||
};
|
||||
|
||||
void logline_restart(const logfile &lf) {
|
||||
for (filter_stack::iterator iter = this->lfo_filter_stack.begin();
|
||||
iter != this->lfo_filter_stack.end();
|
||||
++iter) {
|
||||
(*iter)->revert_to_last(this->lfo_filter_state);
|
||||
for (auto &filter : this->lfo_filter_stack) {
|
||||
filter->revert_to_last(this->lfo_filter_state);
|
||||
}
|
||||
};
|
||||
|
||||
@ -57,24 +55,20 @@ public:
|
||||
|
||||
this->lfo_filter_state.resize(lf.size());
|
||||
if (!this->lfo_filter_stack.empty()) {
|
||||
if (lf.get_format() != NULL) {
|
||||
if (lf.get_format() != nullptr) {
|
||||
lf.get_format()->get_subline(*ll, sbr);
|
||||
}
|
||||
for (filter_stack::iterator iter = this->lfo_filter_stack.begin();
|
||||
iter != this->lfo_filter_stack.end();
|
||||
++iter) {
|
||||
if (offset >= this->lfo_filter_state.tfs_filter_count[(*iter)->get_index()]) {
|
||||
(*iter)->add_line(this->lfo_filter_state, ll, sbr);
|
||||
for (auto &filter : this->lfo_filter_stack) {
|
||||
if (offset >= this->lfo_filter_state.tfs_filter_count[filter->get_index()]) {
|
||||
filter->add_line(this->lfo_filter_state, ll, sbr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void logline_eof(const logfile &lf) {
|
||||
for (filter_stack::iterator iter = this->lfo_filter_stack.begin();
|
||||
iter != this->lfo_filter_stack.end();
|
||||
++iter) {
|
||||
(*iter)->end_of_message(this->lfo_filter_state);
|
||||
for (auto &iter : this->lfo_filter_stack) {
|
||||
iter->end_of_message(this->lfo_filter_state);
|
||||
}
|
||||
};
|
||||
|
||||
@ -90,10 +84,8 @@ public:
|
||||
size_t get_min_count(size_t max) const {
|
||||
size_t retval = max;
|
||||
|
||||
for (filter_stack::iterator iter = this->lfo_filter_stack.begin();
|
||||
iter != this->lfo_filter_stack.end();
|
||||
++iter) {
|
||||
retval = std::min(retval, this->lfo_filter_state.tfs_filter_count[(*iter)->get_index()]);
|
||||
for (auto &filter : this->lfo_filter_stack) {
|
||||
retval = std::min(retval, this->lfo_filter_state.tfs_filter_count[filter->get_index()]);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@ -102,10 +94,8 @@ public:
|
||||
void clear_deleted_filter_state() {
|
||||
uint32_t used_mask = 0;
|
||||
|
||||
for (filter_stack::iterator iter = this->lfo_filter_stack.begin();
|
||||
iter != this->lfo_filter_stack.end();
|
||||
++iter) {
|
||||
used_mask |= (1L << (*iter)->get_index());
|
||||
for (auto &filter : this->lfo_filter_stack) {
|
||||
used_mask |= (1UL << filter->get_index());
|
||||
}
|
||||
this->lfo_filter_state.clear_deleted_filter_state(used_mask);
|
||||
};
|
||||
|
@ -177,6 +177,7 @@ int fs_extension_functions(struct FuncDef **basic_funcs,
|
||||
"Extract the base portion of a pathname.")
|
||||
.sql_function()
|
||||
.with_parameter({"path", "The path"})
|
||||
.with_tags({"filename"})
|
||||
.with_example({"SELECT basename('foobar')"})
|
||||
.with_example({"SELECT basename('foo/bar')"})
|
||||
.with_example({"SELECT basename('foo/bar/')"})
|
||||
@ -191,6 +192,7 @@ int fs_extension_functions(struct FuncDef **basic_funcs,
|
||||
"Extract the directory portion of a pathname.")
|
||||
.sql_function()
|
||||
.with_parameter({"path", "The path"})
|
||||
.with_tags({"filename"})
|
||||
.with_example({"SELECT dirname('foo/bar')"})
|
||||
.with_example({"SELECT dirname('/foo/bar')"})
|
||||
.with_example({"SELECT dirname('/bar')"})
|
||||
@ -206,6 +208,7 @@ int fs_extension_functions(struct FuncDef **basic_funcs,
|
||||
"If an argument starts with a forward or backward slash, it will be considered "
|
||||
"an absolute path and any preceding elements will be ignored.")
|
||||
.one_or_more())
|
||||
.with_tags({"filename"})
|
||||
.with_example({"SELECT joinpath('foo', 'bar')"})
|
||||
.with_example({"SELECT joinpath('', 'foo', 'bar')"})
|
||||
.with_example({"SELECT joinpath('/', 'foo', 'bar')"})
|
||||
@ -217,6 +220,7 @@ int fs_extension_functions(struct FuncDef **basic_funcs,
|
||||
"Read the target of a symbolic link.")
|
||||
.sql_function()
|
||||
.with_parameter({"path", "The path to the symbolic link."})
|
||||
.with_tags({"filename"})
|
||||
),
|
||||
|
||||
sqlite_func_adapter<decltype(&sql_realpath), sql_realpath>::builder(
|
||||
@ -225,6 +229,7 @@ int fs_extension_functions(struct FuncDef **basic_funcs,
|
||||
"resolving '.' and '..' references.")
|
||||
.sql_function()
|
||||
.with_parameter({"path", "The path to resolve."})
|
||||
.with_tags({"filename"})
|
||||
),
|
||||
|
||||
/*
|
||||
|
@ -31,17 +31,17 @@
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <utility>
|
||||
#include "grep_proc.hh"
|
||||
#include "textview_curses.hh"
|
||||
|
||||
class grep_highlighter {
|
||||
public:
|
||||
grep_highlighter(std::unique_ptr<grep_proc> &gp,
|
||||
grep_highlighter(std::unique_ptr<grep_proc<vis_line_t>> &gp,
|
||||
std::string hl_name,
|
||||
textview_curses::highlight_map_t &hl_map)
|
||||
: gh_grep_proc(std::move(gp)),
|
||||
gh_hl_name(hl_name),
|
||||
gh_hl_name(std::move(hl_name)),
|
||||
gh_hl_map(hl_map) { };
|
||||
|
||||
~grep_highlighter()
|
||||
@ -49,10 +49,10 @@ public:
|
||||
this->gh_hl_map.erase(this->gh_hl_map.find(this->gh_hl_name));
|
||||
};
|
||||
|
||||
grep_proc *get_grep_proc() { return this->gh_grep_proc.get(); };
|
||||
grep_proc<vis_line_t> *get_grep_proc() { return this->gh_grep_proc.get(); };
|
||||
|
||||
private:
|
||||
std::unique_ptr<grep_proc> gh_grep_proc;
|
||||
std::unique_ptr<grep_proc<vis_line_t>> gh_grep_proc;
|
||||
std::string gh_hl_name;
|
||||
textview_curses::highlight_map_t &gh_hl_map;
|
||||
};
|
||||
|
@ -43,32 +43,32 @@
|
||||
#include "lnav_log.hh"
|
||||
#include "lnav_util.hh"
|
||||
#include "grep_proc.hh"
|
||||
#include "listview_curses.hh"
|
||||
|
||||
#include "time_T.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
grep_proc::grep_proc(pcre *code, grep_proc_source &gps)
|
||||
template<typename LineType>
|
||||
grep_proc<LineType>::grep_proc(pcre *code, grep_proc_source<LineType> &gps)
|
||||
: gp_pcre(code),
|
||||
gp_code(code),
|
||||
gp_source(gps),
|
||||
gp_pipe_offset(0),
|
||||
gp_child(-1),
|
||||
gp_child_started(false),
|
||||
gp_last_line(0),
|
||||
gp_sink(NULL),
|
||||
gp_control(NULL)
|
||||
gp_source(gps)
|
||||
{
|
||||
require(this->invariant());
|
||||
|
||||
gps.register_proc(this);
|
||||
}
|
||||
|
||||
grep_proc::~grep_proc()
|
||||
template<typename LineType>
|
||||
grep_proc<LineType>::~grep_proc()
|
||||
{
|
||||
this->gp_queue.clear();
|
||||
this->cleanup();
|
||||
}
|
||||
|
||||
void grep_proc::handle_match(int line,
|
||||
template<typename LineType>
|
||||
void grep_proc<LineType>::handle_match(int line,
|
||||
string &line_value,
|
||||
int off,
|
||||
int *matches,
|
||||
@ -94,7 +94,8 @@ void grep_proc::handle_match(int line,
|
||||
}
|
||||
}
|
||||
|
||||
void grep_proc::start(void)
|
||||
template<typename LineType>
|
||||
void grep_proc<LineType>::start()
|
||||
{
|
||||
require(this->invariant());
|
||||
|
||||
@ -133,6 +134,7 @@ void grep_proc::start(void)
|
||||
require(this->gp_err_pipe.get() == -1);
|
||||
this->gp_err_pipe = err_pipe.read_end();
|
||||
this->gp_child_started = true;
|
||||
this->gp_child_queue_size = this->gp_queue.size();
|
||||
|
||||
this->gp_queue.clear();
|
||||
return;
|
||||
@ -154,7 +156,8 @@ void grep_proc::start(void)
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
void grep_proc::child_loop(void)
|
||||
template<typename LineType>
|
||||
void grep_proc<LineType>::child_loop()
|
||||
{
|
||||
char outbuf[BUFSIZ * 2];
|
||||
string line_value;
|
||||
@ -163,21 +166,18 @@ void grep_proc::child_loop(void)
|
||||
if (setvbuf(stdout, outbuf, _IOFBF, BUFSIZ * 2) < 0) {
|
||||
perror("setvbuf");
|
||||
}
|
||||
lnav_log_file = fopen("/tmp/lnav.grep.err", "a");
|
||||
line_value.reserve(BUFSIZ * 2);
|
||||
while (!this->gp_queue.empty()) {
|
||||
grep_line_t start_line = this->gp_queue.front().first;
|
||||
grep_line_t stop_line = this->gp_queue.front().second;
|
||||
LineType start_line = this->gp_queue.front().first;
|
||||
LineType stop_line = this->gp_queue.front().second;
|
||||
bool done = false;
|
||||
int line;
|
||||
LineType line;
|
||||
|
||||
this->gp_queue.pop_front();
|
||||
if (start_line == -1) {
|
||||
start_line = this->gp_highest_line;
|
||||
log_debug("highest %d", start_line);
|
||||
}
|
||||
for (line = start_line;
|
||||
(stop_line == -1 || line < stop_line) && !done;
|
||||
line++) {
|
||||
for (line = this->gp_source.grep_initial_line(start_line, this->gp_highest_line);
|
||||
line != -1 && (stop_line == -1 || line < stop_line) && !done;
|
||||
this->gp_source.grep_next_line(line)) {
|
||||
line_value.clear();
|
||||
done = !this->gp_source.grep_value_for_line(line, line_value);
|
||||
if (!done) {
|
||||
@ -189,7 +189,7 @@ void grep_proc::child_loop(void)
|
||||
pcre_context::capture_t *m;
|
||||
|
||||
if (pi.pi_offset == 0) {
|
||||
fprintf(stdout, "%d\n", line);
|
||||
fprintf(stdout, "%d\n", (int) line);
|
||||
}
|
||||
m = pc.all();
|
||||
fprintf(stdout, "[%d:%d]\n", m->c_begin, m->c_end);
|
||||
@ -234,7 +234,8 @@ void grep_proc::child_loop(void)
|
||||
}
|
||||
}
|
||||
|
||||
void grep_proc::cleanup(void)
|
||||
template<typename LineType>
|
||||
void grep_proc<LineType>::cleanup()
|
||||
{
|
||||
if (this->gp_child != -1 && this->gp_child != 0) {
|
||||
int status = 0;
|
||||
@ -248,9 +249,11 @@ void grep_proc::cleanup(void)
|
||||
this->gp_child_started = false;
|
||||
|
||||
if (this->gp_sink) {
|
||||
for (int lpc = 0; lpc < this->gp_child_queue_size; lpc++) {
|
||||
this->gp_sink->grep_end(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->gp_err_pipe != -1) {
|
||||
this->gp_err_pipe.reset();
|
||||
@ -266,14 +269,18 @@ void grep_proc::cleanup(void)
|
||||
}
|
||||
}
|
||||
|
||||
void grep_proc::dispatch_line(char *line)
|
||||
template<typename LineType>
|
||||
void grep_proc<LineType>::dispatch_line(char *line)
|
||||
{
|
||||
int start, end, capture_start;
|
||||
|
||||
require(line != NULL);
|
||||
|
||||
if (sscanf(line, "h%d", this->gp_highest_line.out()) == 1) {
|
||||
|
||||
if (this->gp_sink) {
|
||||
this->gp_sink->grep_end(*this);
|
||||
}
|
||||
this->gp_child_queue_size -= 1;
|
||||
} else if (sscanf(line, "%d", this->gp_last_line.out()) == 1) {
|
||||
/* Starting a new line with matches. */
|
||||
ensure(this->gp_last_line >= 0);
|
||||
@ -311,7 +318,8 @@ void grep_proc::dispatch_line(char *line)
|
||||
}
|
||||
}
|
||||
|
||||
void grep_proc::check_poll_set(const std::vector<struct pollfd> &pollfds)
|
||||
template<typename LineType>
|
||||
void grep_proc<LineType>::check_poll_set(const std::vector<struct pollfd> &pollfds)
|
||||
{
|
||||
require(this->invariant());
|
||||
|
||||
@ -327,10 +335,10 @@ void grep_proc::check_poll_set(const std::vector<struct pollfd> &pollfds)
|
||||
if (strncmp(buffer, PREFIX, strlen(PREFIX)) == 0) {
|
||||
char *lf;
|
||||
|
||||
if ((lf = strchr(buffer, '\n')) != NULL) {
|
||||
if ((lf = strchr(buffer, '\n')) != nullptr) {
|
||||
*lf = '\0';
|
||||
}
|
||||
if (this->gp_control != NULL) {
|
||||
if (this->gp_control != nullptr) {
|
||||
this->gp_control->grep_error(&buffer[strlen(PREFIX)]);
|
||||
}
|
||||
}
|
||||
@ -355,7 +363,7 @@ void grep_proc::check_poll_set(const std::vector<struct pollfd> &pollfds)
|
||||
loop_count += 1;
|
||||
}
|
||||
|
||||
if (this->gp_sink != NULL) {
|
||||
if (this->gp_sink != nullptr) {
|
||||
this->gp_sink->grep_end_batch(*this);
|
||||
}
|
||||
|
||||
@ -371,3 +379,5 @@ void grep_proc::check_poll_set(const std::vector<struct pollfd> &pollfds)
|
||||
|
||||
ensure(this->invariant());
|
||||
}
|
||||
|
||||
template class grep_proc<vis_line_t>;
|
||||
|
103
src/grep_proc.hh
103
src/grep_proc.hh
@ -57,25 +57,41 @@
|
||||
#include "strong_int.hh"
|
||||
#include "line_buffer.hh"
|
||||
|
||||
/** Strongly-typed integer for matched line numbers. */
|
||||
STRONG_INT_TYPE(int, grep_line);
|
||||
|
||||
template<typename LineType>
|
||||
class grep_proc;
|
||||
|
||||
/**
|
||||
* Data source for lines to be searched using a grep_proc.
|
||||
*/
|
||||
template<typename LineType>
|
||||
class grep_proc_source {
|
||||
public:
|
||||
virtual ~grep_proc_source() { };
|
||||
|
||||
virtual void register_proc(grep_proc<LineType> *proc) {
|
||||
this->gps_proc = proc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for a particular line in the source.
|
||||
*
|
||||
* @param line The line to retrieve.
|
||||
* @param value_out The destination for the line value.
|
||||
*/
|
||||
virtual bool grep_value_for_line(int line, std::string &value_out) = 0;
|
||||
virtual bool grep_value_for_line(LineType line, std::string &value_out) = 0;
|
||||
|
||||
virtual LineType grep_initial_line(LineType start, LineType highest) {
|
||||
if (start == -1) {
|
||||
return highest;
|
||||
}
|
||||
return start;
|
||||
};
|
||||
|
||||
virtual void grep_next_line(LineType &line) {
|
||||
line = line + LineType(1);
|
||||
};
|
||||
|
||||
grep_proc<LineType> *gps_proc;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -93,18 +109,19 @@ public:
|
||||
/**
|
||||
* Sink for matches produced by a grep_proc instance.
|
||||
*/
|
||||
template<typename LineType>
|
||||
class grep_proc_sink {
|
||||
public:
|
||||
virtual ~grep_proc_sink() { };
|
||||
virtual ~grep_proc_sink() = default;
|
||||
|
||||
/** Called at the start of a new grep run. */
|
||||
virtual void grep_begin(grep_proc &gp) { };
|
||||
virtual void grep_begin(grep_proc<LineType> &gp, LineType start, LineType stop) { };
|
||||
|
||||
/** Called periodically between grep_begin and grep_end. */
|
||||
virtual void grep_end_batch(grep_proc &gp) { };
|
||||
virtual void grep_end_batch(grep_proc<LineType> &gp) { };
|
||||
|
||||
/** Called at the end of a grep run. */
|
||||
virtual void grep_end(grep_proc &gp) { };
|
||||
virtual void grep_end(grep_proc<LineType> &gp) { };
|
||||
|
||||
/**
|
||||
* Called when a match is found on 'line' and between [start, end).
|
||||
@ -114,8 +131,8 @@ public:
|
||||
* @param end The offset of the character after the last character in the
|
||||
* match.
|
||||
*/
|
||||
virtual void grep_match(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
virtual void grep_match(grep_proc<LineType> &gp,
|
||||
LineType line,
|
||||
int start,
|
||||
int end) = 0;
|
||||
|
||||
@ -128,13 +145,13 @@ public:
|
||||
* capture.
|
||||
* @param capture The captured substring itself.
|
||||
*/
|
||||
virtual void grep_capture(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
virtual void grep_capture(grep_proc<LineType> &gp,
|
||||
LineType line,
|
||||
int start,
|
||||
int end,
|
||||
char *capture) { };
|
||||
|
||||
virtual void grep_match_end(grep_proc &gp, grep_line_t line) { };
|
||||
virtual void grep_match_end(grep_proc<LineType> &gp, LineType line) { };
|
||||
};
|
||||
|
||||
/**
|
||||
@ -147,6 +164,7 @@ public:
|
||||
* Note: The "grep" executable is not actually used, instead we use the pcre(3)
|
||||
* library directly.
|
||||
*/
|
||||
template<typename LineType>
|
||||
class grep_proc {
|
||||
public:
|
||||
class error
|
||||
@ -165,7 +183,7 @@ public:
|
||||
* @param code The pcre code to run over the lines of input.
|
||||
* @param gps The source of the data to match.
|
||||
*/
|
||||
grep_proc(pcre *code, grep_proc_source &gps);
|
||||
grep_proc(pcre *code, grep_proc_source<LineType> &gps);
|
||||
|
||||
virtual ~grep_proc();
|
||||
|
||||
@ -173,21 +191,14 @@ public:
|
||||
pcre *get_code() { return this->gp_code; };
|
||||
|
||||
/** @param gpd The sink to send resuls to. */
|
||||
void set_sink(grep_proc_sink *gpd)
|
||||
void set_sink(grep_proc_sink<LineType> *gpd)
|
||||
{
|
||||
this->gp_sink = gpd;
|
||||
this->reset();
|
||||
};
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (this->gp_sink != NULL) {
|
||||
this->gp_sink->grep_begin(*this);
|
||||
}
|
||||
};
|
||||
|
||||
void invalidate() {
|
||||
grep_proc &invalidate() {
|
||||
this->cleanup();
|
||||
return *this;
|
||||
};
|
||||
|
||||
/** @param gpd The sink to send results to. */
|
||||
@ -197,7 +208,7 @@ public:
|
||||
};
|
||||
|
||||
/** @return The sink to send resuls to. */
|
||||
grep_proc_sink *get_sink() { return this->gp_sink; };
|
||||
grep_proc_sink<LineType> *get_sink() { return this->gp_sink; };
|
||||
|
||||
/**
|
||||
* Queue a request to search the input between the given line numbers.
|
||||
@ -206,19 +217,24 @@ public:
|
||||
* @param stop The line number to stop the search at or -1 to read until
|
||||
* the end-of-file.
|
||||
*/
|
||||
void queue_request(grep_line_t start = grep_line_t(0),
|
||||
grep_line_t stop = grep_line_t(-1))
|
||||
grep_proc &queue_request(LineType start = LineType(0),
|
||||
LineType stop = LineType(-1))
|
||||
{
|
||||
require(start != -1 || stop == -1);
|
||||
require(stop == -1 || start < stop);
|
||||
|
||||
this->gp_queue.push_back(std::make_pair(start, stop));
|
||||
this->gp_queue.emplace_back(start, stop);
|
||||
if (this->gp_sink) {
|
||||
this->gp_sink->grep_begin(*this, start, stop);
|
||||
}
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start the search requests that have been queued up with queue_request.
|
||||
*/
|
||||
void start(void);
|
||||
void start();
|
||||
|
||||
void update_poll_set(std::vector<struct pollfd> &pollfds)
|
||||
{
|
||||
@ -273,15 +289,15 @@ protected:
|
||||
* Free any resources used by the object and make sure the child has been
|
||||
* terminated.
|
||||
*/
|
||||
void cleanup(void);
|
||||
void cleanup();
|
||||
|
||||
void child_loop(void);
|
||||
void child_loop();
|
||||
|
||||
virtual void child_init(void) { };
|
||||
virtual void child_init() { };
|
||||
|
||||
virtual void child_batch(void) { fflush(stdout); };
|
||||
virtual void child_batch() { fflush(stdout); };
|
||||
|
||||
virtual void child_term(void) { fflush(stdout); };
|
||||
virtual void child_term() { fflush(stdout); };
|
||||
|
||||
virtual void handle_match(int line,
|
||||
std::string &line_value,
|
||||
@ -291,31 +307,32 @@ protected:
|
||||
|
||||
pcrepp gp_pcre;
|
||||
pcre * gp_code; /*< The compiled pattern. */
|
||||
grep_proc_source & gp_source; /*< The data source delegate. */
|
||||
grep_proc_source<LineType> &gp_source; /*< The data source delegate. */
|
||||
|
||||
auto_fd gp_err_pipe; /*< Standard error from the child. */
|
||||
line_buffer gp_line_buffer; /*< Standard out from the child. */
|
||||
off_t gp_pipe_offset;
|
||||
off_t gp_pipe_offset{0};
|
||||
|
||||
pid_t gp_child; /*<
|
||||
pid_t gp_child{-1}; /*<
|
||||
* The child's pid or zero in the
|
||||
* child.
|
||||
*/
|
||||
bool gp_child_started; /*< True if the child was start()'d. */
|
||||
bool gp_child_started{false}; /*< True if the child was start()'d. */
|
||||
size_t gp_child_queue_size{0};
|
||||
|
||||
/** The queue of search requests. */
|
||||
std::deque<std::pair<grep_line_t, grep_line_t> > gp_queue;
|
||||
grep_line_t gp_last_line; /*<
|
||||
std::deque<std::pair<LineType, LineType> > gp_queue;
|
||||
LineType gp_last_line{0}; /*<
|
||||
* The last line number received from
|
||||
* the child. For multiple matches,
|
||||
* the line number is only sent once.
|
||||
*/
|
||||
grep_line_t gp_highest_line; /*< The highest numbered line processed
|
||||
LineType gp_highest_line; /*< The highest numbered line processed
|
||||
* by the grep child process. This
|
||||
* value is used when the start line
|
||||
* for a queued request is -1.
|
||||
*/
|
||||
grep_proc_sink * gp_sink; /*< The sink delegate. */
|
||||
grep_proc_control *gp_control; /*< The control delegate. */
|
||||
grep_proc_sink<LineType> *gp_sink{nullptr}; /*< The sink delegate. */
|
||||
grep_proc_control *gp_control{nullptr}; /*< The control delegate. */
|
||||
};
|
||||
#endif
|
||||
|
25
src/help.txt
25
src/help.txt
@ -472,11 +472,32 @@ COMMANDS
|
||||
relative-goto <line#|N%>
|
||||
Move the current view up or down by the given amount.
|
||||
|
||||
next-mark error|warning|search|user|file|partition
|
||||
comment <message>
|
||||
Add a comment to the top line in the log view. The
|
||||
comment will be saved in the session and will be available
|
||||
the next time the file is loaded. Searches will also scan
|
||||
the comment for any matches.
|
||||
|
||||
clear-comment Clear the comment that is attached to the top line in the
|
||||
log view.
|
||||
|
||||
tag <tag1> [<tag2> [... <tagN>]]
|
||||
Attach a tag to the top line in the log view. The tags are
|
||||
prefixed with a '#', if they don't have one already. And,
|
||||
like comments, they are saved in the session and
|
||||
searchable.
|
||||
|
||||
untag <tag1> [<tag2> [... <tagN>]]
|
||||
Detach a tag from the top line in the log view.
|
||||
|
||||
delete-tags <tag1> [<tag2> [... <tagN>]]
|
||||
Detach the tags from all log lines.
|
||||
|
||||
next-mark error|warning|search|user|file|meta
|
||||
Move to the next bookmark of the given type in the
|
||||
current view.
|
||||
|
||||
prev-mark error|warning|search|user|file|partition
|
||||
prev-mark error|warning|search|user|file|meta
|
||||
Move to the previous bookmark of the given type in the
|
||||
current view.
|
||||
|
||||
|
@ -39,7 +39,10 @@
|
||||
using namespace std;
|
||||
|
||||
|
||||
void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out) {
|
||||
std::multimap<std::string, help_text *> help_text::TAGGED;
|
||||
|
||||
void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out, bool synopsis_only)
|
||||
{
|
||||
static size_t body_indent = 2;
|
||||
|
||||
view_colors &vc = view_colors::singleton();
|
||||
@ -114,9 +117,11 @@ void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out)
|
||||
size_t line_start = body_indent;
|
||||
bool break_all = false;
|
||||
|
||||
if (!synopsis_only) {
|
||||
out.append("Synopsis", &view_curses::VC_STYLE, A_UNDERLINE)
|
||||
.append("\n")
|
||||
.append(body_indent, ' ')
|
||||
.append("\n");
|
||||
}
|
||||
out.append(body_indent, ' ')
|
||||
.append(ht.ht_name, &view_curses::VC_STYLE, A_BOLD);
|
||||
for (auto ¶m : ht.ht_parameters) {
|
||||
if (break_all ||
|
||||
@ -198,17 +203,21 @@ void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out)
|
||||
out.append("]");
|
||||
}
|
||||
}
|
||||
if (!synopsis_only) {
|
||||
out.append("\n\n")
|
||||
.append(body_indent, ' ')
|
||||
.append(ht.ht_summary, &tws)
|
||||
.append("\n");
|
||||
} else {
|
||||
out.append("\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ht.ht_parameters.empty()) {
|
||||
if (!synopsis_only && !ht.ht_parameters.empty()) {
|
||||
size_t max_param_name_width = 0;
|
||||
|
||||
for (auto ¶m : ht.ht_parameters) {
|
||||
@ -237,6 +246,66 @@ void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out)
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
if (!synopsis_only && !ht.ht_tags.empty()) {
|
||||
vector<string> tags;
|
||||
|
||||
for (const auto &tag : ht.ht_tags) {
|
||||
auto tagged = help_text::TAGGED.equal_range(tag);
|
||||
|
||||
for (auto tag_iter = tagged.first;
|
||||
tag_iter != tagged.second;
|
||||
++tag_iter) {
|
||||
if (tag_iter->second == &ht) {
|
||||
continue;
|
||||
}
|
||||
|
||||
help_text &related = *tag_iter->second;
|
||||
|
||||
if (!related.ht_opposites.empty() &&
|
||||
find_if(related.ht_opposites.begin(),
|
||||
related.ht_opposites.end(),
|
||||
[&ht](const char *x) {
|
||||
return strcmp(x, ht.ht_name) == 0;
|
||||
}) == related.ht_opposites.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string name = related.ht_name;
|
||||
switch (related.ht_context) {
|
||||
case HC_COMMAND:
|
||||
name = ":" + name;
|
||||
break;
|
||||
case HC_SQL_FUNCTION:
|
||||
name = name + "()";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tags.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
stable_sort(tags.begin(), tags.end());
|
||||
|
||||
out.append("See Also", &view_curses::VC_STYLE, A_UNDERLINE)
|
||||
.append("\n")
|
||||
.append(body_indent, ' ');
|
||||
|
||||
bool first = true;
|
||||
size_t line_start = out.length();
|
||||
for (const auto &tag : tags) {
|
||||
if (!first) {
|
||||
out.append(", ");
|
||||
}
|
||||
if ((out.length() - line_start + tag.length()) > width) {
|
||||
out.append("\n")
|
||||
.append(body_indent, ' ');
|
||||
line_start = out.length();
|
||||
}
|
||||
out.append(tag, &view_curses::VC_STYLE, A_BOLD);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void format_example_text_for_term(const help_text &ht, int width, attr_line_t &out)
|
||||
|
@ -30,6 +30,7 @@
|
||||
#ifndef LNAV_HELP_TEXT_FORMATTER_HH
|
||||
#define LNAV_HELP_TEXT_FORMATTER_HH
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -65,34 +66,31 @@ struct help_example {
|
||||
};
|
||||
|
||||
struct help_text {
|
||||
help_context_t ht_context;
|
||||
help_context_t ht_context{HC_NONE};
|
||||
const char *ht_name;
|
||||
const char *ht_summary;
|
||||
const char *ht_flag_name;
|
||||
const char *ht_description;
|
||||
const char *ht_flag_name{nullptr};
|
||||
const char *ht_description{nullptr};
|
||||
std::vector<struct help_text> ht_parameters;
|
||||
std::vector<struct help_example> ht_example;
|
||||
help_nargs_t ht_nargs;
|
||||
help_parameter_format_t ht_format;
|
||||
help_nargs_t ht_nargs{HN_REQUIRED};
|
||||
help_parameter_format_t ht_format{HPF_STRING};
|
||||
std::vector<const char *> ht_enum_values;
|
||||
std::vector<const char *> ht_tags;
|
||||
std::vector<const char *> ht_opposites;
|
||||
|
||||
help_text() : ht_context(HC_NONE) {
|
||||
help_text() {
|
||||
|
||||
};
|
||||
|
||||
help_text(const char *name, const char *summary = nullptr)
|
||||
: ht_context(HC_NONE),
|
||||
ht_name(name),
|
||||
ht_summary(summary),
|
||||
ht_flag_name(nullptr),
|
||||
ht_description(nullptr),
|
||||
ht_nargs(HN_REQUIRED),
|
||||
ht_format(HPF_STRING) {
|
||||
: ht_name(name),
|
||||
ht_summary(summary) {
|
||||
if (name[0] == ':') {
|
||||
this->ht_context = HC_COMMAND;
|
||||
this->ht_name = &name[1];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
help_text &command() {
|
||||
this->ht_context = HC_COMMAND;
|
||||
@ -167,9 +165,27 @@ struct help_text {
|
||||
this->ht_enum_values = enum_values;
|
||||
return *this;
|
||||
};
|
||||
|
||||
help_text &with_tags(const std::initializer_list<const char*> &tags) {
|
||||
this->ht_tags = tags;
|
||||
return *this;
|
||||
};
|
||||
|
||||
void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out);
|
||||
help_text &with_opposites(const std::initializer_list<const char*> &opps) {
|
||||
this->ht_opposites = opps;
|
||||
return *this;
|
||||
};
|
||||
|
||||
void index_tags() {
|
||||
for (const auto &tag: this->ht_tags) {
|
||||
TAGGED.insert(std::make_pair(tag, this));
|
||||
}
|
||||
};
|
||||
|
||||
static std::multimap<std::string, help_text *> TAGGED;
|
||||
};
|
||||
|
||||
void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out, bool synopsis_only = false);
|
||||
void format_example_text_for_term(const help_text &ht, int width, attr_line_t &out);
|
||||
|
||||
#endif //LNAV_HELP_TEXT_FORMATTER_HH
|
||||
|
@ -148,6 +148,52 @@ struct highlighter {
|
||||
return this->h_attrs;
|
||||
};
|
||||
|
||||
void annotate(attr_line_t &al, int start) const {
|
||||
const std::string &str = al.get_string();
|
||||
string_attrs_t &sa = al.get_attrs();
|
||||
size_t re_end;
|
||||
|
||||
if (str.length() > 8192)
|
||||
re_end = 8192;
|
||||
else
|
||||
re_end = str.length();
|
||||
for (int off = start; off < (int)str.size(); ) {
|
||||
int rc, matches[60];
|
||||
rc = pcre_exec(this->h_code,
|
||||
this->h_code_extra,
|
||||
str.c_str(),
|
||||
re_end,
|
||||
off,
|
||||
0,
|
||||
matches,
|
||||
60);
|
||||
if (rc > 0) {
|
||||
struct line_range lr;
|
||||
|
||||
if (rc == 2) {
|
||||
lr.lr_start = matches[2];
|
||||
lr.lr_end = matches[3];
|
||||
}
|
||||
else {
|
||||
lr.lr_start = matches[0];
|
||||
lr.lr_end = matches[1];
|
||||
}
|
||||
|
||||
if (lr.lr_end > lr.lr_start) {
|
||||
sa.emplace_back(lr, &view_curses::VC_STYLE, this->h_attrs);
|
||||
|
||||
off = matches[1];
|
||||
}
|
||||
else {
|
||||
off += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
off = str.size();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::string h_pattern;
|
||||
rgb_color h_fg;
|
||||
rgb_color h_bg;
|
||||
|
@ -364,7 +364,7 @@ void handle_paging_key(int ch)
|
||||
break;
|
||||
|
||||
case 'u': {
|
||||
vis_line_t user_top, part_top;
|
||||
vis_line_t user_top, meta_top;
|
||||
|
||||
lnav_data.ld_rl_view->set_alt_value(
|
||||
HELP_MSG_1(c, "to copy marked lines to the clipboard; ")
|
||||
@ -373,44 +373,39 @@ void handle_paging_key(int ch)
|
||||
user_top = next_cluster(&bookmark_vector<vis_line_t>::next,
|
||||
&textview_curses::BM_USER,
|
||||
tc->get_top());
|
||||
part_top = next_cluster(&bookmark_vector<vis_line_t>::next,
|
||||
&textview_curses::BM_PARTITION,
|
||||
meta_top = next_cluster(&bookmark_vector<vis_line_t>::next,
|
||||
&textview_curses::BM_META,
|
||||
tc->get_top());
|
||||
if (part_top == -1 && user_top == -1) {
|
||||
if (user_top == -1 && meta_top == -1) {
|
||||
alerter::singleton().chime();
|
||||
}
|
||||
else if (part_top == -1) {
|
||||
tc->set_top(user_top);
|
||||
}
|
||||
else if (user_top == -1) {
|
||||
tc->set_top(part_top);
|
||||
}
|
||||
else {
|
||||
tc->set_top(min(user_top, part_top));
|
||||
if (user_top == -1) {
|
||||
user_top = vis_line_t(INT_MAX);
|
||||
}
|
||||
if (meta_top == -1) {
|
||||
meta_top = vis_line_t(INT_MAX);
|
||||
}
|
||||
|
||||
tc->set_top(min(user_top, meta_top));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'U': {
|
||||
vis_line_t user_top, part_top;
|
||||
vis_line_t user_top, meta_top;
|
||||
|
||||
user_top = next_cluster(&bookmark_vector<vis_line_t>::prev,
|
||||
&textview_curses::BM_USER,
|
||||
tc->get_top());
|
||||
part_top = next_cluster(&bookmark_vector<vis_line_t>::prev,
|
||||
&textview_curses::BM_PARTITION,
|
||||
meta_top = next_cluster(&bookmark_vector<vis_line_t>::prev,
|
||||
&textview_curses::BM_META,
|
||||
tc->get_top());
|
||||
if (part_top == -1 && user_top == -1) {
|
||||
if (user_top == -1 && meta_top == -1) {
|
||||
alerter::singleton().chime();
|
||||
}
|
||||
else if (part_top == -1) {
|
||||
tc->set_top(user_top);
|
||||
}
|
||||
else if (user_top == -1) {
|
||||
tc->set_top(part_top);
|
||||
}
|
||||
else {
|
||||
tc->set_top(max(user_top, part_top));
|
||||
tc->set_top(max(user_top, meta_top));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -882,6 +877,7 @@ void handle_paging_key(int ch)
|
||||
add_mark_possibilities();
|
||||
add_config_possibilities();
|
||||
add_env_possibilities(LNM_COMMAND);
|
||||
add_tag_possibilities();
|
||||
lnav_data.ld_mode = LNM_COMMAND;
|
||||
lnav_data.ld_rl_view->focus(LNM_COMMAND, ":");
|
||||
break;
|
||||
|
@ -100,6 +100,10 @@ struct string_fragment {
|
||||
return std::string(this->data(), this->length());
|
||||
}
|
||||
|
||||
std::string to_string() {
|
||||
return std::string(&this->sf_string[this->sf_begin], this->length());
|
||||
};
|
||||
|
||||
void clear() {
|
||||
this->sf_begin = 0;
|
||||
this->sf_end = 0;
|
||||
|
@ -40,12 +40,16 @@
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#include "yajlpp.hh"
|
||||
#include "json_op.hh"
|
||||
#include "mapbox/variant.hpp"
|
||||
#include "vtab_module.hh"
|
||||
|
||||
#include "yajl/api/yajl_gen.h"
|
||||
#include "sqlite-extension-func.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace mapbox;
|
||||
|
||||
#define JSON_SUBTYPE 74 /* Ascii for "J" */
|
||||
|
||||
@ -68,6 +72,61 @@ static void null_or_default(sqlite3_context *context, int argc, sqlite3_value **
|
||||
}
|
||||
}
|
||||
|
||||
struct contains_userdata {
|
||||
util::variant<const char *, int64_t, bool> cu_match_value{false};
|
||||
bool cu_result{false};
|
||||
};
|
||||
|
||||
static int contains_string(void *ctx, const unsigned char *str, size_t len)
|
||||
{
|
||||
auto &cu = *((contains_userdata *) ctx);
|
||||
|
||||
if (strncmp((const char *) str, cu.cu_match_value.get<const char *>(), len) == 0) {
|
||||
cu.cu_result = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int contains_integer(void *ctx, int64_t value)
|
||||
{
|
||||
auto &cu = *((contains_userdata *) ctx);
|
||||
|
||||
if (cu.cu_match_value.get<int64_t>() == value) {
|
||||
cu.cu_result = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool json_contains(const char *json_in, sqlite3_value *value)
|
||||
{
|
||||
auto_mem<yajl_handle_t> handle(yajl_free);
|
||||
yajl_callbacks cb;
|
||||
contains_userdata cu;
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
handle = yajl_alloc(&cb, nullptr, &cu);
|
||||
|
||||
switch (sqlite3_value_type(value)) {
|
||||
case SQLITE3_TEXT:
|
||||
cb.yajl_string = contains_string;
|
||||
cu.cu_match_value = (const char *) sqlite3_value_text(value);
|
||||
break;
|
||||
case SQLITE_INTEGER:
|
||||
cb.yajl_integer = contains_integer;
|
||||
cu.cu_match_value = sqlite3_value_int64(value);
|
||||
break;
|
||||
}
|
||||
|
||||
if (yajl_parse(handle.in(), (const unsigned char *) json_in, strlen(json_in)) != yajl_status_ok ||
|
||||
yajl_complete_parse(handle.in()) != yajl_status_ok) {
|
||||
throw yajlpp_error(handle.in(), json_in, strlen(json_in));
|
||||
}
|
||||
|
||||
return cu.cu_result;
|
||||
}
|
||||
|
||||
static int gen_handle_null(void *ctx)
|
||||
{
|
||||
sql_json_op *sjo = (sql_json_op *)ctx;
|
||||
@ -142,7 +201,7 @@ static void sql_jget(sqlite3_context *context,
|
||||
auto_mem<yajl_handle_t> handle(yajl_free);
|
||||
const unsigned char *err;
|
||||
|
||||
gen = yajl_gen_alloc(NULL);
|
||||
gen = yajl_gen_alloc(nullptr);
|
||||
yajl_gen_config(gen.in(), yajl_gen_beautify, false);
|
||||
|
||||
jo.jo_ptr_callbacks = json_op::gen_callbacks;
|
||||
@ -151,7 +210,7 @@ static void sql_jget(sqlite3_context *context,
|
||||
jo.jo_ptr_callbacks.yajl_string = gen_handle_string;
|
||||
jo.jo_ptr_data = gen.in();
|
||||
|
||||
handle.reset(yajl_alloc(&json_op::ptr_callbacks, NULL, &jo));
|
||||
handle.reset(yajl_alloc(&json_op::ptr_callbacks, nullptr, &jo));
|
||||
switch (yajl_parse(handle.in(), (const unsigned char *)json_in, strlen(json_in))) {
|
||||
case yajl_status_error:
|
||||
err = yajl_get_error(handle.in(), 0, (const unsigned char *)json_in, strlen(json_in));
|
||||
@ -397,6 +456,16 @@ int json_extension_functions(struct FuncDef **basic_funcs,
|
||||
struct FuncDefAgg **agg_funcs)
|
||||
{
|
||||
static struct FuncDef json_funcs[] = {
|
||||
sqlite_func_adapter<decltype(&json_contains), json_contains>::builder(
|
||||
help_text("json_contains", "")
|
||||
.sql_function()
|
||||
.with_parameter({"json", "The JSON value to query."})
|
||||
.with_parameter({"value", "The value to look for in the first argument"})
|
||||
.with_tags({"json"})
|
||||
.with_example({"SELECT json_contains('[1, 2, 3]', 4)"})
|
||||
.with_example({"SELECT json_contains('[\"abc\", \"def\"]', 'def')"})
|
||||
),
|
||||
|
||||
{
|
||||
"jget", -1, SQLITE_UTF8, 0, sql_jget,
|
||||
help_text("jget",
|
||||
@ -404,6 +473,7 @@ int json_extension_functions(struct FuncDef **basic_funcs,
|
||||
.sql_function()
|
||||
.with_parameter({"json", "The JSON object to query."})
|
||||
.with_parameter({"ptr", "The JSON-Pointer to lookup in the object."})
|
||||
.with_tags({"json"})
|
||||
.with_example({"SELECT jget('1', '')"})
|
||||
.with_example({"SELECT jget('{ \"a\": 1, \"b\": 2 }', '/b')"})
|
||||
},
|
||||
|
@ -187,17 +187,13 @@ void listview_curses::do_update(void)
|
||||
}
|
||||
|
||||
if (this->lv_needs_update) {
|
||||
vis_line_t y(this->lv_y), height, bottom, row;
|
||||
vis_line_t height, row;
|
||||
attr_line_t overlay_line;
|
||||
vis_line_t overlay_height(0);
|
||||
struct line_range lr;
|
||||
unsigned long width, wrap_width;
|
||||
size_t row_count;
|
||||
|
||||
if (this->lv_overlay_source != NULL) {
|
||||
overlay_height = vis_line_t(
|
||||
this->lv_overlay_source->list_overlay_count(*this));
|
||||
}
|
||||
int y = this->lv_y, bottom;
|
||||
|
||||
this->get_dimensions(height, width);
|
||||
|
||||
@ -214,7 +210,8 @@ void listview_curses::do_update(void)
|
||||
if (this->lv_overlay_source != NULL &&
|
||||
this->lv_overlay_source->list_value_for_overlay(
|
||||
*this,
|
||||
y - vis_line_t(this->lv_y),
|
||||
y - this->lv_y, bottom - this->lv_y,
|
||||
row,
|
||||
overlay_line)) {
|
||||
this->mvwattrline(this->lv_window, y, this->lv_x, overlay_line, lr);
|
||||
overlay_line.clear();
|
||||
@ -254,10 +251,8 @@ void listview_curses::do_update(void)
|
||||
coverage = (double)height / (double)row_count;
|
||||
}
|
||||
|
||||
y = vis_line_t(this->lv_y) +
|
||||
vis_line_t((int)(progress * (double)height));
|
||||
lines = y + min(height, vis_line_t(
|
||||
(int)(coverage * (double)height)));
|
||||
y = this->lv_y + (int)(progress * (double)height);
|
||||
lines = vis_line_t(y + min((int) height, (int)(coverage * (double)height)));
|
||||
|
||||
for (unsigned int gutter_y = this->lv_y;
|
||||
gutter_y < (this->lv_y + height);
|
||||
@ -293,6 +288,7 @@ void listview_curses::do_update(void)
|
||||
|
||||
this->lv_needs_update = false;
|
||||
}
|
||||
#if 0
|
||||
else if (this->lv_overlay_needs_update && this->lv_overlay_source != NULL) {
|
||||
vis_line_t y(this->lv_y), height, bottom;
|
||||
attr_line_t overlay_line;
|
||||
@ -318,6 +314,7 @@ void listview_curses::do_update(void)
|
||||
++y;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int scroll_polarity(mouse_button_t button)
|
||||
|
@ -101,30 +101,13 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
struct listview_overlay {
|
||||
listview_overlay(int y, const attr_line_t &al) : lo_y(y), lo_line(al) { };
|
||||
|
||||
int get_absolute_y(int height) const
|
||||
{
|
||||
if (this->lo_y >= 0) {
|
||||
return this->lo_y;
|
||||
}
|
||||
|
||||
return height + this->lo_y;
|
||||
};
|
||||
|
||||
int lo_y;
|
||||
attr_line_t lo_line;
|
||||
};
|
||||
|
||||
class list_overlay_source {
|
||||
public:
|
||||
virtual ~list_overlay_source() { };
|
||||
|
||||
virtual size_t list_overlay_count(const listview_curses &lv) = 0;
|
||||
|
||||
virtual bool list_value_for_overlay(const listview_curses &lv,
|
||||
vis_line_t y,
|
||||
int y, int bottom,
|
||||
vis_line_t line,
|
||||
attr_line_t &value_out) = 0;
|
||||
};
|
||||
|
||||
|
130
src/lnav.cc
130
src/lnav.cc
@ -64,6 +64,7 @@
|
||||
#define _WCHAR_H_CPLUSPLUS_98_CONFORMANCE_
|
||||
#endif
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
@ -227,7 +228,7 @@ public:
|
||||
|
||||
next = bm[&textview_curses::BM_USER].next(vis_line_t(start));
|
||||
if (next == -1) {
|
||||
next = bm[&textview_curses::BM_PARTITION].next(vis_line_t(start));
|
||||
next = bm[&textview_curses::BM_META].next(vis_line_t(start));
|
||||
}
|
||||
if (next != -1 && next <= end) {
|
||||
ch = search_hit ? ACS_PLUS : ACS_LTEE;
|
||||
@ -588,11 +589,10 @@ void rebuild_indexes(bool force)
|
||||
}
|
||||
}
|
||||
|
||||
if (new_data && lnav_data.ld_search_child[LNV_TEXT].get() != NULL) {
|
||||
lnav_data.ld_search_child[LNV_TEXT]->get_grep_proc()->reset();
|
||||
if (new_data && lnav_data.ld_search_child[LNV_TEXT]) {
|
||||
lnav_data.ld_search_child[LNV_TEXT]->get_grep_proc()->
|
||||
queue_request(grep_line_t(-1));
|
||||
lnav_data.ld_search_child[LNV_TEXT]->get_grep_proc()->start();
|
||||
queue_request(-1_vl)
|
||||
.start();
|
||||
}
|
||||
text_view.reload_data();
|
||||
}
|
||||
@ -626,7 +626,7 @@ void rebuild_indexes(bool force)
|
||||
|
||||
if (lss.rebuild_index(force)) {
|
||||
size_t new_count = lss.text_line_count();
|
||||
grep_line_t start_line;
|
||||
vis_line_t start_line;
|
||||
|
||||
if (!scroll_downs[LNV_LOG] && force) {
|
||||
content_line_t new_top_content = content_line_t(-1);
|
||||
@ -640,20 +640,22 @@ void rebuild_indexes(bool force)
|
||||
}
|
||||
}
|
||||
|
||||
start_line = force ? grep_line_t(0) : grep_line_t(-1);
|
||||
start_line = force ? 0_vl : -1_vl;
|
||||
|
||||
if (force) {
|
||||
if (lnav_data.ld_search_child[LNV_LOG].get() != NULL) {
|
||||
if (lnav_data.ld_search_child[LNV_LOG]) {
|
||||
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->invalidate();
|
||||
}
|
||||
if (lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->invalidate();
|
||||
}
|
||||
log_view.match_reset();
|
||||
}
|
||||
|
||||
if (lnav_data.ld_search_child[LNV_LOG].get() != NULL) {
|
||||
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->reset();
|
||||
if (lnav_data.ld_search_child[LNV_LOG]) {
|
||||
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->
|
||||
queue_request(start_line);
|
||||
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->start();
|
||||
queue_request(start_line)
|
||||
.start();
|
||||
}
|
||||
|
||||
log_view.reload_data();
|
||||
@ -951,7 +953,7 @@ bool toggle_view(textview_curses *toggle_tc)
|
||||
else if (toggle_tc == &lnav_data.ld_views[LNV_HELP]) {
|
||||
build_all_help_text();
|
||||
}
|
||||
lnav_data.ld_last_view = NULL;
|
||||
lnav_data.ld_last_view = nullptr;
|
||||
lnav_data.ld_view_stack.push_back(toggle_tc);
|
||||
retval = true;
|
||||
}
|
||||
@ -967,15 +969,19 @@ void redo_search(lnav_view_t view_index)
|
||||
textview_curses *tc = &lnav_data.ld_views[view_index];
|
||||
|
||||
tc->reload_data();
|
||||
if (lnav_data.ld_search_child[view_index].get() != NULL) {
|
||||
grep_proc *gp = lnav_data.ld_search_child[view_index]->get_grep_proc();
|
||||
if (lnav_data.ld_search_child[view_index] != NULL) {
|
||||
grep_proc<vis_line_t> *gp = lnav_data.ld_search_child[view_index]->get_grep_proc();
|
||||
|
||||
gp->invalidate();
|
||||
tc->match_reset();
|
||||
gp->reset();
|
||||
gp->queue_request(grep_line_t(0));
|
||||
gp->queue_request(0_vl);
|
||||
gp->start();
|
||||
}
|
||||
if (view_index == LNV_LOG && lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->invalidate()
|
||||
.queue_request(0_vl)
|
||||
.start();
|
||||
}
|
||||
if (!lnav_data.ld_view_stack.empty() && tc == lnav_data.ld_view_stack.back()) {
|
||||
lnav_data.ld_scroll_broadcaster.invoke(tc);
|
||||
}
|
||||
@ -989,7 +995,7 @@ void redo_search(lnav_view_t view_index)
|
||||
*/
|
||||
bool ensure_view(textview_curses *expected_tc)
|
||||
{
|
||||
textview_curses *tc = lnav_data.ld_view_stack.empty() ? NULL : lnav_data.ld_view_stack.back();
|
||||
textview_curses *tc = lnav_data.ld_view_stack.empty() ? nullptr : lnav_data.ld_view_stack.back();
|
||||
bool retval = true;
|
||||
|
||||
if (tc != expected_tc) {
|
||||
@ -1142,17 +1148,17 @@ void execute_search(lnav_view_t view, const std::string ®ex_orig)
|
||||
unique_ptr<grep_highlighter> &gc = lnav_data.ld_search_child[view];
|
||||
textview_curses &tc = lnav_data.ld_views[view];
|
||||
std::string regex = regex_orig;
|
||||
pcre * code = NULL;
|
||||
pcre *code = nullptr;
|
||||
|
||||
if ((gc.get() == NULL) || (regex != lnav_data.ld_last_search[view])) {
|
||||
if ((gc.get() == nullptr) || (regex != lnav_data.ld_last_search[view])) {
|
||||
const char *errptr;
|
||||
int eoff;
|
||||
bool quoted = false;
|
||||
|
||||
tc.match_reset();
|
||||
|
||||
if (regex.empty() && gc.get() != NULL) {
|
||||
tc.grep_begin(*(gc->get_grep_proc()));
|
||||
if (regex.empty() && gc != nullptr) {
|
||||
tc.grep_begin(*(gc->get_grep_proc()), 0_vl, -1_vl);
|
||||
tc.grep_end(*(gc->get_grep_proc()));
|
||||
}
|
||||
gc.reset();
|
||||
@ -1166,7 +1172,7 @@ void execute_search(lnav_view_t view, const std::string ®ex_orig)
|
||||
PCRE_CASELESS,
|
||||
&errptr,
|
||||
&eoff,
|
||||
NULL)) == NULL) {
|
||||
nullptr)) == nullptr) {
|
||||
string errmsg = string(errptr);
|
||||
|
||||
quoted = true;
|
||||
@ -1177,7 +1183,7 @@ void execute_search(lnav_view_t view, const std::string ®ex_orig)
|
||||
PCRE_CASELESS,
|
||||
&errptr,
|
||||
&eoff,
|
||||
NULL)) == NULL) {
|
||||
nullptr)) == nullptr) {
|
||||
log_error("Unable to compile quoted regex: %s", regex.c_str());
|
||||
} else {
|
||||
lnav_data.ld_bottom_source.grep_error(
|
||||
@ -1187,7 +1193,7 @@ void execute_search(lnav_view_t view, const std::string ®ex_orig)
|
||||
}
|
||||
}
|
||||
|
||||
if (code != NULL) {
|
||||
if (code != nullptr) {
|
||||
highlighter hl(code);
|
||||
|
||||
hl.with_role(view_colors::VCR_SEARCH);
|
||||
@ -1200,23 +1206,34 @@ void execute_search(lnav_view_t view, const std::string ®ex_orig)
|
||||
textview_curses::highlight_map_t &hm = tc.get_highlights();
|
||||
hm["$search"] = hl;
|
||||
|
||||
unique_ptr<grep_proc> gp(new grep_proc(code, tc));
|
||||
unique_ptr<grep_proc<vis_line_t>> gp = make_unique<grep_proc<vis_line_t>>(code, tc);
|
||||
|
||||
gp->queue_request(grep_line_t(tc.get_top()));
|
||||
gp->set_sink(&tc);
|
||||
gp->queue_request(tc.get_top());
|
||||
if (tc.get_top() > 0) {
|
||||
gp->queue_request(grep_line_t(0), grep_line_t(tc.get_top()));
|
||||
gp->queue_request(0_vl, tc.get_top());
|
||||
}
|
||||
gp->start();
|
||||
gp->set_sink(&tc);
|
||||
|
||||
gc.reset(new grep_highlighter(gp, "$search", hm));
|
||||
gc = std::make_unique<grep_highlighter>(gp, "$search", hm);
|
||||
|
||||
if (view == LNV_LOG) {
|
||||
logfile_sub_source::meta_grepper &mg = lnav_data.ld_log_source.get_meta_grepper();
|
||||
shared_ptr<grep_proc<vis_line_t>> mgp = make_shared<grep_proc<vis_line_t>>(code, mg);
|
||||
|
||||
mgp->set_sink(&mg);
|
||||
mgp->queue_request(0_vl);
|
||||
mgp->start();
|
||||
|
||||
lnav_data.ld_meta_search = mgp;
|
||||
}
|
||||
}
|
||||
|
||||
if (view == LNV_LOG) {
|
||||
static intern_string_t log_search_name = intern_string::lookup("log_search");
|
||||
|
||||
lnav_data.ld_vtab_manager->unregister_vtab(log_search_name);
|
||||
if (code != NULL) {
|
||||
if (code != nullptr) {
|
||||
lnav_data.ld_vtab_manager->register_vtab(new log_search_table(
|
||||
regex.c_str(), log_search_name));
|
||||
}
|
||||
@ -1226,7 +1243,7 @@ void execute_search(lnav_view_t view, const std::string ®ex_orig)
|
||||
lnav_data.ld_last_search[view] = regex;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
static void usage()
|
||||
{
|
||||
const char *usage_msg =
|
||||
"usage: %s [options] [logfile1 logfile2 ...]\n"
|
||||
@ -1486,7 +1503,7 @@ static void expand_filename(string path, bool required)
|
||||
for (lpc = 0; lpc < (int)gl->gl_pathc; lpc++) {
|
||||
auto_mem<char> abspath;
|
||||
|
||||
if ((abspath = realpath(gl->gl_pathv[lpc], NULL)) == NULL) {
|
||||
if ((abspath = realpath(gl->gl_pathv[lpc], nullptr)) == NULL) {
|
||||
if (required) {
|
||||
fprintf(stderr, "Cannot find file: %s -- %s",
|
||||
gl->gl_pathv[lpc], strerror(errno));
|
||||
@ -1980,7 +1997,9 @@ static void execute_examples()
|
||||
ex.he_result.append(dls.dls_rows[0][0]);
|
||||
} else {
|
||||
attr_line_t al;
|
||||
dos.list_value_for_overlay(db_tc, vis_line_t(0),
|
||||
dos.list_value_for_overlay(db_tc,
|
||||
0, 1,
|
||||
vis_line_t(0),
|
||||
al);
|
||||
ex.he_result.append(al);
|
||||
for (int lpc = 0;
|
||||
@ -2321,6 +2340,9 @@ static void looper(void)
|
||||
gc->get_grep_proc()->update_poll_set(pollfds);
|
||||
}
|
||||
}
|
||||
if (lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->update_poll_set(pollfds);
|
||||
}
|
||||
|
||||
rc = poll(&pollfds[0], pollfds.size(), to.tv_usec / 1000);
|
||||
|
||||
@ -2414,6 +2436,9 @@ static void looper(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->check_poll_set(pollfds);
|
||||
}
|
||||
rlc.check_poll_set(pollfds);
|
||||
}
|
||||
|
||||
@ -2531,6 +2556,10 @@ static void looper(void)
|
||||
gather_pipers();
|
||||
}
|
||||
|
||||
if (lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->start();
|
||||
}
|
||||
|
||||
if (lnav_data.ld_view_stack.empty() ||
|
||||
(lnav_data.ld_view_stack.size() == 1 &&
|
||||
starting_view_stack_size == 2 &&
|
||||
@ -2550,6 +2579,10 @@ void wait_for_children()
|
||||
vector<struct pollfd> pollfds;
|
||||
struct timeval to = { 0, 333000 };
|
||||
|
||||
if (lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->start();
|
||||
}
|
||||
|
||||
do {
|
||||
pollfds.clear();
|
||||
|
||||
@ -2558,6 +2591,9 @@ void wait_for_children()
|
||||
gc->get_grep_proc()->update_poll_set(pollfds);
|
||||
}
|
||||
}
|
||||
if (lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->update_poll_set(pollfds);
|
||||
}
|
||||
|
||||
if (pollfds.empty()) {
|
||||
return;
|
||||
@ -2585,6 +2621,9 @@ void wait_for_children()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lnav_data.ld_meta_search) {
|
||||
lnav_data.ld_meta_search->check_poll_set(pollfds);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@ -3628,13 +3667,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
los = tc->get_overlay_source();
|
||||
|
||||
for (vis_line_t vl = tc->get_top();
|
||||
vis_line_t vl;
|
||||
for (vl = tc->get_top();
|
||||
vl < tc->get_inner_height();
|
||||
++vl, ++y) {
|
||||
attr_line_t al;
|
||||
string &line = al.get_string();
|
||||
while (los != NULL &&
|
||||
los->list_value_for_overlay(*tc, y, al)) {
|
||||
while (los != nullptr &&
|
||||
los->list_value_for_overlay(*tc, y, tc->get_inner_height(), vl, al)) {
|
||||
if (write(STDOUT_FILENO, line.c_str(),
|
||||
line.length()) == -1 ||
|
||||
write(STDOUT_FILENO, "\n", 1) == -1) {
|
||||
@ -3656,6 +3696,22 @@ int main(int argc, char *argv[])
|
||||
write(STDOUT_FILENO, "\n", 1) == -1) {
|
||||
perror("2 write to STDOUT");
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
attr_line_t al;
|
||||
string &line = al.get_string();
|
||||
|
||||
while (los != nullptr &&
|
||||
los->list_value_for_overlay(*tc, y, tc->get_inner_height(), vl, al) &&
|
||||
!al.empty()) {
|
||||
if (write(STDOUT_FILENO, line.c_str(),
|
||||
line.length()) == -1 ||
|
||||
write(STDOUT_FILENO, "\n", 1) == -1) {
|
||||
perror("1 write to STDOUT");
|
||||
}
|
||||
++y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -266,6 +266,7 @@ struct _lnav_data {
|
||||
textview_curses *ld_last_view;
|
||||
textview_curses ld_views[LNV__MAX];
|
||||
std::unique_ptr<grep_highlighter> ld_search_child[LNV__MAX];
|
||||
std::shared_ptr<grep_proc<vis_line_t>> ld_meta_search;
|
||||
vis_line_t ld_search_start_line;
|
||||
readline_curses * ld_rl_view;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -264,7 +264,7 @@ void log_msg(lnav_log_level_t level, const char *src_file, int line_number,
|
||||
}
|
||||
line[prefix_size + rc] = '\n';
|
||||
log_ring.lr_length += prefix_size + rc + 1;
|
||||
if (lnav_log_file != NULL) {
|
||||
if (lnav_log_file != nullptr) {
|
||||
fwrite(line, 1, prefix_size + rc + 1, lnav_log_file);
|
||||
fflush(lnav_log_file);
|
||||
}
|
||||
@ -283,7 +283,7 @@ void log_msg_extra(const char *fmt, ...)
|
||||
line = log_alloc();
|
||||
rc = vsnprintf(line, MAX_LOG_LINE_SIZE - 1, fmt, args);
|
||||
log_ring.lr_length += rc;
|
||||
if (lnav_log_file != NULL) {
|
||||
if (lnav_log_file != nullptr) {
|
||||
fwrite(line, 1, rc, lnav_log_file);
|
||||
fflush(lnav_log_file);
|
||||
}
|
||||
@ -299,7 +299,7 @@ void log_msg_extra_complete()
|
||||
line = log_alloc();
|
||||
line[0] = '\n';
|
||||
log_ring.lr_length += 1;
|
||||
if (lnav_log_file != NULL) {
|
||||
if (lnav_log_file != nullptr) {
|
||||
fwrite(line, 1, 1, lnav_log_file);
|
||||
fflush(lnav_log_file);
|
||||
}
|
||||
@ -315,7 +315,7 @@ static void sigabrt(int sig)
|
||||
struct tm localtm;
|
||||
time_t curr_time;
|
||||
|
||||
if (lnav_log_crash_dir == NULL) {
|
||||
if (lnav_log_crash_dir == nullptr) {
|
||||
printf("%*s", (int) log_ring.lr_length, log_ring.lr_data);
|
||||
return;
|
||||
}
|
||||
@ -325,7 +325,7 @@ static void sigabrt(int sig)
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
frame_count = backtrace(frames, 128);
|
||||
#endif
|
||||
curr_time = time(NULL);
|
||||
curr_time = time(nullptr);
|
||||
localtime_r(&curr_time, &localtm);
|
||||
snprintf(crash_path, sizeof(crash_path),
|
||||
"%s/crash-%4d-%02d-%02d-%02d-%02d-%02d.%d.log",
|
||||
|
@ -78,6 +78,22 @@ inline std::string tolower(const std::string &str)
|
||||
return tolower(str.c_str());
|
||||
}
|
||||
|
||||
inline std::string toupper(const char *str)
|
||||
{
|
||||
std::string retval;
|
||||
|
||||
for (int lpc = 0; str[lpc]; lpc++) {
|
||||
retval.push_back(::toupper(str[lpc]));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline std::string toupper(const std::string &str)
|
||||
{
|
||||
return toupper(str.c_str());
|
||||
}
|
||||
|
||||
size_t unquote(char *dst, const char *str, size_t len);
|
||||
|
||||
#undef rounddown
|
||||
|
@ -1005,6 +1005,10 @@ void external_log_format::rewrite(exec_context &ec,
|
||||
continue;
|
||||
}
|
||||
|
||||
ec.ec_source.emplace(this->elf_name.to_string() +
|
||||
":" +
|
||||
vd_iter->first.to_string(),
|
||||
1);
|
||||
string field_value = execute_any(ec, vd.vd_rewriter);
|
||||
struct line_range adj_origin = iter->origin_in_full_msg(
|
||||
value_out.c_str(), value_out.length());
|
||||
|
@ -692,11 +692,17 @@ static void write_sample_file(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void format_error_reporter(const yajlpp_parse_context &ypc, const char *msg)
|
||||
static void format_error_reporter(const yajlpp_parse_context &ypc,
|
||||
lnav_log_level_t level,
|
||||
const char *msg)
|
||||
{
|
||||
if (level >= LOG_LEVEL_ERROR) {
|
||||
struct userdata *ud = (userdata *) ypc.ypc_userdata;
|
||||
|
||||
ud->ud_errors->push_back(msg);
|
||||
} else {
|
||||
fprintf(stderr, "warning:%s\n", msg);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<intern_string_t> load_format_file(const string &filename, std::vector<string> &errors)
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "lnav.hh"
|
||||
#include "lnav_log.hh"
|
||||
#include "sql_util.hh"
|
||||
#include "log_vtab_impl.hh"
|
||||
@ -39,7 +40,7 @@ using namespace std;
|
||||
|
||||
static struct log_cursor log_cursor_latest;
|
||||
|
||||
sql_progress_callback_t log_vtab_progress_callback;
|
||||
struct _log_vtab_data log_vtab_data;
|
||||
|
||||
static const char *type_to_string(int type)
|
||||
{
|
||||
@ -59,7 +60,7 @@ static const char *type_to_string(int type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string log_vtab_impl::get_table_statement(void)
|
||||
std::string log_vtab_impl::get_table_statement()
|
||||
{
|
||||
std::vector<log_vtab_impl::vtab_column> cols;
|
||||
std::vector<log_vtab_impl::vtab_column>::const_iterator iter;
|
||||
@ -74,6 +75,8 @@ std::string log_vtab_impl::get_table_statement(void)
|
||||
<< " log_idle_msecs INTEGER,\n"
|
||||
<< " log_level TEXT COLLATE loglevel,\n"
|
||||
<< " log_mark BOOLEAN,\n"
|
||||
<< " log_comment TEXT,\n"
|
||||
<< " log_tags TEXT,\n"
|
||||
<< " -- BEGIN Format-specific fields:\n";
|
||||
this->get_columns(cols);
|
||||
this->vi_column_count = cols.size();
|
||||
@ -272,8 +275,8 @@ static int vt_next(sqlite3_vtab_cursor *cur)
|
||||
do {
|
||||
log_cursor_latest = vc->log_cursor;
|
||||
if (((log_cursor_latest.lc_curr_line % 1024) == 0) &&
|
||||
(log_vtab_progress_callback != NULL &&
|
||||
log_vtab_progress_callback(log_cursor_latest))) {
|
||||
(log_vtab_data.lvd_progress != NULL &&
|
||||
log_vtab_data.lvd_progress(log_cursor_latest))) {
|
||||
break;
|
||||
}
|
||||
done = vt->vi->next(vc->log_cursor, *vt->lss);
|
||||
@ -304,7 +307,7 @@ static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
|
||||
case VT_COL_PARTITION:
|
||||
{
|
||||
vis_bookmarks &vb = vt->tc->get_bookmarks();
|
||||
bookmark_vector<vis_line_t> &bv = vb[&textview_curses::BM_PARTITION];
|
||||
bookmark_vector<vis_line_t> &bv = vb[&textview_curses::BM_META];
|
||||
bookmark_vector<vis_line_t>::iterator iter;
|
||||
vis_line_t curr_line;
|
||||
|
||||
@ -323,7 +326,7 @@ static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
|
||||
std::map<content_line_t, bookmark_metadata>::iterator meta_iter;
|
||||
|
||||
meta_iter = bm_meta.find(part_line);
|
||||
if (meta_iter != bm_meta.end()) {
|
||||
if (meta_iter != bm_meta.end() && !meta_iter->second.bm_name.empty()) {
|
||||
sqlite3_result_text(ctx,
|
||||
meta_iter->second.bm_name.c_str(),
|
||||
meta_iter->second.bm_name.size(),
|
||||
@ -416,6 +419,54 @@ static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_COL_LOG_COMMENT: {
|
||||
const map<content_line_t, bookmark_metadata> &bm = vt->lss->get_user_bookmark_metadata();
|
||||
|
||||
auto bm_iter = bm.find(vt->lss->at(vc->log_cursor.lc_curr_line));
|
||||
if (bm_iter == bm.end() || bm_iter->second.bm_comment.empty()) {
|
||||
sqlite3_result_null(ctx);
|
||||
} else {
|
||||
const bookmark_metadata &meta = bm_iter->second;
|
||||
sqlite3_result_text(ctx,
|
||||
meta.bm_comment.c_str(),
|
||||
meta.bm_comment.length(),
|
||||
SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VT_COL_LOG_TAGS: {
|
||||
const map<content_line_t, bookmark_metadata> &bm = vt->lss->get_user_bookmark_metadata();
|
||||
|
||||
auto bm_iter = bm.find(vt->lss->at(vc->log_cursor.lc_curr_line));
|
||||
if (bm_iter == bm.end() || bm_iter->second.bm_tags.empty()) {
|
||||
sqlite3_result_null(ctx);
|
||||
} else {
|
||||
const bookmark_metadata &meta = bm_iter->second;
|
||||
|
||||
yajlpp_gen gen;
|
||||
|
||||
yajl_gen_config(gen, yajl_gen_beautify, false);
|
||||
|
||||
{
|
||||
yajlpp_array arr(gen);
|
||||
|
||||
for (auto str : meta.bm_tags) {
|
||||
arr.gen(str);
|
||||
}
|
||||
}
|
||||
|
||||
string_fragment sf = gen.to_string_fragment();
|
||||
|
||||
sqlite3_result_text(ctx,
|
||||
sf.data(),
|
||||
sf.length(),
|
||||
SQLITE_TRANSIENT);
|
||||
sqlite3_result_subtype(ctx, 'J');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (col > (VT_COL_MAX + vt->vi->vi_column_count - 1)) {
|
||||
int post_col_number = col -
|
||||
@ -708,6 +759,16 @@ static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info)
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static struct json_path_handler tags_handler[] = {
|
||||
json_path_handler("#")
|
||||
.with_synopsis("<tag>")
|
||||
.with_description("A tag for the log line")
|
||||
.with_pattern(R"(^#[^\s]+$)")
|
||||
.for_field(&nullobj<bookmark_metadata>()->bm_tags),
|
||||
|
||||
json_path_handler()
|
||||
};
|
||||
|
||||
static int vt_update(sqlite3_vtab *tab,
|
||||
int argc,
|
||||
sqlite3_value **argv,
|
||||
@ -724,33 +785,66 @@ static int vt_update(sqlite3_vtab *tab,
|
||||
|
||||
std::map<content_line_t, bookmark_metadata> &bm = vt->lss->get_user_bookmark_metadata();
|
||||
const unsigned char *part_name = sqlite3_value_text(argv[2 + VT_COL_PARTITION]);
|
||||
const unsigned char *log_comment = sqlite3_value_text(argv[2 + VT_COL_LOG_COMMENT]);
|
||||
const unsigned char *log_tags = sqlite3_value_text(argv[2 + VT_COL_LOG_TAGS]);
|
||||
|
||||
bookmark_vector<vis_line_t> &bv = vt->tc->get_bookmarks()[
|
||||
&textview_curses::BM_PARTITION];
|
||||
bookmark_vector<vis_line_t>::iterator part_iter;
|
||||
bool set_name = false;
|
||||
&textview_curses::BM_META];
|
||||
bool has_meta = part_name != nullptr || log_comment != nullptr ||
|
||||
log_tags != nullptr;
|
||||
|
||||
if ((part_iter = find(bv.begin(), bv.end(), vrowid)) != bv.end()) {
|
||||
if (part_name == NULL) {
|
||||
vt->tc->set_user_mark(&textview_curses::BM_PARTITION, vrowid, false);
|
||||
if (binary_search(bv.begin(), bv.end(), vrowid) && !has_meta) {
|
||||
vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, false);
|
||||
bm.erase(vt->lss->at(vrowid));
|
||||
}
|
||||
else {
|
||||
set_name = true;
|
||||
}
|
||||
}
|
||||
else if (part_name != NULL) {
|
||||
vt->tc->set_user_mark(&textview_curses::BM_PARTITION, vrowid, true);
|
||||
set_name = true;
|
||||
}
|
||||
|
||||
if (set_name) {
|
||||
if (has_meta) {
|
||||
bookmark_metadata &line_meta = bm[vt->lss->at(vrowid)];
|
||||
|
||||
vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, true);
|
||||
if (part_name) {
|
||||
line_meta.bm_name = string((const char *) part_name);
|
||||
} else {
|
||||
line_meta.bm_name.clear();
|
||||
}
|
||||
if (log_comment) {
|
||||
line_meta.bm_comment = string((const char *) log_comment);
|
||||
} else {
|
||||
line_meta.bm_comment.clear();
|
||||
}
|
||||
if (log_tags) {
|
||||
vector<string> errors;
|
||||
yajlpp_parse_context ypc(log_vtab_data.lvd_source, tags_handler);
|
||||
auto_mem<yajl_handle_t> handle(yajl_free);
|
||||
|
||||
line_meta.bm_tags.clear();
|
||||
handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc);
|
||||
ypc.ypc_userdata = &errors;
|
||||
ypc.ypc_line_number = log_vtab_data.lvd_line_number;
|
||||
ypc.with_handle(handle)
|
||||
.with_error_reporter([](const yajlpp_parse_context &ypc,
|
||||
lnav_log_level_t level,
|
||||
const char *msg) {
|
||||
vector<string> &errors = *((vector<string> *) ypc.ypc_userdata);
|
||||
errors.emplace_back(msg);
|
||||
})
|
||||
.with_obj(line_meta);
|
||||
ypc.parse(log_tags, strlen((const char *) log_tags));
|
||||
ypc.complete_parse();
|
||||
if (!errors.empty()) {
|
||||
tab->zErrMsg = sqlite3_mprintf("%s",
|
||||
join(errors.begin(), errors.end(), "\n").c_str());
|
||||
retval = SQLITE_ERROR;
|
||||
}
|
||||
for (const auto &tag : line_meta.bm_tags) {
|
||||
bookmark_metadata::KNOWN_TAGS.insert(tag);
|
||||
}
|
||||
} else {
|
||||
line_meta.bm_tags.clear();
|
||||
}
|
||||
}
|
||||
|
||||
vt->tc->set_user_mark(&textview_curses::BM_USER, vis_line_t(rowid), val);
|
||||
vt->tc->set_user_mark(&textview_curses::BM_USER, vrowid, val);
|
||||
rowid += 1;
|
||||
while ((size_t)rowid < vt->lss->text_line_count()) {
|
||||
vis_line_t vl(rowid);
|
||||
@ -763,8 +857,10 @@ static int vt_update(sqlite3_vtab *tab,
|
||||
rowid += 1;
|
||||
}
|
||||
|
||||
if (retval != SQLITE_ERROR) {
|
||||
retval = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -795,8 +891,8 @@ static int progress_callback(void *ptr)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
if (log_vtab_progress_callback != NULL) {
|
||||
retval = log_vtab_progress_callback(log_cursor_latest);
|
||||
if (log_vtab_data.lvd_progress != NULL) {
|
||||
retval = log_vtab_data.lvd_progress(log_cursor_latest);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -47,6 +47,8 @@ enum {
|
||||
VT_COL_IDLE_MSECS,
|
||||
VT_COL_LEVEL,
|
||||
VT_COL_MARK,
|
||||
VT_COL_LOG_COMMENT,
|
||||
VT_COL_LOG_TAGS,
|
||||
VT_COL_MAX
|
||||
};
|
||||
|
||||
@ -188,16 +190,26 @@ protected:
|
||||
|
||||
typedef int (*sql_progress_callback_t)(const log_cursor &lc);
|
||||
|
||||
extern sql_progress_callback_t log_vtab_progress_callback;
|
||||
extern struct _log_vtab_data {
|
||||
sql_progress_callback_t lvd_progress;
|
||||
std::string lvd_source;
|
||||
int lvd_line_number{0};
|
||||
} log_vtab_data;
|
||||
|
||||
class sql_progress_guard {
|
||||
public:
|
||||
sql_progress_guard(sql_progress_callback_t cb) {
|
||||
log_vtab_progress_callback = cb;
|
||||
sql_progress_guard(sql_progress_callback_t cb,
|
||||
const std::string &source,
|
||||
int line_number) {
|
||||
log_vtab_data.lvd_progress = cb;
|
||||
log_vtab_data.lvd_source = source;
|
||||
log_vtab_data.lvd_line_number = line_number;
|
||||
};
|
||||
|
||||
~sql_progress_guard() {
|
||||
log_vtab_progress_callback = NULL;
|
||||
log_vtab_data.lvd_progress = NULL;
|
||||
log_vtab_data.lvd_source.clear();
|
||||
log_vtab_data.lvd_line_number = 0;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -54,21 +54,10 @@ static const size_t MAX_UNRECOGNIZED_LINES = 1000;
|
||||
static const size_t INDEX_RESERVE_INCREMENT = 1024;
|
||||
|
||||
logfile::logfile(const string &filename, logfile_open_options &loo)
|
||||
: lf_filename(filename),
|
||||
lf_index_time(0),
|
||||
lf_index_size(0),
|
||||
lf_sort_needed(false),
|
||||
lf_is_closed(false),
|
||||
lf_logline_observer(NULL),
|
||||
lf_logfile_observer(NULL),
|
||||
lf_longest_line(0),
|
||||
lf_text_format(TF_UNKNOWN)
|
||||
: lf_filename(filename)
|
||||
{
|
||||
require(filename.size() > 0);
|
||||
|
||||
this->lf_time_offset.tv_sec = 0;
|
||||
this->lf_time_offset.tv_usec = 0;
|
||||
|
||||
memset(&this->lf_stat, 0, sizeof(this->lf_stat));
|
||||
if (loo.loo_fd == -1) {
|
||||
char resolved_path[PATH_MAX];
|
||||
@ -372,7 +361,7 @@ logfile::rebuild_result_t logfile::rebuild_index()
|
||||
old_size = 0;
|
||||
}
|
||||
|
||||
for (logfile::iterator iter = this->begin() + old_size;
|
||||
for (auto iter = this->begin() + old_size;
|
||||
iter != this->end(); ++iter) {
|
||||
if (this->lf_logline_observer != NULL) {
|
||||
this->lf_logline_observer->logline_new_line(*this, iter, sbr);
|
||||
@ -386,7 +375,7 @@ logfile::rebuild_result_t logfile::rebuild_index()
|
||||
st.st_size);
|
||||
}
|
||||
|
||||
if (!has_format && this->lf_format.get() != NULL) {
|
||||
if (!has_format && this->lf_format != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -438,7 +427,7 @@ void logfile::read_line(logfile::iterator ll, string &line_out)
|
||||
|
||||
line_out.clear();
|
||||
if (this->lf_line_buffer.read_line(off, sbr)) {
|
||||
if (this->lf_format.get() != NULL) {
|
||||
if (this->lf_format != NULL) {
|
||||
this->lf_format->get_subline(*ll, sbr);
|
||||
}
|
||||
line_out.append(sbr.get_data(), sbr.length());
|
||||
@ -458,7 +447,7 @@ bool logfile::read_line(logfile::iterator ll, shared_buffer_ref &sbr)
|
||||
off_t off = ll->get_offset();
|
||||
|
||||
if (this->lf_line_buffer.read_line(off, sbr)) {
|
||||
if (this->lf_format.get() != NULL) {
|
||||
if (this->lf_format != NULL) {
|
||||
this->lf_format->get_subline(*ll, sbr);
|
||||
}
|
||||
return true;
|
||||
|
@ -423,18 +423,18 @@ protected:
|
||||
struct stat lf_stat;
|
||||
std::unique_ptr<log_format> lf_format;
|
||||
std::vector<logline> lf_index;
|
||||
time_t lf_index_time;
|
||||
off_t lf_index_size;
|
||||
bool lf_sort_needed;
|
||||
time_t lf_index_time{0};
|
||||
off_t lf_index_size{0};
|
||||
bool lf_sort_needed{false};
|
||||
line_buffer lf_line_buffer;
|
||||
int lf_time_offset_line;
|
||||
struct timeval lf_time_offset;
|
||||
bool lf_is_closed;
|
||||
bool lf_partial_line;
|
||||
logline_observer *lf_logline_observer;
|
||||
logfile_observer *lf_logfile_observer;
|
||||
size_t lf_longest_line;
|
||||
text_format_t lf_text_format;
|
||||
int lf_time_offset_line{0};
|
||||
struct timeval lf_time_offset{0, 0};
|
||||
bool lf_is_closed{false};
|
||||
bool lf_partial_line{false};
|
||||
logline_observer *lf_logline_observer{nullptr};
|
||||
logfile_observer *lf_logfile_observer{nullptr};
|
||||
size_t lf_longest_line{0};
|
||||
text_format_t lf_text_format{TF_UNKNOWN};
|
||||
};
|
||||
|
||||
class logline_observer {
|
||||
|
@ -101,8 +101,10 @@ logfile_sub_source::logfile_sub_source()
|
||||
lss_force_rebuild(false),
|
||||
lss_token_file(NULL),
|
||||
lss_min_log_level(logline::LEVEL_UNKNOWN),
|
||||
lss_marked_only(false),
|
||||
lss_index_delegate(NULL),
|
||||
lss_longest_line(0)
|
||||
lss_longest_line(0),
|
||||
lss_meta_grepper(*this)
|
||||
{
|
||||
this->clear_line_size_cache();
|
||||
this->clear_min_max_log_times();
|
||||
@ -485,7 +487,7 @@ void logfile_sub_source::text_attrs_for_line(textview_curses &lv,
|
||||
this->lss_token_file->get_format()->get_name());
|
||||
|
||||
{
|
||||
bookmark_vector<vis_line_t> &bv = lv.get_bookmarks()[&textview_curses::BM_PARTITION];
|
||||
bookmark_vector<vis_line_t> &bv = lv.get_bookmarks()[&textview_curses::BM_META];
|
||||
bookmark_vector<vis_line_t>::iterator bv_iter;
|
||||
|
||||
bv_iter = lower_bound(bv.begin(), bv.end(), vis_line_t(row + 1));
|
||||
@ -495,7 +497,8 @@ void logfile_sub_source::text_attrs_for_line(textview_curses &lv,
|
||||
std::map<content_line_t, bookmark_metadata>::iterator bm_iter;
|
||||
|
||||
if ((bm_iter = this->lss_user_mark_metadata.find(part_start_line))
|
||||
!= this->lss_user_mark_metadata.end()) {
|
||||
!= this->lss_user_mark_metadata.end() &&
|
||||
!bm_iter->second.bm_name.empty()) {
|
||||
lr.lr_start = 0;
|
||||
lr.lr_end = -1;
|
||||
value_out.emplace_back(lr, &logline::L_PARTITION, &bm_iter->second);
|
||||
@ -706,7 +709,7 @@ bool logfile_sub_source::rebuild_index(bool force)
|
||||
content_line_t cl = (content_line_t) this->lss_index[index_index];
|
||||
uint64_t line_number;
|
||||
logfile_data *ld = this->find_data(cl, line_number);
|
||||
logfile::iterator line_iter = ld->get_file()->begin() + line_number;
|
||||
auto line_iter = ld->get_file()->begin() + line_number;
|
||||
|
||||
if (!ld->ld_filter_state.excluded(filter_in_mask, filter_out_mask,
|
||||
line_number) && this->check_extra_filters(*line_iter)) {
|
||||
@ -719,7 +722,7 @@ bool logfile_sub_source::rebuild_index(bool force)
|
||||
}
|
||||
}
|
||||
|
||||
if (this->lss_index_delegate != NULL) {
|
||||
if (this->lss_index_delegate != nullptr) {
|
||||
this->lss_index_delegate->index_complete(*this);
|
||||
}
|
||||
}
|
||||
@ -729,18 +732,15 @@ bool logfile_sub_source::rebuild_index(bool force)
|
||||
|
||||
void logfile_sub_source::text_update_marks(vis_bookmarks &bm)
|
||||
{
|
||||
shared_ptr<logfile> last_file = NULL;
|
||||
shared_ptr<logfile> last_file = nullptr;
|
||||
vis_line_t vl;
|
||||
|
||||
bm[&BM_WARNINGS].clear();
|
||||
bm[&BM_ERRORS].clear();
|
||||
bm[&BM_FILES].clear();
|
||||
|
||||
for (bookmarks<content_line_t>::type::iterator iter =
|
||||
this->lss_user_marks.begin();
|
||||
iter != this->lss_user_marks.end();
|
||||
++iter) {
|
||||
bm[iter->first].clear();
|
||||
for (auto &lss_user_mark : this->lss_user_marks) {
|
||||
bm[lss_user_mark.first].clear();
|
||||
}
|
||||
|
||||
for (; vl < (int)this->lss_filtered_index.size(); ++vl) {
|
||||
@ -750,16 +750,13 @@ void logfile_sub_source::text_update_marks(vis_bookmarks &bm)
|
||||
|
||||
lf = this->find(cl);
|
||||
|
||||
for (bookmarks<content_line_t>::type::iterator iter =
|
||||
this->lss_user_marks.begin();
|
||||
iter != this->lss_user_marks.end();
|
||||
++iter) {
|
||||
if (binary_search(iter->second.begin(),
|
||||
iter->second.end(),
|
||||
for (auto &lss_user_mark : this->lss_user_marks) {
|
||||
if (binary_search(lss_user_mark.second.begin(),
|
||||
lss_user_mark.second.end(),
|
||||
orig_cl)) {
|
||||
bm[iter->first].insert_once(vl);
|
||||
bm[lss_user_mark.first].insert_once(vl);
|
||||
|
||||
if (iter->first == &textview_curses::BM_USER) {
|
||||
if (lss_user_mark.first == &textview_curses::BM_USER) {
|
||||
logfile::iterator ll = lf->begin() + cl;
|
||||
|
||||
ll->set_mark(true);
|
||||
@ -771,7 +768,7 @@ void logfile_sub_source::text_update_marks(vis_bookmarks &bm)
|
||||
bm[&BM_FILES].insert_once(vl);
|
||||
}
|
||||
|
||||
logfile::iterator line_iter = lf->begin() + cl;
|
||||
auto line_iter = lf->begin() + cl;
|
||||
if (!line_iter->is_continued()) {
|
||||
switch (line_iter->get_msg_level()) {
|
||||
case logline::LEVEL_WARNING:
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
@ -89,17 +90,12 @@ public:
|
||||
logfile_sub_source();
|
||||
virtual ~logfile_sub_source();
|
||||
|
||||
void toggle_scrub(void) {
|
||||
this->lss_flags ^= F_SCRUB;
|
||||
this->clear_line_size_cache();
|
||||
};
|
||||
|
||||
void toggle_time_offset(void) {
|
||||
void toggle_time_offset() {
|
||||
this->lss_flags ^= F_TIME_OFFSET;
|
||||
this->clear_line_size_cache();
|
||||
};
|
||||
|
||||
void increase_line_context(void) {
|
||||
void increase_line_context() {
|
||||
auto old_flags = this->lss_flags;
|
||||
|
||||
if (this->lss_flags & F_FILENAME) {
|
||||
@ -115,7 +111,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool decrease_line_context(void) {
|
||||
bool decrease_line_context() {
|
||||
auto old_flags = this->lss_flags;
|
||||
|
||||
if (this->lss_flags & F_FILENAME) {
|
||||
@ -141,19 +137,19 @@ public:
|
||||
this->clear_line_size_cache();
|
||||
};
|
||||
|
||||
bool is_time_offset_enabled(void) const {
|
||||
bool is_time_offset_enabled() const {
|
||||
return (bool) (this->lss_flags & F_TIME_OFFSET);
|
||||
};
|
||||
|
||||
bool is_filename_enabled(void) const {
|
||||
bool is_filename_enabled() const {
|
||||
return (bool) (this->lss_flags & F_FILENAME);
|
||||
};
|
||||
|
||||
bool is_basename_enabled(void) const {
|
||||
bool is_basename_enabled() const {
|
||||
return (bool) (this->lss_flags & F_BASENAME);
|
||||
};
|
||||
|
||||
logline::level_t get_min_log_level(void) const {
|
||||
logline::level_t get_min_log_level() const {
|
||||
return this->lss_min_log_level;
|
||||
};
|
||||
|
||||
@ -199,6 +195,17 @@ public:
|
||||
|
||||
bool list_input_handle_key(listview_curses &lv, int ch);
|
||||
|
||||
void set_marked_only(bool val) {
|
||||
if (this->lss_marked_only != val) {
|
||||
this->lss_marked_only = val;
|
||||
this->lss_force_rebuild = true;
|
||||
}
|
||||
};
|
||||
|
||||
bool get_marked_only() {
|
||||
return this->lss_marked_only;
|
||||
};
|
||||
|
||||
size_t text_line_count()
|
||||
{
|
||||
return this->lss_filtered_index.size();
|
||||
@ -245,13 +252,13 @@ public:
|
||||
return this->lss_line_size_cache[index].second;
|
||||
};
|
||||
|
||||
void text_mark(bookmark_type_t *bm, int line, bool added)
|
||||
void text_mark(bookmark_type_t *bm, vis_line_t line, bool added)
|
||||
{
|
||||
if (line >= (int) this->lss_index.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
content_line_t cl = this->at(vis_line_t(line));
|
||||
content_line_t cl = this->at(line);
|
||||
std::vector<content_line_t>::iterator lb;
|
||||
|
||||
if (bm == &textview_curses::BM_USER) {
|
||||
@ -272,6 +279,10 @@ public:
|
||||
|
||||
this->lss_user_marks[bm].erase(lb);
|
||||
}
|
||||
if (bm == &textview_curses::BM_META &&
|
||||
this->lss_meta_grepper.gps_proc != nullptr) {
|
||||
this->lss_meta_grepper.gps_proc->queue_request(line, line + 1_vl);
|
||||
}
|
||||
};
|
||||
|
||||
void text_clear_marks(bookmark_type_t *bm)
|
||||
@ -280,12 +291,18 @@ public:
|
||||
|
||||
if (bm == &textview_curses::BM_USER) {
|
||||
for (iter = this->lss_user_marks[bm].begin();
|
||||
iter != this->lss_user_marks[bm].end();
|
||||
++iter) {
|
||||
iter != this->lss_user_marks[bm].end();) {
|
||||
auto bm_iter = this->lss_user_mark_metadata.find(*iter);
|
||||
if (bm_iter != this->lss_user_mark_metadata.end()) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
this->find_line(*iter)->set_mark(false);
|
||||
iter = this->lss_user_marks[bm].erase(iter);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->lss_user_marks[bm].clear();
|
||||
}
|
||||
};
|
||||
|
||||
bool insert_file(std::shared_ptr<logfile> lf)
|
||||
@ -355,12 +372,12 @@ public:
|
||||
this->lss_user_marks[bm].insert_once(cl);
|
||||
};
|
||||
|
||||
bookmarks<content_line_t>::type &get_user_bookmarks(void)
|
||||
bookmarks<content_line_t>::type &get_user_bookmarks()
|
||||
{
|
||||
return this->lss_user_marks;
|
||||
};
|
||||
|
||||
std::map<content_line_t, bookmark_metadata> &get_user_bookmark_metadata(void) {
|
||||
std::map<content_line_t, bookmark_metadata> &get_user_bookmark_metadata() {
|
||||
return this->lss_user_mark_metadata;
|
||||
};
|
||||
|
||||
@ -382,11 +399,11 @@ public:
|
||||
|
||||
logline *find_line(content_line_t line)
|
||||
{
|
||||
logline *retval = NULL;
|
||||
logline *retval = nullptr;
|
||||
std::shared_ptr<logfile> lf = this->find(line);
|
||||
|
||||
if (lf != NULL) {
|
||||
logfile::iterator ll_iter = lf->begin() + line;
|
||||
if (lf != nullptr) {
|
||||
auto ll_iter = lf->begin() + line;
|
||||
|
||||
retval = &(*ll_iter);
|
||||
}
|
||||
@ -437,7 +454,7 @@ public:
|
||||
lf->set_logline_observer(&this->ld_filter_state);
|
||||
};
|
||||
|
||||
void clear(void)
|
||||
void clear()
|
||||
{
|
||||
this->ld_filter_state.lfo_filter_state.clear();
|
||||
};
|
||||
@ -446,7 +463,7 @@ public:
|
||||
this->ld_enabled = enabled;
|
||||
}
|
||||
|
||||
void set_file(std::shared_ptr<logfile> lf) {
|
||||
void set_file(const std::shared_ptr<logfile> &lf) {
|
||||
this->ld_filter_state.lfo_filter_state.tfs_logfile = lf;
|
||||
lf->set_logline_observer(&this->ld_filter_state);
|
||||
};
|
||||
@ -495,7 +512,7 @@ public:
|
||||
};
|
||||
|
||||
content_line_t get_file_base_content_line(iterator iter) {
|
||||
int index = std::distance(this->begin(), iter);
|
||||
ssize_t index = std::distance(this->begin(), iter);
|
||||
|
||||
return content_line_t(index * MAX_LINES_PER_FILE);
|
||||
};
|
||||
@ -517,8 +534,8 @@ public:
|
||||
}
|
||||
|
||||
this->lss_index_delegate->index_start(*this);
|
||||
for (size_t index = 0; index < this->lss_filtered_index.size(); index++) {
|
||||
content_line_t cl = (content_line_t) this->lss_index[this->lss_filtered_index[index]];
|
||||
for (unsigned int index : this->lss_filtered_index) {
|
||||
content_line_t cl = (content_line_t) this->lss_index[index];
|
||||
uint64_t line_number;
|
||||
logfile_data *ld = this->find_data(cl, line_number);
|
||||
std::shared_ptr<logfile> lf = ld->get_file();
|
||||
@ -528,6 +545,77 @@ public:
|
||||
this->lss_index_delegate->index_complete(*this);
|
||||
};
|
||||
|
||||
class meta_grepper
|
||||
: public grep_proc_source<vis_line_t>,
|
||||
public grep_proc_sink<vis_line_t> {
|
||||
public:
|
||||
meta_grepper(logfile_sub_source &source)
|
||||
: lmg_source(source) {
|
||||
};
|
||||
|
||||
bool grep_value_for_line(vis_line_t line, std::string &value_out) override {
|
||||
content_line_t cl = this->lmg_source.at(vis_line_t(line));
|
||||
std::map<content_line_t, bookmark_metadata> &user_mark_meta =
|
||||
lmg_source.get_user_bookmark_metadata();
|
||||
auto meta_iter = user_mark_meta.find(cl);
|
||||
|
||||
if (meta_iter == user_mark_meta.end()) {
|
||||
value_out.clear();
|
||||
} else {
|
||||
bookmark_metadata &bm = meta_iter->second;
|
||||
|
||||
value_out.append(bm.bm_comment);
|
||||
for (const auto &tag : bm.bm_tags) {
|
||||
value_out.append(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return !this->lmg_done;
|
||||
};
|
||||
|
||||
vis_line_t grep_initial_line(vis_line_t start, vis_line_t highest) override {
|
||||
vis_bookmarks &bm = this->lmg_source.tss_view->get_bookmarks();
|
||||
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_META];
|
||||
|
||||
if (bv.empty()) {
|
||||
return -1_vl;
|
||||
}
|
||||
return *bv.begin();
|
||||
};
|
||||
|
||||
void grep_next_line(vis_line_t &line) override {
|
||||
vis_bookmarks &bm = this->lmg_source.tss_view->get_bookmarks();
|
||||
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_META];
|
||||
|
||||
line = bv.next(vis_line_t(line));
|
||||
if (line == -1) {
|
||||
this->lmg_done = true;
|
||||
}
|
||||
};
|
||||
|
||||
void grep_begin(grep_proc<vis_line_t> &gp, vis_line_t start, vis_line_t stop) override {
|
||||
this->lmg_source.tss_view->grep_begin(gp, start, stop);
|
||||
};
|
||||
|
||||
void grep_end(grep_proc<vis_line_t> &gp) override {
|
||||
this->lmg_source.tss_view->grep_end(gp);
|
||||
};
|
||||
|
||||
void grep_match(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end) override {
|
||||
this->lmg_source.tss_view->grep_match(gp, line, start, end);
|
||||
};
|
||||
|
||||
logfile_sub_source &lmg_source;
|
||||
bool lmg_done{false};
|
||||
};
|
||||
|
||||
meta_grepper &get_meta_grepper() {
|
||||
return this->lss_meta_grepper;
|
||||
}
|
||||
|
||||
static const uint64_t MAX_CONTENT_LINES = (1ULL << 40) - 1;
|
||||
static const uint64_t MAX_LINES_PER_FILE = 256 * 1024 * 1024;
|
||||
static const uint64_t MAX_FILES = (
|
||||
@ -544,10 +632,10 @@ private:
|
||||
};
|
||||
|
||||
enum {
|
||||
F_SCRUB = (1L << B_SCRUB),
|
||||
F_TIME_OFFSET = (1L << B_TIME_OFFSET),
|
||||
F_FILENAME = (1L << B_FILENAME),
|
||||
F_BASENAME = (1L << B_BASENAME),
|
||||
F_SCRUB = (1UL << B_SCRUB),
|
||||
F_TIME_OFFSET = (1UL << B_TIME_OFFSET),
|
||||
F_FILENAME = (1UL << B_FILENAME),
|
||||
F_BASENAME = (1UL << B_BASENAME),
|
||||
|
||||
F_NAME_MASK = (F_FILENAME | F_BASENAME),
|
||||
};
|
||||
@ -646,7 +734,7 @@ private:
|
||||
* Functor for comparing the ld_file field of the logfile_data struct.
|
||||
*/
|
||||
struct logfile_data_eq {
|
||||
logfile_data_eq(std::shared_ptr<logfile> lf) : lde_file(lf) { };
|
||||
explicit logfile_data_eq(std::shared_ptr<logfile> lf) : lde_file(std::move(lf)) { };
|
||||
|
||||
bool operator()(const logfile_data *ld)
|
||||
{
|
||||
@ -656,12 +744,16 @@ private:
|
||||
std::shared_ptr<logfile> lde_file;
|
||||
};
|
||||
|
||||
void clear_line_size_cache(void) {
|
||||
void clear_line_size_cache() {
|
||||
memset(this->lss_line_size_cache, 0, sizeof(this->lss_line_size_cache));
|
||||
this->lss_line_size_cache[0].first = -1;
|
||||
};
|
||||
|
||||
bool check_extra_filters(const logline &ll) {
|
||||
if (this->lss_marked_only && !ll.is_marked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
ll.get_msg_level() >= this->lss_min_log_level &&
|
||||
!(ll < this->lss_min_log_time) &&
|
||||
@ -693,8 +785,10 @@ private:
|
||||
logline::level_t lss_min_log_level;
|
||||
struct timeval lss_min_log_time;
|
||||
struct timeval lss_max_log_time;
|
||||
bool lss_marked_only;
|
||||
index_delegate *lss_index_delegate;
|
||||
size_t lss_longest_line;
|
||||
meta_grepper lss_meta_grepper;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -133,6 +133,7 @@ int network_extension_functions(struct FuncDef **basic_funcs,
|
||||
"Get the IP address for the given hostname")
|
||||
.sql_function()
|
||||
.with_parameter({"hostname", "The DNS hostname to lookup."})
|
||||
.with_tags({"net"})
|
||||
.with_example({"SELECT gethostbyname('localhost')"})
|
||||
),
|
||||
|
||||
@ -141,6 +142,7 @@ int network_extension_functions(struct FuncDef **basic_funcs,
|
||||
"Get the IP address for the given hostname")
|
||||
.sql_function()
|
||||
.with_parameter({"hostname", "The DNS hostname to lookup."})
|
||||
.with_tags({"net"})
|
||||
.with_example({"SELECT gethostbyaddr('127.0.0.1')"})
|
||||
),
|
||||
|
||||
|
@ -51,6 +51,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
@ -343,10 +344,10 @@ public:
|
||||
class error : public std::exception {
|
||||
public:
|
||||
error(std::string msg, int offset = 0)
|
||||
: e_msg(msg), e_offset(offset) { };
|
||||
: e_msg(std::move(msg)), e_offset(offset) { };
|
||||
virtual ~error() { };
|
||||
|
||||
virtual const char *what() const throw() {
|
||||
virtual const char *what() const noexcept {
|
||||
return this->e_msg.c_str();
|
||||
};
|
||||
|
||||
|
@ -99,27 +99,23 @@ void rl_change(void *dummy, readline_curses *rc)
|
||||
}
|
||||
}
|
||||
else {
|
||||
readline_context::command_t &cmd = iter->second;
|
||||
readline_context::command_t &cmd = *iter->second;
|
||||
const help_text &ht = cmd.c_help;
|
||||
|
||||
if (ht.ht_name) {
|
||||
textview_curses &dtc = lnav_data.ld_doc_view;
|
||||
textview_curses &etc = lnav_data.ld_example_view;
|
||||
vector<attr_line_t> lines;
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
attr_line_t al;
|
||||
|
||||
dtc.get_dimensions(height, width);
|
||||
format_help_text_for_term(ht, min(70UL, width), al);
|
||||
al.split_lines(lines);
|
||||
lnav_data.ld_doc_source.replace_with(al);
|
||||
|
||||
al.clear();
|
||||
lines.clear();
|
||||
etc.get_dimensions(height, width);
|
||||
format_example_text_for_term(ht, width, al);
|
||||
al.split_lines(lines);
|
||||
lnav_data.ld_example_source.replace_with(al);
|
||||
}
|
||||
|
||||
@ -243,14 +239,15 @@ static void rl_search_internal(void *dummy, readline_curses *rc, bool complete =
|
||||
x -= 1;
|
||||
}
|
||||
|
||||
auto iter = rfind_string_attr_if(sa, x, [](auto sa) {
|
||||
return (sa.sa_type == &SQL_FUNCTION_ATTR ||
|
||||
sa.sa_type == &SQL_KEYWORD_ATTR);
|
||||
});
|
||||
vector<string> kw;
|
||||
auto iter = rfind_string_attr_if(sa, x, [&al, &name, &kw](auto sa) {
|
||||
if (sa.sa_type != &SQL_FUNCTION_ATTR &&
|
||||
sa.sa_type != &SQL_KEYWORD_ATTR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iter != sa.end()) {
|
||||
const line_range &lr = iter->sa_range;
|
||||
const string &str = al.get_string();
|
||||
const line_range &lr = sa.sa_range;
|
||||
int lpc;
|
||||
|
||||
for (lpc = lr.lr_start; lpc < lr.lr_end; lpc++) {
|
||||
@ -259,32 +256,58 @@ static void rl_search_internal(void *dummy, readline_curses *rc, bool complete =
|
||||
}
|
||||
}
|
||||
|
||||
name = str.substr(lr.lr_start, lpc - lr.lr_start);
|
||||
string tmp_name = str.substr(lr.lr_start, lpc - lr.lr_start);
|
||||
if (sa.sa_type == &SQL_KEYWORD_ATTR) {
|
||||
tmp_name = toupper(tmp_name);
|
||||
}
|
||||
bool retval = sqlite_function_help.count(tmp_name) > 0;
|
||||
|
||||
const auto &func_iter = sqlite_function_help.find(tolower(name));
|
||||
if (retval) {
|
||||
kw.push_back(tmp_name);
|
||||
name = tmp_name;
|
||||
}
|
||||
return retval;
|
||||
});
|
||||
|
||||
if (func_iter != sqlite_function_help.end()) {
|
||||
if (iter != sa.end()) {
|
||||
auto func_pair = sqlite_function_help.equal_range(name);
|
||||
size_t help_count = distance(func_pair.first, func_pair.second);
|
||||
textview_curses &dtc = lnav_data.ld_doc_view;
|
||||
textview_curses &etc = lnav_data.ld_example_view;
|
||||
const help_text &ht = *func_iter->second;
|
||||
vector<attr_line_t> lines;
|
||||
unsigned long width;
|
||||
vis_line_t height;
|
||||
attr_line_t al;
|
||||
unsigned long doc_width, ex_width;
|
||||
vis_line_t doc_height, ex_height;
|
||||
attr_line_t doc_al, ex_al;
|
||||
|
||||
dtc.get_dimensions(height, width);
|
||||
format_help_text_for_term(ht, min(70UL, width), al);
|
||||
al.split_lines(lines);
|
||||
lnav_data.ld_doc_source.replace_with(al);
|
||||
dtc.get_dimensions(doc_height, doc_width);
|
||||
etc.get_dimensions(ex_height, ex_width);
|
||||
if (help_count > 1 && name != func_pair.first->second->ht_name) {
|
||||
while (find(kw.begin(), kw.end(),
|
||||
func_pair.first->second->ht_name) == kw.end()) {
|
||||
++func_pair.first;
|
||||
}
|
||||
func_pair.second = next(func_pair.first);
|
||||
help_count = 1;
|
||||
}
|
||||
for (auto func_iter = func_pair.first;
|
||||
func_iter != func_pair.second;
|
||||
++func_iter) {
|
||||
const help_text &ht = *func_iter->second;
|
||||
|
||||
format_help_text_for_term(ht, min(70UL, doc_width), doc_al,
|
||||
help_count > 1);
|
||||
if (help_count == 1) {
|
||||
format_example_text_for_term(ht, ex_width, ex_al);
|
||||
}
|
||||
}
|
||||
|
||||
if (!doc_al.empty()) {
|
||||
lnav_data.ld_doc_source.replace_with(doc_al);
|
||||
dtc.reload_data();
|
||||
|
||||
al.clear();
|
||||
lines.clear();
|
||||
etc.get_dimensions(height, width);
|
||||
format_example_text_for_term(ht, width, al);
|
||||
al.split_lines(lines);
|
||||
lnav_data.ld_example_source.replace_with(al);
|
||||
if (!ex_al.empty()) {
|
||||
lnav_data.ld_example_source.replace_with(ex_al);
|
||||
etc.reload_data();
|
||||
}
|
||||
|
||||
has_doc = true;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ class readline_context {
|
||||
public:
|
||||
typedef std::string (*command_func_t)(exec_context &ec,
|
||||
std::string cmdline, std::vector<std::string> &args);
|
||||
typedef struct {
|
||||
typedef struct _command_t {
|
||||
const char *c_name;
|
||||
command_func_t c_func;
|
||||
|
||||
@ -82,7 +82,7 @@ public:
|
||||
this->c_func = func;
|
||||
}
|
||||
} command_t;
|
||||
typedef std::map<std::string, command_t> command_map_t;
|
||||
typedef std::map<std::string, command_t *> command_map_t;
|
||||
|
||||
readline_context(const std::string &name,
|
||||
command_map_t *commands = NULL,
|
||||
@ -101,7 +101,7 @@ public:
|
||||
std::string cmd = iter->first;
|
||||
|
||||
this->rc_possibilities["__command"].insert(cmd);
|
||||
iter->second.c_func(INIT_EXEC_CONTEXT, cmd, this->rc_prototypes[cmd]);
|
||||
iter->second->c_func(INIT_EXEC_CONTEXT, cmd, this->rc_prototypes[cmd]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,14 +354,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<template<typename ...> class Container>
|
||||
void add_possibility(int context,
|
||||
const std::string &type,
|
||||
const std::vector<std::string> &values)
|
||||
const Container<std::string> &values)
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator iter = values.begin();
|
||||
iter != values.end();
|
||||
++iter) {
|
||||
this->add_possibility(context, type, *iter);
|
||||
for (const auto &str : values) {
|
||||
this->add_possibility(context, type, str);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -329,10 +329,10 @@ static void readline_regex_highlighter_int(attr_line_t &al, int x, int skip)
|
||||
break;
|
||||
default:
|
||||
if (isdigit(line[lpc])) {
|
||||
al.get_attrs().push_back(string_attr(
|
||||
al.get_attrs().emplace_back(
|
||||
line_range(lpc - 1, lpc + 1),
|
||||
&view_curses::VC_STYLE,
|
||||
special_char));
|
||||
special_char);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -354,6 +354,7 @@ void readline_command_highlighter(attr_line_t &al, int x)
|
||||
static const pcrepp RE_PREFIXES(
|
||||
R"(^:(filter-in|filter-out|delete-filter|enable-filter|disable-filter|highlight|clear-highlight|create-search-table\s+[^\s]+\s+))");
|
||||
static const pcrepp SH_PREFIXES("^:(eval|open|append-to|write-to|write-csv-to|write-json-to)");
|
||||
static const pcrepp IDENT_PREFIXES("^:(tag|untag|delete-tags)");
|
||||
|
||||
view_colors &vc = view_colors::singleton();
|
||||
int keyword_attrs = (
|
||||
@ -365,6 +366,7 @@ void readline_command_highlighter(attr_line_t &al, int x)
|
||||
size_t ws_index;
|
||||
|
||||
ws_index = line.find(' ');
|
||||
string command = line.substr(0, ws_index);
|
||||
if (ws_index != string::npos) {
|
||||
al.get_attrs().push_back(string_attr(
|
||||
line_range(1, ws_index),
|
||||
@ -378,6 +380,32 @@ void readline_command_highlighter(attr_line_t &al, int x)
|
||||
if (SH_PREFIXES.match(pc, pi)) {
|
||||
readline_shlex_highlighter(al, x);
|
||||
}
|
||||
pi.reset(line);
|
||||
if (IDENT_PREFIXES.match(pc, pi)) {
|
||||
size_t start = ws_index, last;
|
||||
|
||||
do {
|
||||
for (; start < line.length() && isspace(line[start]); start++);
|
||||
for (last = start; last < line.length() && !isspace(line[last]); last++);
|
||||
struct line_range lr{(int) start, (int) last};
|
||||
|
||||
if (lr.length() > 0 && !lr.contains(x) && !lr.contains(x - 1)) {
|
||||
string value(lr.substr(line), lr.sublen(line));
|
||||
|
||||
if ((command == ":tag" ||
|
||||
command == ":untag" ||
|
||||
command == ":delete-tags") &&
|
||||
!startswith(value, "#")) {
|
||||
value = "#" + value;
|
||||
}
|
||||
al.get_attrs().emplace_back(lr,
|
||||
&view_curses::VC_STYLE,
|
||||
vc.attrs_for_ident(value));
|
||||
}
|
||||
|
||||
start = last;
|
||||
} while (start < line.length());
|
||||
}
|
||||
}
|
||||
|
||||
static string sql_keyword_re(void)
|
||||
|
@ -48,7 +48,7 @@ static int handle_collation_list(void *ptr,
|
||||
char **colvalues,
|
||||
char **colnames)
|
||||
{
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
if (lnav_data.ld_rl_view != nullptr) {
|
||||
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[1]);
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ static int handle_db_list(void *ptr,
|
||||
char **colvalues,
|
||||
char **colnames)
|
||||
{
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
if (lnav_data.ld_rl_view != nullptr) {
|
||||
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[1]);
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ static int handle_table_list(void *ptr,
|
||||
char **colvalues,
|
||||
char **colnames)
|
||||
{
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
if (lnav_data.ld_rl_view != nullptr) {
|
||||
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[0]);
|
||||
|
||||
lnav_data.ld_table_ddl[colvalues[0]] = colvalues[1];
|
||||
@ -86,7 +86,7 @@ static int handle_table_info(void *ptr,
|
||||
char **colvalues,
|
||||
char **colnames)
|
||||
{
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
if (lnav_data.ld_rl_view != nullptr) {
|
||||
auto_mem<char, sqlite3_free> quoted_name;
|
||||
|
||||
quoted_name = sql_quote_ident(colvalues[1]);
|
||||
@ -94,7 +94,7 @@ static int handle_table_info(void *ptr,
|
||||
string(quoted_name));
|
||||
}
|
||||
if (strcmp(colvalues[5], "1") == 0) {
|
||||
lnav_data.ld_db_key_names.push_back(colvalues[1]);
|
||||
lnav_data.ld_db_key_names.emplace_back(colvalues[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -104,8 +104,8 @@ static int handle_foreign_key_list(void *ptr,
|
||||
char **colvalues,
|
||||
char **colnames)
|
||||
{
|
||||
lnav_data.ld_db_key_names.push_back(colvalues[3]);
|
||||
lnav_data.ld_db_key_names.push_back(colvalues[4]);
|
||||
lnav_data.ld_db_key_names.emplace_back(colvalues[3]);
|
||||
lnav_data.ld_db_key_names.emplace_back(colvalues[4]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -189,14 +189,14 @@ void add_view_text_possibilities(int context, const string &type, textview_curse
|
||||
auto_mem<FILE> pfile(pclose);
|
||||
|
||||
pfile = open_clipboard(CT_FIND, CO_READ);
|
||||
if (pfile.in() != NULL) {
|
||||
if (pfile.in() != nullptr) {
|
||||
char buffer[64];
|
||||
|
||||
if (fgets(buffer, sizeof(buffer), pfile) != NULL) {
|
||||
if (fgets(buffer, sizeof(buffer), pfile) != nullptr) {
|
||||
char *nl;
|
||||
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
if ((nl = strchr(buffer, '\n')) != NULL) {
|
||||
if ((nl = strchr(buffer, '\n')) != nullptr) {
|
||||
*nl = '\0';
|
||||
}
|
||||
rlc->add_possibility(context, type, std::string(buffer));
|
||||
@ -213,6 +213,8 @@ void add_view_text_possibilities(int context, const string &type, textview_curse
|
||||
|
||||
add_text_possibilities(context, type, line);
|
||||
}
|
||||
|
||||
rlc->add_possibility(context, type, bookmark_metadata::KNOWN_TAGS);
|
||||
}
|
||||
|
||||
void add_env_possibilities(int context)
|
||||
@ -220,19 +222,19 @@ void add_env_possibilities(int context)
|
||||
extern char **environ;
|
||||
readline_curses *rlc = lnav_data.ld_rl_view;
|
||||
|
||||
for (char **var = environ; *var != NULL; var++) {
|
||||
for (char **var = environ; *var != nullptr; var++) {
|
||||
rlc->add_possibility(context, "*", "$" + string(*var, strchr(*var, '=')));
|
||||
}
|
||||
|
||||
exec_context &ec = lnav_data.ld_exec_context;
|
||||
|
||||
if (!ec.ec_local_vars.empty()) {
|
||||
for (const auto iter : ec.ec_local_vars.top()) {
|
||||
for (const auto &iter : ec.ec_local_vars.top()) {
|
||||
rlc->add_possibility(context, "*", "$" + iter.first);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto iter : ec.ec_global_vars) {
|
||||
for (const auto &iter : ec.ec_global_vars) {
|
||||
rlc->add_possibility(context, "*", "$" + iter.first);
|
||||
}
|
||||
}
|
||||
@ -246,9 +248,7 @@ void add_filter_possibilities(textview_curses *tc)
|
||||
rc->clear_possibilities(LNM_COMMAND, "all-filters");
|
||||
rc->clear_possibilities(LNM_COMMAND, "disabled-filter");
|
||||
rc->clear_possibilities(LNM_COMMAND, "enabled-filter");
|
||||
for (auto iter = fs.begin(); iter != fs.end(); ++iter) {
|
||||
shared_ptr<text_filter> tf = *iter;
|
||||
|
||||
for (const auto &tf : fs) {
|
||||
rc->add_possibility(LNM_COMMAND, "all-filters", tf->get_id());
|
||||
if (tf->is_enabled()) {
|
||||
rc->add_possibility(LNM_COMMAND, "enabled-filter", tf->get_id());
|
||||
@ -264,7 +264,7 @@ void add_mark_possibilities()
|
||||
readline_curses *rc = lnav_data.ld_rl_view;
|
||||
|
||||
rc->clear_possibilities(LNM_COMMAND, "mark-type");
|
||||
for (bookmark_type_t::type_iterator iter = bookmark_type_t::type_begin();
|
||||
for (auto iter = bookmark_type_t::type_begin();
|
||||
iter != bookmark_type_t::type_end();
|
||||
++iter) {
|
||||
bookmark_type_t *bt = (*iter);
|
||||
@ -288,3 +288,25 @@ void add_config_possibilities()
|
||||
}
|
||||
rc->add_possibility(LNM_COMMAND, "config-option", config_options);
|
||||
}
|
||||
|
||||
void add_tag_possibilities()
|
||||
{
|
||||
readline_curses *rc = lnav_data.ld_rl_view;
|
||||
|
||||
rc->clear_possibilities(LNM_COMMAND, "tag");
|
||||
rc->clear_possibilities(LNM_COMMAND, "line-tags");
|
||||
rc->add_possibility(LNM_COMMAND, "tag", bookmark_metadata::KNOWN_TAGS);
|
||||
if (lnav_data.ld_view_stack.back() == &lnav_data.ld_views[LNV_LOG]) {
|
||||
logfile_sub_source &lss = lnav_data.ld_log_source;
|
||||
content_line_t cl = lss.at(lnav_data.ld_views[LNV_LOG].get_top());
|
||||
const map<content_line_t, bookmark_metadata> &user_meta =
|
||||
lss.get_user_bookmark_metadata();
|
||||
auto meta_iter = user_meta.find(cl);
|
||||
|
||||
if (meta_iter != user_meta.end()) {
|
||||
rc->add_possibility(LNM_COMMAND,
|
||||
"line-tags",
|
||||
meta_iter->second.bm_tags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ void add_env_possibilities(int context);
|
||||
void add_filter_possibilities(textview_curses *tc);
|
||||
void add_mark_possibilities();
|
||||
void add_config_possibilities();
|
||||
void add_tag_possibilities();
|
||||
|
||||
extern struct sqlite_metadata_callbacks lnav_sql_meta_callbacks;
|
||||
|
||||
|
@ -36,22 +36,22 @@
|
||||
#include "grep_proc.hh"
|
||||
#include "sequence_matcher.hh"
|
||||
|
||||
class sequence_sink : public grep_proc_sink {
|
||||
class sequence_sink : public grep_proc_sink<vis_line_t> {
|
||||
public:
|
||||
sequence_sink(sequence_matcher &sm, bookmark_vector<vis_line_t> &bv)
|
||||
: ss_matcher(sm),
|
||||
ss_bookmarks(bv) {};
|
||||
|
||||
void grep_match(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
void grep_match(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end)
|
||||
{
|
||||
this->ss_line_values.clear();
|
||||
};
|
||||
|
||||
void grep_capture(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
void grep_capture(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end,
|
||||
char *capture)
|
||||
@ -64,17 +64,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void grep_match_end(grep_proc &gp, grep_line_t line)
|
||||
void grep_match_end(grep_proc<vis_line_t> &gp, vis_line_t line)
|
||||
{
|
||||
sequence_matcher::id_t line_id;
|
||||
|
||||
this->ss_matcher.identity(this->ss_line_values, line_id);
|
||||
|
||||
std::vector<grep_line_t> &line_state = this->ss_state[line_id];
|
||||
std::vector<vis_line_t> &line_state = this->ss_state[line_id];
|
||||
if (this->ss_matcher.match(this->ss_line_values,
|
||||
line_state,
|
||||
line)) {
|
||||
std::vector<grep_line_t>::iterator iter;
|
||||
std::vector<vis_line_t>::iterator iter;
|
||||
|
||||
for (iter = line_state.begin();
|
||||
iter != line_state.end();
|
||||
@ -89,6 +89,6 @@ private:
|
||||
sequence_matcher & ss_matcher;
|
||||
bookmark_vector<vis_line_t> &ss_bookmarks;
|
||||
std::vector<std::string> ss_line_values;
|
||||
std::map<sequence_matcher::id_t, std::vector<grep_line_t> > ss_state;
|
||||
std::map<sequence_matcher::id_t, std::vector<vis_line_t> > ss_state;
|
||||
};
|
||||
#endif
|
||||
|
@ -40,6 +40,8 @@
|
||||
#include "spookyhash/SpookyV2.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <yajl/api/yajl_tree.h>
|
||||
|
||||
#include "yajlpp.hh"
|
||||
#include "lnav.hh"
|
||||
@ -62,6 +64,8 @@ static const char *BOOKMARK_TABLE_DEF =
|
||||
" session_time integer,\n"
|
||||
" part_name text,\n"
|
||||
" access_time datetime DEFAULT CURRENT_TIMESTAMP,\n"
|
||||
" comment text DEFAULT '',\n"
|
||||
" tags text DEFAULT '',\n"
|
||||
"\n"
|
||||
" PRIMARY KEY (log_time, log_format, log_hash, session_time)\n"
|
||||
");\n"
|
||||
@ -82,11 +86,14 @@ static const char *BOOKMARK_LRU_STMT =
|
||||
" (SELECT access_time FROM bookmarks "
|
||||
" ORDER BY access_time DESC LIMIT 1 OFFSET 50000)";
|
||||
|
||||
static const char *UPGRADE_STMTS[] = {
|
||||
R"(ALTER TABLE bookmarks ADD COLUMN comment text DEFAULT '';)",
|
||||
R"(ALTER TABLE bookmarks ADD COLUMN tags text DEFAULT '';)",
|
||||
};
|
||||
|
||||
static const size_t MAX_SESSIONS = 8;
|
||||
static const size_t MAX_SESSION_FILE_COUNT = 256;
|
||||
|
||||
typedef std::vector<std::pair<int, string> > timestamped_list_t;
|
||||
|
||||
static std::vector<content_line_t> marked_session_lines;
|
||||
static std::vector<content_line_t> offset_session_lines;
|
||||
|
||||
@ -154,9 +161,12 @@ static bool bind_line(sqlite3 *db,
|
||||
|
||||
struct session_file_info {
|
||||
session_file_info(int timestamp,
|
||||
const string &id,
|
||||
const string &path)
|
||||
: sfi_timestamp(timestamp), sfi_id(id), sfi_path(path) {};
|
||||
string id,
|
||||
string path)
|
||||
: sfi_timestamp(timestamp),
|
||||
sfi_id(std::move(id)),
|
||||
sfi_path(std::move(path)) {
|
||||
};
|
||||
|
||||
bool operator<(const session_file_info &other) const
|
||||
{
|
||||
@ -209,8 +219,7 @@ static void cleanup_session_data(void)
|
||||
hash_id,
|
||||
×tamp) == 2) {
|
||||
session_count[hash_id] += 1;
|
||||
session_info_list.push_back(session_file_info(
|
||||
timestamp, hash_id, path));
|
||||
session_info_list.emplace_back(timestamp, hash_id, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,7 +275,7 @@ void init_session(void)
|
||||
|
||||
context.Init(0, 0);
|
||||
hash_updater updater(&context);
|
||||
for (map<string, logfile_open_options>::iterator iter = lnav_data.ld_file_names.begin();
|
||||
for (auto iter = lnav_data.ld_file_names.begin();
|
||||
iter != lnav_data.ld_file_names.end();
|
||||
++iter) {
|
||||
updater(iter->first);
|
||||
@ -307,7 +316,7 @@ void scan_sessions(void)
|
||||
"view-info-%s.*.json",
|
||||
lnav_data.ld_session_id.c_str());
|
||||
view_info_pattern = dotlnav_path(view_info_pattern_base);
|
||||
if (glob(view_info_pattern.c_str(), 0, NULL,
|
||||
if (glob(view_info_pattern.c_str(), 0, nullptr,
|
||||
view_info_list.inout()) == 0) {
|
||||
for (size_t lpc = 0; lpc < view_info_list->gl_pathc; lpc++) {
|
||||
const char *path = view_info_list->gl_pathv[lpc];
|
||||
@ -327,7 +336,7 @@ void scan_sessions(void)
|
||||
|
||||
ptp.first = (ppid == getppid()) ? 1 : 0;
|
||||
ptp.second = timestamp;
|
||||
session_file_names.push_back(make_pair(ptp, path));
|
||||
session_file_names.emplace_back(ptp, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -366,6 +375,8 @@ static void load_time_bookmarks(void)
|
||||
string db_path = dotlnav_path(LOG_METADATA_NAME);
|
||||
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
|
||||
logfile_sub_source::iterator file_iter;
|
||||
bool reload_needed = false;
|
||||
auto_mem<char, sqlite3_free> errmsg;
|
||||
|
||||
log_info("loading bookmark db: %s", db_path.c_str());
|
||||
|
||||
@ -373,15 +384,22 @@ static void load_time_bookmarks(void)
|
||||
return;
|
||||
}
|
||||
|
||||
for (const char *stmt : UPGRADE_STMTS) {
|
||||
if (sqlite3_exec(db.in(), stmt, nullptr, nullptr, errmsg.out()) != SQLITE_OK) {
|
||||
log_error("unable to upgrade bookmark table -- %s\n", errmsg.in());
|
||||
}
|
||||
}
|
||||
|
||||
if (sqlite3_prepare_v2(db.in(),
|
||||
"SELECT *,session_time=? as same_session FROM bookmarks WHERE "
|
||||
"SELECT log_time, log_format, log_hash, session_time, part_name, access_time, comment,"
|
||||
" tags, session_time=? as same_session FROM bookmarks WHERE "
|
||||
" log_time between ? and ? and log_format = ? "
|
||||
" ORDER BY same_session DESC, session_time DESC",
|
||||
-1,
|
||||
stmt.out(),
|
||||
NULL) != SQLITE_OK) {
|
||||
nullptr) != SQLITE_OK) {
|
||||
log_error(
|
||||
"could not prepare bookmark select statemnt -- %s\n",
|
||||
"could not prepare bookmark select statement -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
@ -398,7 +416,7 @@ static void load_time_bookmarks(void)
|
||||
|
||||
base_content_line = lss.get_file_base_content_line(file_iter);
|
||||
|
||||
logfile::iterator line_iter = lf->begin();
|
||||
auto line_iter = lf->begin();
|
||||
|
||||
sql_strftime(low_timestamp, sizeof(low_timestamp),
|
||||
lf->original_line_time(line_iter), 'T');
|
||||
@ -458,6 +476,8 @@ static void load_time_bookmarks(void)
|
||||
const char *log_time = (const char *)sqlite3_column_text(stmt.in(), 0);
|
||||
const char *log_hash = (const char *)sqlite3_column_text(stmt.in(), 2);
|
||||
const char *part_name = (const char *)sqlite3_column_text(stmt.in(), 4);
|
||||
const char *comment = (const char *)sqlite3_column_text(stmt.in(), 6);
|
||||
const char *tags = (const char *)sqlite3_column_text(stmt.in(), 7);
|
||||
int64_t mark_time = sqlite3_column_int64(stmt.in(), 3);
|
||||
struct timeval log_tv;
|
||||
struct exttm log_tm;
|
||||
@ -500,18 +520,47 @@ static void load_time_bookmarks(void)
|
||||
if (line_hash == log_hash) {
|
||||
content_line_t line_cl = content_line_t(
|
||||
base_content_line + std::distance(lf->begin(), line_iter));
|
||||
bool meta = false;
|
||||
|
||||
if (part_name != NULL && part_name[0] != '\0') {
|
||||
lss.set_user_mark(&textview_curses::BM_PARTITION,
|
||||
line_cl);
|
||||
lss.set_user_mark(&textview_curses::BM_META, line_cl);
|
||||
bm_meta[line_cl].bm_name = part_name;
|
||||
meta = true;
|
||||
}
|
||||
else {
|
||||
if (comment != NULL && comment[0] != '\0') {
|
||||
lss.set_user_mark(&textview_curses::BM_META,
|
||||
line_cl);
|
||||
bm_meta[line_cl].bm_comment = comment;
|
||||
meta = true;
|
||||
}
|
||||
if (tags != nullptr && tags[0] != '\0') {
|
||||
auto_mem<yajl_val_s> tag_list(yajl_tree_free);
|
||||
char error_buffer[1024];
|
||||
|
||||
tag_list = yajl_tree_parse(tags, error_buffer, sizeof(error_buffer));
|
||||
if (!YAJL_IS_ARRAY(tag_list.in())) {
|
||||
log_error("invalid tags column: %s", tags);
|
||||
} else {
|
||||
lss.set_user_mark(&textview_curses::BM_META,
|
||||
line_cl);
|
||||
for (int lpc = 0; lpc < tag_list.in()->u.array.len; lpc++) {
|
||||
yajl_val elem = tag_list.in()->u.array.values[lpc];
|
||||
|
||||
if (!YAJL_IS_STRING(elem)) {
|
||||
continue;
|
||||
}
|
||||
bookmark_metadata::KNOWN_TAGS.insert(elem->u.string);
|
||||
bm_meta[line_cl].add_tag(elem->u.string);
|
||||
}
|
||||
}
|
||||
meta = true;
|
||||
}
|
||||
if (!meta) {
|
||||
marked_session_lines.push_back(line_cl);
|
||||
lss.set_user_mark(&textview_curses::BM_USER,
|
||||
line_cl);
|
||||
|
||||
}
|
||||
reload_needed = true;
|
||||
}
|
||||
|
||||
++line_iter;
|
||||
@ -543,9 +592,9 @@ static void load_time_bookmarks(void)
|
||||
" ORDER BY same_session DESC, session_time DESC",
|
||||
-1,
|
||||
stmt.out(),
|
||||
NULL) != SQLITE_OK) {
|
||||
nullptr) != SQLITE_OK) {
|
||||
log_error(
|
||||
"could not prepare time_offset select statemnt -- %s\n",
|
||||
"could not prepare time_offset select statement -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
@ -557,8 +606,9 @@ static void load_time_bookmarks(void)
|
||||
shared_ptr<logfile> lf = (*file_iter)->get_file();
|
||||
content_line_t base_content_line;
|
||||
|
||||
if (lf == NULL)
|
||||
if (lf == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lss.find(lf->get_filename().c_str(), base_content_line);
|
||||
|
||||
@ -665,6 +715,8 @@ static void load_time_bookmarks(void)
|
||||
offset.tv_sec = sqlite3_column_int64(stmt.in(), 4);
|
||||
offset.tv_usec = sqlite3_column_int64(stmt.in(), 5);
|
||||
lf->adjust_content_time(file_line, offset);
|
||||
|
||||
reload_needed = true;
|
||||
}
|
||||
|
||||
++line_iter;
|
||||
@ -689,6 +741,10 @@ static void load_time_bookmarks(void)
|
||||
|
||||
sqlite3_reset(stmt.in());
|
||||
}
|
||||
|
||||
if (reload_needed) {
|
||||
lnav_data.ld_views[LNV_LOG].reload_data();
|
||||
}
|
||||
}
|
||||
|
||||
static int read_save_time(yajlpp_parse_context *ypc, long long value)
|
||||
@ -823,7 +879,7 @@ void load_session(void)
|
||||
string &view_info_name = sess_iter->second;
|
||||
|
||||
yajlpp_parse_context ypc(view_info_name, view_info_handlers);
|
||||
handle = yajl_alloc(&ypc.ypc_callbacks, NULL, &ypc);
|
||||
handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc);
|
||||
|
||||
load_time_bookmarks();
|
||||
|
||||
@ -860,13 +916,10 @@ static void save_user_bookmarks(
|
||||
|
||||
for (iter = user_marks.begin(); iter != user_marks.end(); ++iter) {
|
||||
std::map<content_line_t, bookmark_metadata>::iterator meta_iter;
|
||||
logfile::iterator line_iter;
|
||||
content_line_t cl = *iter;
|
||||
|
||||
meta_iter = bm_meta.find(cl);
|
||||
|
||||
marked_session_lines.push_back(cl);
|
||||
|
||||
if (!bind_line(db, stmt, cl, lnav_data.ld_session_time)) {
|
||||
continue;
|
||||
}
|
||||
@ -879,11 +932,52 @@ static void save_user_bookmarks(
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (meta_iter->second.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sqlite3_bind_text(stmt, 5,
|
||||
meta_iter->second.bm_name.c_str(),
|
||||
meta_iter->second.bm_name.length(),
|
||||
SQLITE_TRANSIENT) != SQLITE_OK) {
|
||||
log_error("could not bind log hash -- %s\n",
|
||||
log_error("could not bind part name -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
|
||||
bookmark_metadata &line_meta = meta_iter->second;
|
||||
if (sqlite3_bind_text(stmt, 6,
|
||||
meta_iter->second.bm_comment.c_str(),
|
||||
meta_iter->second.bm_comment.length(),
|
||||
SQLITE_TRANSIENT) != SQLITE_OK) {
|
||||
log_error("could not bind comment -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
|
||||
string tags;
|
||||
|
||||
if (!line_meta.bm_tags.empty()) {
|
||||
yajlpp_gen gen;
|
||||
|
||||
yajl_gen_config(gen, yajl_gen_beautify, false);
|
||||
|
||||
{
|
||||
yajlpp_array arr(gen);
|
||||
|
||||
for (const auto &str : line_meta.bm_tags) {
|
||||
arr.gen(str);
|
||||
}
|
||||
}
|
||||
|
||||
tags = gen.to_string_fragment().to_string();
|
||||
}
|
||||
|
||||
if (sqlite3_bind_text(stmt, 7,
|
||||
tags.c_str(),
|
||||
tags.length(),
|
||||
SQLITE_TRANSIENT) != SQLITE_OK) {
|
||||
log_error("could not bind tags -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
@ -896,6 +990,8 @@ static void save_user_bookmarks(
|
||||
return;
|
||||
}
|
||||
|
||||
marked_session_lines.push_back(cl);
|
||||
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
|
||||
@ -932,18 +1028,16 @@ static void save_time_bookmarks(void)
|
||||
" and session_time = ?",
|
||||
-1,
|
||||
stmt.out(),
|
||||
NULL) != SQLITE_OK) {
|
||||
nullptr) != SQLITE_OK) {
|
||||
log_error(
|
||||
"could not prepare bookmark delete statemnt -- %s\n",
|
||||
"could not prepare bookmark delete statement -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::vector<content_line_t>::iterator cl_iter = marked_session_lines.begin();
|
||||
cl_iter != marked_session_lines.end();
|
||||
++cl_iter) {
|
||||
for (auto &marked_session_line : marked_session_lines) {
|
||||
if (!bind_line(
|
||||
db.in(), stmt.in(), *cl_iter, lnav_data.ld_session_time)) {
|
||||
db.in(), stmt.in(), marked_session_line, lnav_data.ld_session_time)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -961,13 +1055,13 @@ static void save_time_bookmarks(void)
|
||||
|
||||
if (sqlite3_prepare_v2(db.in(),
|
||||
"REPLACE INTO bookmarks"
|
||||
" (log_time, log_format, log_hash, session_time, part_name)"
|
||||
" VALUES (?, ?, ?, ?, ?)",
|
||||
" (log_time, log_format, log_hash, session_time, part_name, comment, tags)"
|
||||
" VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
-1,
|
||||
stmt.out(),
|
||||
NULL) != SQLITE_OK) {
|
||||
nullptr) != SQLITE_OK) {
|
||||
log_error(
|
||||
"could not prepare bookmark replace statemnt -- %s\n",
|
||||
"could not prepare bookmark replace statement -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
@ -1011,7 +1105,7 @@ static void save_time_bookmarks(void)
|
||||
}
|
||||
|
||||
save_user_bookmarks(db.in(), stmt.in(), bm[&textview_curses::BM_USER]);
|
||||
save_user_bookmarks(db.in(), stmt.in(), bm[&textview_curses::BM_PARTITION]);
|
||||
save_user_bookmarks(db.in(), stmt.in(), bm[&textview_curses::BM_META]);
|
||||
|
||||
if (sqlite3_prepare_v2(db.in(),
|
||||
"DELETE FROM time_offset WHERE "
|
||||
@ -1021,16 +1115,14 @@ static void save_time_bookmarks(void)
|
||||
stmt.out(),
|
||||
NULL) != SQLITE_OK) {
|
||||
log_error(
|
||||
"could not prepare time_offset delete statemnt -- %s\n",
|
||||
"could not prepare time_offset delete statement -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::vector<content_line_t>::iterator cl_iter = offset_session_lines.begin();
|
||||
cl_iter != offset_session_lines.end();
|
||||
++cl_iter) {
|
||||
for (auto &offset_session_line : offset_session_lines) {
|
||||
if (!bind_line(
|
||||
db.in(), stmt.in(), *cl_iter, lnav_data.ld_session_time)) {
|
||||
db.in(), stmt.in(), offset_session_line, lnav_data.ld_session_time)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1054,7 +1146,7 @@ static void save_time_bookmarks(void)
|
||||
stmt.out(),
|
||||
NULL) != SQLITE_OK) {
|
||||
log_error(
|
||||
"could not prepare time_offset replace statemnt -- %s\n",
|
||||
"could not prepare time_offset replace statement -- %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
return;
|
||||
}
|
||||
@ -1101,15 +1193,13 @@ static void save_time_bookmarks(void)
|
||||
}
|
||||
}
|
||||
|
||||
for (logfile_sub_source::iterator file_iter = lss.begin();
|
||||
file_iter != lss.end();
|
||||
++file_iter) {
|
||||
for (auto &ls : lss) {
|
||||
logfile::iterator line_iter;
|
||||
|
||||
if ((*file_iter)->get_file() == NULL)
|
||||
if (ls->get_file() == NULL)
|
||||
continue;
|
||||
|
||||
shared_ptr<logfile> lf = (*file_iter)->get_file();
|
||||
shared_ptr<logfile> lf = ls->get_file();
|
||||
|
||||
if (!lf->is_time_adjusted())
|
||||
continue;
|
||||
@ -1234,10 +1324,8 @@ void save_session(void)
|
||||
{
|
||||
yajlpp_array file_list(handle);
|
||||
|
||||
for (map<string, logfile_open_options>::iterator iter = lnav_data.ld_file_names.begin();
|
||||
iter != lnav_data.ld_file_names.end();
|
||||
++iter) {
|
||||
file_list.gen(iter->first);
|
||||
for (auto &ld_file_name : lnav_data.ld_file_names) {
|
||||
file_list.gen(ld_file_name.first);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1358,18 +1446,18 @@ void save_session(void)
|
||||
}
|
||||
}
|
||||
|
||||
void reset_session(void)
|
||||
void reset_session()
|
||||
{
|
||||
textview_curses::highlight_map_t &hmap =
|
||||
lnav_data.ld_views[LNV_LOG].get_highlights();
|
||||
textview_curses::highlight_map_t::iterator hl_iter = hmap.begin();
|
||||
auto hl_iter = hmap.begin();
|
||||
|
||||
log_info("reset session: time=%d", lnav_data.ld_session_time);
|
||||
|
||||
save_session();
|
||||
scan_sessions();
|
||||
|
||||
lnav_data.ld_session_time = time(NULL);
|
||||
lnav_data.ld_session_time = time(nullptr);
|
||||
|
||||
while (hl_iter != hmap.end()) {
|
||||
if (hl_iter->first[0] == '$') {
|
||||
@ -1390,23 +1478,23 @@ void reset_session(void)
|
||||
lf->clear_time_offset();
|
||||
}
|
||||
|
||||
lnav_data.ld_log_source.set_marked_only(false);
|
||||
lnav_data.ld_log_source.clear_min_max_log_times();
|
||||
|
||||
lnav_data.ld_log_source.get_user_bookmark_metadata().clear();
|
||||
|
||||
for (int lpc = 0; lpc < LNV__MAX; lpc++) {
|
||||
textview_curses &tc = lnav_data.ld_views[lpc];
|
||||
for (auto &tc : lnav_data.ld_views) {
|
||||
text_sub_source *tss = tc.get_sub_source();
|
||||
|
||||
if (tss == NULL) {
|
||||
if (tss == nullptr) {
|
||||
continue;
|
||||
}
|
||||
tss->get_filters().clear_filters();
|
||||
tss->text_filters_changed();
|
||||
tss->text_clear_marks(&textview_curses::BM_USER);
|
||||
tc.get_bookmarks()[&textview_curses::BM_USER].clear();
|
||||
tss->text_clear_marks(&textview_curses::BM_PARTITION);
|
||||
tc.get_bookmarks()[&textview_curses::BM_PARTITION].clear();
|
||||
tss->text_clear_marks(&textview_curses::BM_META);
|
||||
tc.get_bookmarks()[&textview_curses::BM_META].clear();
|
||||
tc.reload_data();
|
||||
}
|
||||
|
||||
|
@ -227,12 +227,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
size_t list_overlay_count(const listview_curses &lv) {
|
||||
return 1;
|
||||
};
|
||||
|
||||
bool list_value_for_overlay(const listview_curses &lv,
|
||||
vis_line_t y,
|
||||
int y, int bottom,
|
||||
vis_line_t row,
|
||||
attr_line_t &value_out) {
|
||||
if (y != 0) {
|
||||
return false;
|
||||
|
@ -786,8 +786,6 @@ int guess_type_from_pcre(const string &pattern, const char **collator)
|
||||
vector<int> matches;
|
||||
int retval = SQLITE3_TEXT;
|
||||
|
||||
log_debug("guess pattern %s", pattern.c_str());
|
||||
|
||||
*collator = NULL;
|
||||
for (int lpc = 0; TYPE_TEST_VALUE[lpc].sqlite_type != SQLITE_NULL; lpc++) {
|
||||
pcre_context_static<30> pc;
|
||||
@ -799,7 +797,6 @@ int guess_type_from_pcre(const string &pattern, const char **collator)
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("match size %d", matches.size());
|
||||
if (matches.size() == 1) {
|
||||
retval = TYPE_TEST_VALUE[matches.front()].sqlite_type;
|
||||
*collator = TYPE_TEST_VALUE[matches.front()].collator;
|
||||
|
@ -53,7 +53,7 @@ sqlite_registration_func_t sqlite_registration_funcs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, help_text *> sqlite_function_help;
|
||||
multimap<std::string, help_text *> sqlite_function_help;
|
||||
|
||||
int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
{
|
||||
@ -80,13 +80,14 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
basic_funcs[i].eTextRep,
|
||||
(void *) &fd,
|
||||
basic_funcs[i].xFunc,
|
||||
0,
|
||||
0);
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (fd.fd_help.ht_context != HC_NONE) {
|
||||
help_text &ht = fd.fd_help;
|
||||
|
||||
sqlite_function_help[ht.ht_name] = &ht;
|
||||
sqlite_function_help.insert(make_pair(ht.ht_name, &ht));
|
||||
ht.index_tags();
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,6 +109,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
"Return the absolute value of the argument")
|
||||
.sql_function()
|
||||
.with_parameter({"x", "The number to convert"})
|
||||
.with_tags({"math"})
|
||||
.with_example({"SELECT abs(-1)"}),
|
||||
|
||||
help_text("changes",
|
||||
@ -119,6 +121,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.sql_function()
|
||||
.with_parameter(help_text("X", "The unicode code point values")
|
||||
.zero_or_more())
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT char(0x48, 0x49)"}),
|
||||
|
||||
help_text("coalesce",
|
||||
@ -154,6 +157,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.sql_function()
|
||||
.with_parameter({"haystack", "The string to search within"})
|
||||
.with_parameter({"needle", "The string to look for in the haystack"})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT instr('abc', 'b')"}),
|
||||
|
||||
help_text("last_insert_rowid",
|
||||
@ -164,6 +168,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
"Returns the number of characters (not bytes) in the given string prior to the first NUL character")
|
||||
.sql_function()
|
||||
.with_parameter({"str", "The string to determine the length of"})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT length('abc')"}),
|
||||
|
||||
help_text("like",
|
||||
@ -202,6 +207,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
"Returns a copy of the given string with all ASCII characters converted to lower case.")
|
||||
.sql_function()
|
||||
.with_parameter({"str", "The string to convert."})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT lower('AbC')"}),
|
||||
|
||||
help_text("ltrim",
|
||||
@ -210,6 +216,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"str", "The string to trim characters from the left side"})
|
||||
.with_parameter(help_text("chars", "The characters to trim. Defaults to spaces.")
|
||||
.optional())
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT ltrim(' abc')"})
|
||||
.with_example({"SELECT ltrim('aaaabbbc', 'ab')"}),
|
||||
|
||||
@ -219,6 +226,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter(help_text("X", "The numbers to find the maximum of. "
|
||||
"If only one argument is given, this function operates as an aggregate.")
|
||||
.one_or_more())
|
||||
.with_tags({"math"})
|
||||
.with_example({"SELECT max(2, 1, 3)"})
|
||||
.with_example({"SELECT max(status) FROM http_status_codes"}),
|
||||
|
||||
@ -228,6 +236,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter(help_text("X", "The numbers to find the minimum of. "
|
||||
"If only one argument is given, this function operates as an aggregate.")
|
||||
.one_or_more())
|
||||
.with_tags({"math"})
|
||||
.with_example({"SELECT min(2, 1, 3)"})
|
||||
.with_example({"SELECT min(status) FROM http_status_codes"}),
|
||||
|
||||
@ -245,6 +254,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.sql_function()
|
||||
.with_parameter({"format", "The format of the string to return."})
|
||||
.with_parameter(help_text("X", "The argument to substitute at a given position in the format."))
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT printf('Hello, %s!', 'World')"})
|
||||
.with_example({"SELECT printf('align: % 10s', 'small')"})
|
||||
.with_example({"SELECT printf('value: %05d', 11)"}),
|
||||
@ -271,6 +281,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"str", "The string to perform substitutions on."})
|
||||
.with_parameter({"old", "The string to be replaced."})
|
||||
.with_parameter({"replacement", "The string to replace any occurrences of the old string with."})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT replace('abc', 'x', 'z')"})
|
||||
.with_example({"SELECT replace('abc', 'a', 'z')"}),
|
||||
|
||||
@ -280,6 +291,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"num", "The value to round."})
|
||||
.with_parameter(help_text("digits", "The number of digits to the right of the decimal to round to.")
|
||||
.optional())
|
||||
.with_tags({"math"})
|
||||
.with_example({"SELECT round(123.456)"})
|
||||
.with_example({"SELECT round(123.456, 1)"})
|
||||
.with_example({"SELECT round(123.456, 5)"}),
|
||||
@ -290,6 +302,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"str", "The string to trim characters from the right side"})
|
||||
.with_parameter(help_text("chars", "The characters to trim. Defaults to spaces.")
|
||||
.optional())
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT ltrim('abc ')"})
|
||||
.with_example({"SELECT ltrim('abbbbcccc', 'bc')"}),
|
||||
|
||||
@ -323,6 +336,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
"If not given, then all characters through the end of the string are returned. "
|
||||
"If the value is negative, then the characters before the start are returned.")
|
||||
.optional())
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT substr('abc', 2)"})
|
||||
.with_example({"SELECT substr('abc', 2, 1)"})
|
||||
.with_example({"SELECT substr('abc', -1)"})
|
||||
@ -338,6 +352,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"str", "The string to trim characters from the left and right sides."})
|
||||
.with_parameter(help_text("chars", "The characters to trim. Defaults to spaces.")
|
||||
.optional())
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT trim(' abc ')"})
|
||||
.with_example({"SELECT trim('-+abc+-', '-+')"}),
|
||||
|
||||
@ -363,6 +378,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
"Returns a copy of the given string with all ASCII characters converted to upper case.")
|
||||
.sql_function()
|
||||
.with_parameter({"str", "The string to convert."})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT upper('aBc')"}),
|
||||
|
||||
help_text("zeroblob",
|
||||
@ -376,6 +392,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"timestring", "The string to convert to a date."})
|
||||
.with_parameter(help_text("modifier", "A transformation that is applied to the value to the left.")
|
||||
.zero_or_more())
|
||||
.with_tags({"datetime"})
|
||||
.with_example({"SELECT date('2017-01-02T03:04:05')"})
|
||||
.with_example({"SELECT date('2017-01-02T03:04:05', '+1 day')"})
|
||||
.with_example({"SELECT date(1491341842, 'unixepoch')"}),
|
||||
@ -386,6 +403,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"timestring", "The string to convert to a time."})
|
||||
.with_parameter(help_text("modifier", "A transformation that is applied to the value to the left.")
|
||||
.zero_or_more())
|
||||
.with_tags({"datetime"})
|
||||
.with_example({"SELECT time('2017-01-02T03:04:05')"})
|
||||
.with_example({"SELECT time('2017-01-02T03:04:05', '+1 minute')"})
|
||||
.with_example({"SELECT time(1491341842, 'unixepoch')"}),
|
||||
@ -396,6 +414,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"timestring", "The string to convert to a date with time."})
|
||||
.with_parameter(help_text("modifier", "A transformation that is applied to the value to the left.")
|
||||
.zero_or_more())
|
||||
.with_tags({"datetime"})
|
||||
.with_example({"SELECT datetime('2017-01-02T03:04:05')"})
|
||||
.with_example({"SELECT datetime('2017-01-02T03:04:05', '+1 minute')"})
|
||||
.with_example({"SELECT datetime(1491341842, 'unixepoch')"}),
|
||||
@ -406,6 +425,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"timestring", "The string to convert to a date with time."})
|
||||
.with_parameter(help_text("modifier", "A transformation that is applied to the value to the left.")
|
||||
.zero_or_more())
|
||||
.with_tags({"datetime"})
|
||||
.with_example({"SELECT julianday('2017-01-02T03:04:05')"})
|
||||
.with_example({"SELECT julianday('2017-01-02T03:04:05', '+1 minute')"})
|
||||
.with_example({"SELECT julianday(1491341842, 'unixepoch')"}),
|
||||
@ -417,6 +437,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"timestring", "The string to convert to a date with time."})
|
||||
.with_parameter(help_text("modifier", "A transformation that is applied to the value to the left.")
|
||||
.zero_or_more())
|
||||
.with_tags({"datetime"})
|
||||
.with_example({"SELECT strftime('%Y', '2017-01-02T03:04:05')"})
|
||||
.with_example({"SELECT strftime('The time is: %H%M%S', '2017-01-02T03:04:05', '+1 minute')"})
|
||||
.with_example({"SELECT strftime('Julian day: %J', 1491341842, 'unixepoch')"}),
|
||||
@ -425,6 +446,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
"Returns the average value of all non-NULL numbers within a group.")
|
||||
.sql_function()
|
||||
.with_parameter({"X", "The value to compute the average of."})
|
||||
.with_tags({"math"})
|
||||
.with_example({"SELECT avg(ex_duration) FROM lnav_example_log"})
|
||||
.with_example({"SELECT ex_procname, avg(ex_duration) FROM lnav_example_log GROUP BY ex_procname"}),
|
||||
|
||||
@ -442,6 +464,7 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_parameter({"X", "The value to concatenate."})
|
||||
.with_parameter(help_text("sep", "The separator to place between the values.")
|
||||
.optional())
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT group_concat(ex_procname) FROM lnav_example_log"})
|
||||
.with_example({"SELECT group_concat(ex_procname, ', ') FROM lnav_example_log"})
|
||||
.with_example({"SELECT group_concat(DISTINCT ex_procname) FROM lnav_example_log"}),
|
||||
@ -450,18 +473,21 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
"Returns the sum of the values in the group as an integer.")
|
||||
.sql_function()
|
||||
.with_parameter({"X", "The values to add."})
|
||||
.with_tags({"math"})
|
||||
.with_example({"SELECT sum(ex_duration) FROM lnav_example_log"}),
|
||||
|
||||
help_text("total",
|
||||
"Returns the sum of the values in the group as a floating-point.")
|
||||
.sql_function()
|
||||
.with_parameter({"X", "The values to add."})
|
||||
.with_tags({"math"})
|
||||
.with_example({"SELECT total(ex_duration) FROM lnav_example_log"}),
|
||||
|
||||
};
|
||||
|
||||
for (auto &ht : builtin_funcs) {
|
||||
sqlite_function_help[ht.ht_name] = &ht;
|
||||
sqlite_function_help.insert(make_pair(ht.ht_name, &ht));
|
||||
ht.index_tags();
|
||||
}
|
||||
|
||||
static help_text idents[] = {
|
||||
@ -481,6 +507,82 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
.with_flag_name("DATABASE"))
|
||||
.with_example({"DETACH DATABASE customers"}),
|
||||
|
||||
help_text("CREATE", "Assign a name to a SELECT statement")
|
||||
.sql_keyword()
|
||||
.with_parameter(help_text("TEMP")
|
||||
.optional())
|
||||
.with_parameter(help_text("")
|
||||
.with_flag_name("VIEW"))
|
||||
.with_parameter(help_text("IF NOT EXISTS", "Do not create the view if it already exists")
|
||||
.optional())
|
||||
.with_parameter(help_text("schema-name.", "The database to create the view in")
|
||||
.optional())
|
||||
.with_parameter(help_text("view-name", "The name of the view"))
|
||||
.with_parameter(help_text("select-stmt", "The SELECT statement the view represents")
|
||||
.with_flag_name("AS")),
|
||||
|
||||
help_text("CREATE", "Create a table")
|
||||
.sql_keyword()
|
||||
.with_parameter(help_text("TEMP").optional())
|
||||
.with_parameter(help_text("")
|
||||
.with_flag_name("TABLE"))
|
||||
.with_parameter(help_text("IF NOT EXISTS")
|
||||
.optional())
|
||||
.with_parameter(help_text("schema-name.")
|
||||
.optional())
|
||||
.with_parameter(help_text("table-name"))
|
||||
.with_parameter(help_text("select-stmt")
|
||||
.with_flag_name("AS")),
|
||||
|
||||
help_text("DELETE", "Delete rows from a table")
|
||||
.sql_keyword()
|
||||
.with_parameter(help_text("table-name", "The name of the table")
|
||||
.with_flag_name("FROM"))
|
||||
.with_parameter(help_text("cond", "The conditions used to delete the rows.")
|
||||
.with_flag_name("WHERE")
|
||||
.optional())
|
||||
.with_example({"SELECT * FROM syslog_log"}),
|
||||
|
||||
help_text("DROP", "Drop an index")
|
||||
.sql_keyword()
|
||||
.with_parameter(help_text("")
|
||||
.with_flag_name("INDEX"))
|
||||
.with_parameter(help_text("IF EXISTS")
|
||||
.optional())
|
||||
.with_parameter(help_text("schema-name.")
|
||||
.optional())
|
||||
.with_parameter(help_text("index-name")),
|
||||
|
||||
help_text("DROP", "Drop a table")
|
||||
.sql_keyword()
|
||||
.with_parameter(help_text("")
|
||||
.with_flag_name("TABLE"))
|
||||
.with_parameter(help_text("IF EXISTS")
|
||||
.optional())
|
||||
.with_parameter(help_text("schema-name.")
|
||||
.optional())
|
||||
.with_parameter(help_text("table-name")),
|
||||
|
||||
help_text("DROP", "Drop a view")
|
||||
.sql_keyword()
|
||||
.with_parameter(help_text("")
|
||||
.with_flag_name("VIEW"))
|
||||
.with_parameter(help_text("IF EXISTS")
|
||||
.optional())
|
||||
.with_parameter(help_text("schema-name.")
|
||||
.optional())
|
||||
.with_parameter(help_text("view-name")),
|
||||
|
||||
help_text("DROP", "Drop a trigger")
|
||||
.sql_keyword()
|
||||
.with_parameter(help_text("")
|
||||
.with_flag_name("TRIGGER"))
|
||||
.with_parameter(help_text("IF EXISTS")
|
||||
.optional())
|
||||
.with_parameter(help_text("schema-name.")
|
||||
.optional())
|
||||
.with_parameter(help_text("trigger-name")),
|
||||
|
||||
help_text("SELECT",
|
||||
"Query the database and return zero or more rows of data.")
|
||||
.sql_keyword()
|
||||
@ -556,12 +658,12 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
|
||||
};
|
||||
|
||||
for (auto &ht : idents) {
|
||||
sqlite_function_help[tolower(ht.ht_name)] = &ht;
|
||||
sqlite_function_help.insert(make_pair(toupper(ht.ht_name), &ht));
|
||||
for (const auto ¶m : ht.ht_parameters) {
|
||||
if (!param.ht_flag_name) {
|
||||
continue;
|
||||
}
|
||||
sqlite_function_help[tolower(param.ht_flag_name)] = &ht;
|
||||
sqlite_function_help.insert(make_pair(toupper(param.ht_flag_name), &ht));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
#include "help_text_formatter.hh"
|
||||
|
||||
@ -83,7 +83,7 @@ int time_extension_functions(struct FuncDef **basic_funcs,
|
||||
|
||||
extern sqlite_registration_func_t sqlite_registration_funcs[];
|
||||
|
||||
extern std::unordered_map<std::string, help_text *> sqlite_function_help;
|
||||
extern std::multimap<std::string, help_text *> sqlite_function_help;
|
||||
|
||||
int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs);
|
||||
|
||||
|
@ -55,7 +55,7 @@ static cache_entry *find_re(const char *re)
|
||||
auto_mem<char> e2(sqlite3_free);
|
||||
|
||||
e2 = sqlite3_mprintf("%s: %s", re, c.re->error().c_str());
|
||||
throw new pcrepp::error(e2.in(), 0);
|
||||
throw pcrepp::error(e2.in(), 0);
|
||||
}
|
||||
CACHE[re_str] = c;
|
||||
|
||||
@ -91,7 +91,7 @@ regexp_match(const char *re, const char *str)
|
||||
|
||||
auto_mem<yajl_gen_t> gen(yajl_gen_free);
|
||||
|
||||
gen = yajl_gen_alloc(NULL);
|
||||
gen = yajl_gen_alloc(nullptr);
|
||||
yajl_gen_config(gen.in(), yajl_gen_beautify, false);
|
||||
|
||||
if (extractor.get_capture_count() == 1) {
|
||||
@ -216,6 +216,7 @@ int string_extension_functions(struct FuncDef **basic_funcs,
|
||||
.sql_function()
|
||||
.with_parameter({"re", "The regular expression to use"})
|
||||
.with_parameter({"str", "The string to test against the regular expression"})
|
||||
.with_tags({"string", "regex"})
|
||||
.with_example({"SELECT regexp_match('(\\d+)', '123')"})
|
||||
.with_example({"SELECT regexp_match('(\\d+) (\\w+)', '123 four')"})
|
||||
.with_example({"SELECT regexp_match('(?<num>\\d+) (?<str>\\w+)', '123 four')"})
|
||||
@ -230,6 +231,7 @@ int string_extension_functions(struct FuncDef **basic_funcs,
|
||||
.with_parameter({"repl", "The replacement string. "
|
||||
"You can reference capture groups with a backslash followed by the number of the "
|
||||
"group, starting with 1."})
|
||||
.with_tags({"string", "regex"})
|
||||
.with_example({"SELECT regexp_replace('Hello, World!', '^(\\w+)', 'Goodbye')"})
|
||||
.with_example({"SELECT regexp_replace('123 abc', '(\\w+)', '<\\1>')"})
|
||||
),
|
||||
@ -239,6 +241,7 @@ int string_extension_functions(struct FuncDef **basic_funcs,
|
||||
"Automatically Parse and extract data from a string")
|
||||
.sql_function()
|
||||
.with_parameter({"str", "The string to parse"})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT extract('foo=1 bar=2 name=\"Rolo Tomassi\"')"})
|
||||
.with_example({"SELECT extract('1.0 abc 2.0')"})
|
||||
),
|
||||
@ -251,6 +254,7 @@ int string_extension_functions(struct FuncDef **basic_funcs,
|
||||
.sql_function()
|
||||
.with_parameter({"str", "The string to test"})
|
||||
.with_parameter({"prefix", "The prefix to check in the string"})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT startswith('foobar', 'foo')"})
|
||||
.with_example({"SELECT startswith('foobar', 'bar')"})
|
||||
),
|
||||
@ -261,6 +265,7 @@ int string_extension_functions(struct FuncDef **basic_funcs,
|
||||
.sql_function()
|
||||
.with_parameter({"str", "The string to test"})
|
||||
.with_parameter({"suffix", "The suffix to check in the string"})
|
||||
.with_tags({"string"})
|
||||
.with_example({"SELECT endswith('notbad.jpg', '.jpg')"})
|
||||
.with_example({"SELECT endswith('notbad.png', '.jpg')"})
|
||||
),
|
||||
|
@ -55,8 +55,8 @@ void text_filter::add_line(
|
||||
}
|
||||
|
||||
bookmark_type_t textview_curses::BM_USER("user");
|
||||
bookmark_type_t textview_curses::BM_PARTITION("partition");
|
||||
bookmark_type_t textview_curses::BM_SEARCH("search");
|
||||
bookmark_type_t textview_curses::BM_META("meta");
|
||||
|
||||
string_attr_type textview_curses::SA_ORIGINAL_LINE("original_line");
|
||||
string_attr_type textview_curses::SA_BODY("body");
|
||||
@ -66,7 +66,6 @@ string_attr_type textview_curses::SA_FORMAT("format");
|
||||
textview_curses::textview_curses()
|
||||
: tc_sub_source(NULL),
|
||||
tc_delegate(NULL),
|
||||
tc_searching(false),
|
||||
tc_selection_start(-1),
|
||||
tc_selection_last(-1),
|
||||
tc_selection_cleared(false),
|
||||
@ -82,33 +81,49 @@ textview_curses::~textview_curses()
|
||||
|
||||
void textview_curses::reload_data(void)
|
||||
{
|
||||
if (this->tc_sub_source != NULL) {
|
||||
if (this->tc_sub_source != nullptr) {
|
||||
this->tc_sub_source->text_update_marks(this->tc_bookmarks);
|
||||
}
|
||||
this->listview_curses::reload_data();
|
||||
}
|
||||
|
||||
void textview_curses::grep_begin(grep_proc &gp)
|
||||
void textview_curses::grep_begin(grep_proc<vis_line_t> &gp, vis_line_t start, vis_line_t stop)
|
||||
{
|
||||
this->tc_searching = true;
|
||||
require(this->tc_searching >= 0);
|
||||
|
||||
this->tc_searching += 1;
|
||||
this->tc_search_action.invoke(this);
|
||||
|
||||
bookmark_vector<vis_line_t> &search_bv = this->tc_bookmarks[&BM_SEARCH];
|
||||
|
||||
if (start != -1) {
|
||||
auto pair = search_bv.equal_range(vis_line_t(start), vis_line_t(stop));
|
||||
|
||||
for (auto mark_iter = pair.first;
|
||||
mark_iter != pair.second;
|
||||
++mark_iter) {
|
||||
this->set_user_mark(&BM_SEARCH, *mark_iter, false);
|
||||
}
|
||||
}
|
||||
|
||||
listview_curses::reload_data();
|
||||
}
|
||||
|
||||
void textview_curses::grep_end(grep_proc &gp)
|
||||
void textview_curses::grep_end(grep_proc<vis_line_t> &gp)
|
||||
{
|
||||
this->tc_searching = false;
|
||||
this->tc_searching -= 1;
|
||||
this->tc_search_action.invoke(this);
|
||||
|
||||
ensure(this->tc_searching >= 0);
|
||||
}
|
||||
|
||||
void textview_curses::grep_match(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
void textview_curses::grep_match(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end)
|
||||
{
|
||||
this->tc_bookmarks[&BM_SEARCH].insert_once(vis_line_t(line));
|
||||
if (this->tc_sub_source != NULL) {
|
||||
if (this->tc_sub_source != nullptr) {
|
||||
this->tc_sub_source->text_mark(&BM_SEARCH, line, true);
|
||||
}
|
||||
|
||||
@ -137,7 +152,7 @@ bool textview_curses::handle_mouse(mouse_event &me)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->tc_delegate != NULL &&
|
||||
if (this->tc_delegate != nullptr &&
|
||||
this->tc_delegate->text_handle_mouse(*this, me)) {
|
||||
return true;
|
||||
}
|
||||
@ -214,10 +229,8 @@ void textview_curses::textview_value_for_row(vis_line_t row,
|
||||
{
|
||||
view_colors &vc = view_colors::singleton();
|
||||
bookmark_vector<vis_line_t> &user_marks = this->tc_bookmarks[&BM_USER];
|
||||
bookmark_vector<vis_line_t> &part_marks = this->tc_bookmarks[&BM_PARTITION];
|
||||
string_attrs_t &sa = value_out.get_attrs();
|
||||
string &str = value_out.get_string();
|
||||
highlight_map_t::iterator iter;
|
||||
text_format_t source_format = this->tc_sub_source->get_text_format();
|
||||
intern_string_t format_name;
|
||||
|
||||
@ -245,20 +258,13 @@ void textview_curses::textview_value_for_row(vis_line_t row,
|
||||
format_name = sa_iter->to_string();
|
||||
}
|
||||
|
||||
for (iter = this->tc_highlights.begin();
|
||||
for (auto iter = this->tc_highlights.begin();
|
||||
iter != this->tc_highlights.end();
|
||||
iter++) {
|
||||
// XXX testing for '$search' here sucks
|
||||
bool internal_hl = iter->first[0] == '$'
|
||||
&& iter->first != "$search"
|
||||
&& iter->first != "$preview";
|
||||
int off;
|
||||
size_t re_end;
|
||||
|
||||
if (body.lr_end > 8192)
|
||||
re_end = 8192;
|
||||
else
|
||||
re_end = body.lr_end;
|
||||
|
||||
if (iter->second.h_text_format != TF_UNKNOWN &&
|
||||
source_format != iter->second.h_text_format) {
|
||||
@ -270,42 +276,7 @@ void textview_curses::textview_value_for_row(vis_line_t row,
|
||||
continue;
|
||||
}
|
||||
|
||||
for (off = internal_hl ? body.lr_start : 0; off < (int)str.size(); ) {
|
||||
int rc, matches[60];
|
||||
rc = pcre_exec(iter->second.h_code,
|
||||
iter->second.h_code_extra,
|
||||
str.c_str(),
|
||||
re_end,
|
||||
off,
|
||||
0,
|
||||
matches,
|
||||
60);
|
||||
if (rc > 0) {
|
||||
struct line_range lr;
|
||||
|
||||
if (rc == 2) {
|
||||
lr.lr_start = matches[2];
|
||||
lr.lr_end = matches[3];
|
||||
}
|
||||
else {
|
||||
lr.lr_start = matches[0];
|
||||
lr.lr_end = matches[1];
|
||||
}
|
||||
|
||||
if (lr.lr_end > lr.lr_start) {
|
||||
sa.push_back(string_attr(
|
||||
lr, &view_curses::VC_STYLE, iter->second.get_attrs()));
|
||||
|
||||
off = matches[1];
|
||||
}
|
||||
else {
|
||||
off += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
off = str.size();
|
||||
}
|
||||
}
|
||||
iter->second.annotate(value_out, internal_hl ? body.lr_start : 0);
|
||||
}
|
||||
|
||||
if (this->tc_hide_fields) {
|
||||
@ -398,8 +369,4 @@ void textview_curses::textview_value_for_row(vis_line_t row,
|
||||
|
||||
sa.emplace_back(orig_line, &view_curses::VC_STYLE, A_REVERSE);
|
||||
}
|
||||
else if (binary_search(part_marks.begin(), part_marks.end(), row + 1)) {
|
||||
sa.push_back(string_attr(
|
||||
line_range(0), &view_curses::VC_STYLE, A_UNDERLINE));
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#ifndef __textview_curses_hh
|
||||
#define __textview_curses_hh
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "grep_proc.hh"
|
||||
@ -48,13 +49,14 @@ class textview_curses;
|
||||
|
||||
class logfile_filter_state {
|
||||
public:
|
||||
logfile_filter_state(std::shared_ptr<logfile> lf = nullptr) : tfs_logfile(lf) {
|
||||
logfile_filter_state(std::shared_ptr<logfile> lf = nullptr) : tfs_logfile(
|
||||
std::move(lf)) {
|
||||
memset(this->tfs_filter_count, 0, sizeof(this->tfs_filter_count));
|
||||
this->tfs_mask.reserve(64 * 1024);
|
||||
};
|
||||
|
||||
void clear(void) {
|
||||
this->tfs_logfile = NULL;
|
||||
void clear() {
|
||||
this->tfs_logfile = nullptr;
|
||||
memset(this->tfs_filter_count, 0, sizeof(this->tfs_filter_count));
|
||||
this->tfs_mask.clear();
|
||||
this->tfs_index.clear();
|
||||
@ -113,13 +115,13 @@ public:
|
||||
lf_index(index) { };
|
||||
virtual ~text_filter() { };
|
||||
|
||||
type_t get_type(void) const { return this->lf_type; };
|
||||
std::string get_id(void) const { return this->lf_id; };
|
||||
size_t get_index(void) const { return this->lf_index; };
|
||||
type_t get_type() const { return this->lf_type; };
|
||||
std::string get_id() const { return this->lf_id; };
|
||||
size_t get_index() const { return this->lf_index; };
|
||||
|
||||
bool is_enabled(void) { return this->lf_enabled; };
|
||||
void enable(void) { this->lf_enabled = true; };
|
||||
void disable(void) { this->lf_enabled = false; };
|
||||
bool is_enabled() { return this->lf_enabled; };
|
||||
void enable() { this->lf_enabled = true; };
|
||||
void disable() { this->lf_enabled = false; };
|
||||
|
||||
void revert_to_last(logfile_filter_state &lfs) {
|
||||
this->lf_message_matched = this->lf_last_message_matched;
|
||||
@ -160,7 +162,7 @@ public:
|
||||
|
||||
virtual bool matches(const logfile &lf, const logline &ll, shared_buffer_ref &line) = 0;
|
||||
|
||||
virtual std::string to_command(void) = 0;
|
||||
virtual std::string to_command() = 0;
|
||||
|
||||
bool operator==(const std::string &rhs) {
|
||||
return this->lf_id == rhs;
|
||||
@ -206,14 +208,14 @@ public:
|
||||
bool used[32];
|
||||
|
||||
memset(used, 0, sizeof(used));
|
||||
for (iterator iter = this->begin(); iter != this->end(); ++iter) {
|
||||
size_t index = (*iter)->get_index();
|
||||
for (auto &iter : *this) {
|
||||
size_t index = iter->get_index();
|
||||
|
||||
require(used[index] == false);
|
||||
|
||||
used[index] = true;
|
||||
}
|
||||
for (int lpc = 0; lpc < logfile_filter_state::MAX_FILTERS; lpc++) {
|
||||
for (size_t lpc = 0; lpc < logfile_filter_state::MAX_FILTERS; lpc++) {
|
||||
if (!used[lpc]) {
|
||||
return lpc;
|
||||
}
|
||||
@ -221,17 +223,17 @@ public:
|
||||
throw "No more filters";
|
||||
};
|
||||
|
||||
void add_filter(std::shared_ptr<text_filter> filter) {
|
||||
void add_filter(const std::shared_ptr<text_filter> &filter) {
|
||||
this->fs_filters.push_back(filter);
|
||||
};
|
||||
|
||||
void clear_filters(void) {
|
||||
void clear_filters() {
|
||||
while (!this->fs_filters.empty()) {
|
||||
this->fs_filters.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
void set_filter_enabled(std::shared_ptr<text_filter> filter, bool enabled) {
|
||||
void set_filter_enabled(const std::shared_ptr<text_filter> &filter, bool enabled) {
|
||||
if (enabled) {
|
||||
filter->enable();
|
||||
}
|
||||
@ -240,7 +242,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<text_filter> get_filter(std::string id)
|
||||
std::shared_ptr<text_filter> get_filter(const std::string &id)
|
||||
{
|
||||
auto iter = this->fs_filters.begin();
|
||||
std::shared_ptr<text_filter> retval;
|
||||
@ -255,7 +257,7 @@ public:
|
||||
return retval;
|
||||
};
|
||||
|
||||
bool delete_filter(std::string id) {
|
||||
bool delete_filter(const std::string &id) {
|
||||
auto iter = this->fs_filters.begin();
|
||||
|
||||
for (;
|
||||
@ -273,7 +275,7 @@ public:
|
||||
|
||||
void get_enabled_mask(uint32_t &filter_in_mask, uint32_t &filter_out_mask) {
|
||||
filter_in_mask = filter_out_mask = 0;
|
||||
for (iterator iter = this->begin(); iter != this->end(); ++iter) {
|
||||
for (auto iter = this->begin(); iter != this->end(); ++iter) {
|
||||
std::shared_ptr<text_filter> tf = (*iter);
|
||||
if (tf->is_enabled()) {
|
||||
uint32_t bit = (1UL << tf->get_index());
|
||||
@ -320,14 +322,16 @@ public:
|
||||
};
|
||||
|
||||
enum {
|
||||
RF_RAW = (1L << RB_RAW),
|
||||
RF_FULL = (1L << RB_FULL),
|
||||
RF_REWRITE = (1L << RB_REWRITE),
|
||||
RF_RAW = (1UL << RB_RAW),
|
||||
RF_FULL = (1UL << RB_FULL),
|
||||
RF_REWRITE = (1UL << RB_REWRITE),
|
||||
};
|
||||
|
||||
typedef long line_flags_t;
|
||||
|
||||
virtual void toggle_scrub(void) { };
|
||||
void register_view(textview_curses *tc) {
|
||||
this->tss_view = tc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return The total number of lines available from the source.
|
||||
@ -367,7 +371,7 @@ public:
|
||||
* @param added True if the line was bookmarked and false if it was
|
||||
* unmarked.
|
||||
*/
|
||||
virtual void text_mark(bookmark_type_t *bm, int line, bool added) {};
|
||||
virtual void text_mark(bookmark_type_t *bm, vis_line_t line, bool added) {};
|
||||
|
||||
/**
|
||||
* Clear the bookmarks for a particular type in the text source.
|
||||
@ -416,7 +420,8 @@ public:
|
||||
return TF_UNKNOWN;
|
||||
};
|
||||
|
||||
private:
|
||||
protected:
|
||||
textview_curses *tss_view;
|
||||
filter_stack tss_filters;
|
||||
};
|
||||
|
||||
@ -438,15 +443,15 @@ public:
|
||||
class textview_curses
|
||||
: public listview_curses,
|
||||
public list_data_source,
|
||||
public grep_proc_source,
|
||||
public grep_proc_sink {
|
||||
public grep_proc_source<vis_line_t>,
|
||||
public grep_proc_sink<vis_line_t> {
|
||||
public:
|
||||
|
||||
typedef view_action<textview_curses> action;
|
||||
|
||||
static bookmark_type_t BM_USER;
|
||||
static bookmark_type_t BM_PARTITION;
|
||||
static bookmark_type_t BM_SEARCH;
|
||||
static bookmark_type_t BM_META;
|
||||
|
||||
static string_attr_type SA_ORIGINAL_LINE;
|
||||
static string_attr_type SA_BODY;
|
||||
@ -477,8 +482,7 @@ public:
|
||||
}
|
||||
for (vis_line_t curr_line = start_line; curr_line <= end_line;
|
||||
++curr_line) {
|
||||
bookmark_vector<vis_line_t> &bv =
|
||||
this->tc_bookmarks[bm];
|
||||
bookmark_vector<vis_line_t> &bv = this->tc_bookmarks[bm];
|
||||
bookmark_vector<vis_line_t>::iterator iter;
|
||||
bool added;
|
||||
|
||||
@ -490,8 +494,8 @@ public:
|
||||
bv.erase(iter);
|
||||
added = false;
|
||||
}
|
||||
if (this->tc_sub_source != NULL) {
|
||||
this->tc_sub_source->text_mark(bm, (int)curr_line, added);
|
||||
if (this->tc_sub_source) {
|
||||
this->tc_sub_source->text_mark(bm, curr_line, added);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -509,13 +513,14 @@ public:
|
||||
bv.erase(iter);
|
||||
}
|
||||
}
|
||||
if (this->tc_sub_source != NULL) {
|
||||
this->tc_sub_source->text_mark(bm, (int)vl, marked);
|
||||
if (this->tc_sub_source) {
|
||||
this->tc_sub_source->text_mark(bm, vl, marked);
|
||||
}
|
||||
};
|
||||
|
||||
textview_curses &set_sub_source(text_sub_source *src) {
|
||||
this->tc_sub_source = src;
|
||||
src->register_view(this);
|
||||
this->reload_data();
|
||||
return *this;
|
||||
};
|
||||
@ -532,7 +537,7 @@ public:
|
||||
|
||||
void horiz_shift(vis_line_t start, vis_line_t end,
|
||||
int off_start,
|
||||
std::string highlight_name,
|
||||
const std::string &highlight_name,
|
||||
std::pair<int, int> &range_out)
|
||||
{
|
||||
highlighter &hl = this->tc_highlights[highlight_name];
|
||||
@ -598,7 +603,7 @@ public:
|
||||
this->tc_search_action = action(mf);
|
||||
};
|
||||
|
||||
void grep_end_batch(grep_proc &gp)
|
||||
void grep_end_batch(grep_proc<vis_line_t> &gp)
|
||||
{
|
||||
if (this->tc_follow_deadline.tv_sec) {
|
||||
struct timeval now;
|
||||
@ -624,16 +629,16 @@ public:
|
||||
}
|
||||
this->tc_search_action.invoke(this);
|
||||
};
|
||||
void grep_end(grep_proc &gp);
|
||||
void grep_end(grep_proc<vis_line_t> &gp);
|
||||
|
||||
size_t listview_rows(const listview_curses &lv)
|
||||
{
|
||||
return this->tc_sub_source == NULL ? 0 :
|
||||
return this->tc_sub_source == nullptr ? 0 :
|
||||
this->tc_sub_source->text_line_count();
|
||||
};
|
||||
|
||||
size_t listview_width(const listview_curses &lv) {
|
||||
return this->tc_sub_source == NULL ? 0 :
|
||||
return this->tc_sub_source == nullptr ? 0 :
|
||||
this->tc_sub_source->text_line_width(*this);
|
||||
};
|
||||
|
||||
@ -648,15 +653,15 @@ public:
|
||||
};
|
||||
|
||||
std::string listview_source_name(const listview_curses &lv) {
|
||||
return this->tc_sub_source == NULL ? "" :
|
||||
return this->tc_sub_source == nullptr ? "" :
|
||||
this->tc_sub_source->text_source_name(*this);
|
||||
};
|
||||
|
||||
bool grep_value_for_line(int line, std::string &value_out)
|
||||
bool grep_value_for_line(vis_line_t line, std::string &value_out)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
if (this->tc_sub_source != NULL &&
|
||||
if (this->tc_sub_source &&
|
||||
line < (int)this->tc_sub_source->text_line_count()) {
|
||||
this->tc_sub_source->text_value_for_line(*this,
|
||||
line,
|
||||
@ -668,20 +673,20 @@ public:
|
||||
return retval;
|
||||
};
|
||||
|
||||
void grep_begin(grep_proc &gp);
|
||||
void grep_match(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
void grep_begin(grep_proc<vis_line_t> &gp, vis_line_t start, vis_line_t stop);
|
||||
void grep_match(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end);
|
||||
|
||||
bool is_searching(void) { return this->tc_searching; };
|
||||
bool is_searching(void) { return this->tc_searching > 0; };
|
||||
|
||||
void set_follow_search_for(int64_t ms_to_deadline) {
|
||||
struct timeval now, tv;
|
||||
|
||||
tv.tv_sec = ms_to_deadline / 1000;
|
||||
tv.tv_usec = (ms_to_deadline % 1000) * 1000;
|
||||
gettimeofday(&now, NULL);
|
||||
gettimeofday(&now, nullptr);
|
||||
timeradd(&now, &tv, &this->tc_follow_deadline);
|
||||
};
|
||||
|
||||
@ -702,6 +707,8 @@ public:
|
||||
|
||||
highlight_map_t &get_highlights() { return this->tc_highlights; };
|
||||
|
||||
const highlight_map_t &get_highlights() const { return this->tc_highlights; };
|
||||
|
||||
bool handle_mouse(mouse_event &me);
|
||||
|
||||
void reload_data(void);
|
||||
@ -727,12 +734,11 @@ protected:
|
||||
|
||||
vis_bookmarks tc_bookmarks;
|
||||
|
||||
bool tc_searching;
|
||||
int tc_searching{0};
|
||||
struct timeval tc_follow_deadline;
|
||||
action tc_search_action;
|
||||
|
||||
highlight_map_t tc_highlights;
|
||||
highlight_map_t::iterator tc_current_highlight;
|
||||
|
||||
vis_line_t tc_selection_start;
|
||||
vis_line_t tc_selection_last;
|
||||
|
@ -127,6 +127,7 @@ int time_extension_functions(struct FuncDef **basic_funcs,
|
||||
.sql_function()
|
||||
.with_parameter({"time", "The timestamp to get the time slice for."})
|
||||
.with_parameter({"slice", "The size of the time slices"})
|
||||
.with_tags({"datetime"})
|
||||
.with_example({"SELECT timeslice('2017-01-01T05:05:00', '10m')"})
|
||||
.with_example({"SELECT timeslice(log_time, '5m') AS slice, count(*) FROM lnav_example_log GROUP BY slice"})
|
||||
),
|
||||
@ -137,6 +138,7 @@ int time_extension_functions(struct FuncDef **basic_funcs,
|
||||
.sql_function()
|
||||
.with_parameter({"time1", "The first timestamp"})
|
||||
.with_parameter({"time2", "The timestamp to subtract from the first"})
|
||||
.with_tags({"datetime"})
|
||||
.with_example({"SELECT timediff('2017-02-03T04:05:06', '2017-02-03T04:05:00')"})
|
||||
.with_example({"SELECT timediff('today', 'yesterday')"})
|
||||
),
|
||||
|
@ -61,6 +61,7 @@ public:
|
||||
{
|
||||
this->tss_fields[TSF_TIME].set_width(24);
|
||||
this->tss_fields[TSF_PARTITION_NAME].set_width(34);
|
||||
this->tss_fields[TSF_PARTITION_NAME].set_left_pad(1);
|
||||
this->tss_fields[TSF_VIEW_NAME].set_width(8);
|
||||
this->tss_fields[TSF_VIEW_NAME].set_role(view_colors::VCR_VIEW_STATUS);
|
||||
this->tss_fields[TSF_VIEW_NAME].right_justify(true);
|
||||
|
@ -83,7 +83,7 @@ static struct _xterm_colors {
|
||||
yajlpp_parse_context ypc_xterm("xterm-palette.json", root_color_handler);
|
||||
yajl_handle handle;
|
||||
|
||||
handle = yajl_alloc(&ypc_xterm.ypc_callbacks, NULL, &ypc_xterm);
|
||||
handle = yajl_alloc(&ypc_xterm.ypc_callbacks, nullptr, &ypc_xterm);
|
||||
ypc_xterm
|
||||
.with_ignore_unused(true)
|
||||
.with_obj(this->xc_palette)
|
||||
@ -175,8 +175,8 @@ ui_periodic_timer::ui_periodic_timer()
|
||||
sa.sa_handler = ui_periodic_timer::sigalrm;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
if (setitimer(ITIMER_REAL, &INTERVAL, NULL) == -1) {
|
||||
sigaction(SIGALRM, &sa, nullptr);
|
||||
if (setitimer(ITIMER_REAL, &INTERVAL, nullptr) == -1) {
|
||||
perror("setitimer");
|
||||
}
|
||||
}
|
||||
@ -208,7 +208,7 @@ attr_line_t &attr_line_t::with_ansi_string(const char *str, ...)
|
||||
auto ret = vasprintf(formatted_str.out(), str, args);
|
||||
va_end(args);
|
||||
|
||||
if (ret >= 0 && formatted_str != NULL) {
|
||||
if (ret >= 0 && formatted_str != nullptr) {
|
||||
this->al_string = formatted_str;
|
||||
scrub_ansi_string(this->al_string, this->al_attrs);
|
||||
}
|
||||
@ -382,7 +382,8 @@ void view_curses::mvwattrline(WINDOW *window,
|
||||
const struct line_range &lr,
|
||||
view_colors::role_t base_role)
|
||||
{
|
||||
int text_attrs, attrs, line_width;
|
||||
attr_t text_attrs, attrs;
|
||||
int line_width;
|
||||
string_attrs_t & sa = al.get_attrs();
|
||||
string & line = al.get_string();
|
||||
string_attrs_t::const_iterator iter;
|
||||
@ -544,7 +545,7 @@ class color_listener : public lnav_config_listener {
|
||||
|
||||
static color_listener _COLOR_LISTENER;
|
||||
|
||||
int view_colors::BASIC_HL_PAIRS[view_colors::BASIC_COLOR_COUNT] = {
|
||||
attr_t view_colors::BASIC_HL_PAIRS[view_colors::BASIC_COLOR_COUNT] = {
|
||||
ansi_color_pair(COLOR_BLUE, COLOR_BLACK),
|
||||
ansi_color_pair(COLOR_CYAN, COLOR_BLACK),
|
||||
ansi_color_pair(COLOR_GREEN, COLOR_BLACK),
|
||||
@ -620,7 +621,7 @@ void view_colors::init(void)
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
inline int attr_for_colors(int &pair_base, short fg, short bg)
|
||||
inline attr_t attr_for_colors(int &pair_base, short fg, short bg)
|
||||
{
|
||||
int pair = ++pair_base;
|
||||
|
||||
|
@ -206,7 +206,7 @@ public:
|
||||
|
||||
broadcaster()
|
||||
: b_functor(*this, &broadcaster::invoke) { };
|
||||
virtual ~broadcaster() { };
|
||||
virtual ~broadcaster() = default;
|
||||
|
||||
void invoke(_Sender *sender)
|
||||
{
|
||||
@ -233,8 +233,8 @@ private:
|
||||
* parameters, the first being the value of the receiver pointer and the
|
||||
* second being the sender pointer as passed to invoke().
|
||||
*/
|
||||
view_action(void(*invoker)(void *, _Sender *) = NULL)
|
||||
: va_functor(NULL),
|
||||
view_action(void(*invoker)(void *, _Sender *) = nullptr)
|
||||
: va_functor(nullptr),
|
||||
va_invoker(invoker) { };
|
||||
|
||||
template<class _Receiver>
|
||||
@ -350,10 +350,12 @@ struct lab_color {
|
||||
return i < 0.0 ? 0.0 : sqrt(i);
|
||||
}
|
||||
|
||||
void operator=(const lab_color &other) {
|
||||
lab_color& operator=(const lab_color &other) {
|
||||
this->lc_l = other.lc_l;
|
||||
this->lc_a = other.lc_a;
|
||||
this->lc_b = other.lc_b;
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
double lc_l;
|
||||
@ -369,7 +371,7 @@ public:
|
||||
static const unsigned long BASIC_COLOR_COUNT = 8;
|
||||
static const unsigned long HI_COLOR_COUNT = 6 * 3 * 3;
|
||||
|
||||
static int BASIC_HL_PAIRS[BASIC_COLOR_COUNT];
|
||||
static attr_t BASIC_HL_PAIRS[BASIC_COLOR_COUNT];
|
||||
|
||||
/** Roles that can be mapped to curses attributes using attrs_for_role() */
|
||||
typedef enum {
|
||||
@ -429,7 +431,7 @@ public:
|
||||
* @param role The role to retrieve character attributes for.
|
||||
* @return The attributes to use for the given role.
|
||||
*/
|
||||
int attrs_for_role(role_t role) const
|
||||
attr_t attrs_for_role(role_t role) const
|
||||
{
|
||||
require(role >= 0);
|
||||
require(role < VCR__MAX);
|
||||
@ -437,7 +439,7 @@ public:
|
||||
return this->vc_role_colors[role];
|
||||
};
|
||||
|
||||
int reverse_attrs_for_role(role_t role) const
|
||||
attr_t reverse_attrs_for_role(role_t role) const
|
||||
{
|
||||
require(role >= 0);
|
||||
require(role < VCR__MAX);
|
||||
@ -445,9 +447,9 @@ public:
|
||||
return this->vc_role_reverse_colors[role];
|
||||
};
|
||||
|
||||
int attrs_for_ident(const char *str, size_t len) const {
|
||||
attr_t attrs_for_ident(const char *str, size_t len) const {
|
||||
unsigned long index = crc32(1, (const Bytef*)str, len);
|
||||
int retval;
|
||||
attr_t retval;
|
||||
|
||||
if (COLORS >= 256) {
|
||||
unsigned long offset = index % HI_COLOR_COUNT;
|
||||
@ -460,7 +462,7 @@ public:
|
||||
return retval;
|
||||
};
|
||||
|
||||
int attrs_for_ident(const std::string &str) const {
|
||||
attr_t attrs_for_ident(const std::string &str) const {
|
||||
return this->attrs_for_ident(str.c_str(), str.length());
|
||||
};
|
||||
|
||||
@ -471,7 +473,7 @@ public:
|
||||
return VC_ANSI_START + ((fg * 8) + bg);
|
||||
};
|
||||
|
||||
static inline int ansi_color_pair(int fg, int bg)
|
||||
static inline attr_t ansi_color_pair(int fg, int bg)
|
||||
{
|
||||
return COLOR_PAIR(ansi_color_pair_index(fg, bg));
|
||||
};
|
||||
@ -489,9 +491,9 @@ private:
|
||||
static bool initialized;
|
||||
|
||||
/** Map of role IDs to attribute values. */
|
||||
int vc_role_colors[VCR__MAX];
|
||||
attr_t vc_role_colors[VCR__MAX];
|
||||
/** Map of role IDs to reverse-video attribute values. */
|
||||
int vc_role_reverse_colors[VCR__MAX];
|
||||
attr_t vc_role_reverse_colors[VCR__MAX];
|
||||
int vc_color_pair_end;
|
||||
|
||||
};
|
||||
|
@ -91,6 +91,13 @@ struct from_sqlite<int64_t> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from_sqlite<sqlite3_value *> {
|
||||
inline sqlite3_value *operator()(int argc, sqlite3_value **val, int argi) {
|
||||
return val[argi];
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from_sqlite<int> {
|
||||
inline int operator()(int argc, sqlite3_value **val, int argi) {
|
||||
@ -175,6 +182,11 @@ inline void to_sqlite(sqlite3_context *ctx, int64_t val)
|
||||
sqlite3_result_int64(ctx, val);
|
||||
}
|
||||
|
||||
inline void to_sqlite(sqlite3_context *ctx, int val)
|
||||
{
|
||||
sqlite3_result_int64(ctx, val);
|
||||
}
|
||||
|
||||
inline void to_sqlite(sqlite3_context *ctx, double val)
|
||||
{
|
||||
sqlite3_result_double(ctx, val);
|
||||
|
123
src/yajlpp.cc
123
src/yajlpp.cc
@ -91,18 +91,50 @@ int yajlpp_static_string(yajlpp_parse_context *ypc, const unsigned char *str, si
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool yajlpp_string_validator(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
|
||||
{
|
||||
const json_path_handler_base *jph = ypc->ypc_current_handler;
|
||||
bool retval = true;
|
||||
|
||||
if (jph->jph_pattern) {
|
||||
pcre_input pi((const char *) str, 0, len);
|
||||
pcre_context_static<30> pc;
|
||||
|
||||
if (!jph->jph_pattern->match(pc, pi)) {
|
||||
ypc->report_error(LOG_LEVEL_ERROR,
|
||||
"Value (%.*s) does not match pattern: %s",
|
||||
len, str,
|
||||
jph->jph_pattern_re);
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
if (len == 0 && jph->jph_min_length > 0) {
|
||||
ypc->report_error(LOG_LEVEL_ERROR, "value must not be empty");
|
||||
retval = false;
|
||||
} else if (len < jph->jph_min_length) {
|
||||
ypc->report_error(LOG_LEVEL_ERROR,
|
||||
"value must be at least %lu characters long",
|
||||
jph->jph_min_length);
|
||||
retval = false;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int yajlpp_static_string_vector(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
|
||||
{
|
||||
const json_path_handler_base *jph = ypc->ypc_current_handler;
|
||||
|
||||
if (jph->jph_kv_pair) {
|
||||
map<string, vector<string>> &field_ptr = resolve_root<map<string, vector<string>>>(ypc);
|
||||
auto &field_ptr = resolve_root<map<string, vector<string>>>(ypc);
|
||||
|
||||
field_ptr[ypc->get_path_fragment(-2)].push_back(string((const char *) str, len));
|
||||
} else {
|
||||
vector<string> &field_ptr = resolve_root<vector<string>>(ypc);
|
||||
auto &field_ptr = resolve_root<vector<string>>(ypc);
|
||||
|
||||
field_ptr.push_back(string((const char *) str, len));
|
||||
if (yajlpp_string_validator(ypc, str, len)) {
|
||||
field_ptr.emplace_back((const char *) str, len);
|
||||
}
|
||||
}
|
||||
|
||||
yajlpp_validator_for_string_vector(*ypc, *ypc->ypc_current_handler);
|
||||
@ -112,7 +144,7 @@ int yajlpp_static_string_vector(yajlpp_parse_context *ypc, const unsigned char *
|
||||
|
||||
int yajlpp_static_intern_string(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
|
||||
{
|
||||
intern_string_t &field_ptr = resolve_root<intern_string_t>(ypc);
|
||||
auto &field_ptr = resolve_root<intern_string_t>(ypc);
|
||||
|
||||
field_ptr = intern_string::lookup((const char *) str, len);
|
||||
|
||||
@ -138,22 +170,25 @@ int yajlpp_static_enum(yajlpp_parse_context *ypc, const unsigned char *str, size
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ypc->report_error("error:%s:line %d\n "
|
||||
ypc->report_error(LOG_LEVEL_ERROR,
|
||||
"error:%s:line %d\n "
|
||||
"Invalid value, '%.*s', for option:",
|
||||
ypc->ypc_source.c_str(),
|
||||
ypc->get_line_number(),
|
||||
len,
|
||||
str);
|
||||
|
||||
ypc->report_error(" %s %s -- %s\n",
|
||||
ypc->report_error(LOG_LEVEL_ERROR,
|
||||
" %s %s -- %s\n",
|
||||
&ypc->ypc_path[0],
|
||||
jph.jph_synopsis,
|
||||
jph.jph_description);
|
||||
ypc->report_error(" Allowed values: ");
|
||||
ypc->report_error(LOG_LEVEL_ERROR,
|
||||
" Allowed values: ");
|
||||
for (int lpc = 0; jph.jph_enum_values[lpc].first; lpc++) {
|
||||
const json_path_handler::enum_value_t &ev = jph.jph_enum_values[lpc];
|
||||
|
||||
ypc->report_error(" %s\n", ev.first);
|
||||
ypc->report_error(LOG_LEVEL_ERROR, " %s\n", ev.first);
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,9 +237,9 @@ yajl_gen_status yajlpp_static_gen_string_vector(yajlpp_gen_context &ygc,
|
||||
yajl_gen handle)
|
||||
{
|
||||
if (jph.jph_kv_pair) {
|
||||
map<string, vector<string>> *default_field_ptr = resolve_root<map<string, vector<string>>>(
|
||||
auto *default_field_ptr = resolve_root<map<string, vector<string>>>(
|
||||
ygc.ygc_default_stack, jph);
|
||||
map<string, vector<string>> *field_ptr = resolve_root<map<string, vector<string>>>(
|
||||
auto *field_ptr = resolve_root<map<string, vector<string>>>(
|
||||
ygc.ygc_obj_stack, jph);
|
||||
const string &base_name = ygc.ygc_base_name;
|
||||
|
||||
@ -241,12 +276,12 @@ void yajlpp_validator_for_string(yajlpp_parse_context &ypc,
|
||||
return; // XXX
|
||||
}
|
||||
|
||||
string &field_ptr = resolve_root<string>(&ypc);
|
||||
auto &field_ptr = resolve_root<string>(&ypc);
|
||||
|
||||
if (field_ptr.empty() && jph.jph_min_length > 0) {
|
||||
ypc.report_error("value must not be empty");
|
||||
ypc.report_error(LOG_LEVEL_ERROR, "value must not be empty");
|
||||
} else if (field_ptr.size() < jph.jph_min_length) {
|
||||
ypc.report_error("value must be at least %lu characters long",
|
||||
ypc.report_error(LOG_LEVEL_ERROR, "value must be at least %lu characters long",
|
||||
jph.jph_min_length);
|
||||
}
|
||||
}
|
||||
@ -258,13 +293,13 @@ void yajlpp_validator_for_string_vector(yajlpp_parse_context &ypc,
|
||||
return; // XXX
|
||||
}
|
||||
|
||||
vector<string> &field_ptr = resolve_root<vector<string>>(&ypc);
|
||||
auto &field_ptr = resolve_root<vector<string>>(&ypc);
|
||||
|
||||
for (string str : field_ptr) {
|
||||
for (const string &str : field_ptr) {
|
||||
if (str.empty() && jph.jph_min_length > 0) {
|
||||
ypc.report_error("value must not be empty");
|
||||
ypc.report_error(LOG_LEVEL_ERROR, "value must not be empty");
|
||||
} else if (str.size() < jph.jph_min_length) {
|
||||
ypc.report_error("value must be at least %lu characters long",
|
||||
ypc.report_error(LOG_LEVEL_ERROR, "value must be at least %lu characters long",
|
||||
jph.jph_min_length);
|
||||
}
|
||||
}
|
||||
@ -273,17 +308,17 @@ void yajlpp_validator_for_string_vector(yajlpp_parse_context &ypc,
|
||||
void yajlpp_validator_for_intern_string(yajlpp_parse_context &ypc,
|
||||
const json_path_handler_base &jph)
|
||||
{
|
||||
intern_string_t &field_ptr = resolve_root<intern_string_t>(&ypc);
|
||||
auto &field_ptr = resolve_root<intern_string_t>(&ypc);
|
||||
char buffer[1024];
|
||||
|
||||
if (field_ptr.empty() && jph.jph_min_length > 0) {
|
||||
ypc.report_error("value must not be empty");
|
||||
ypc.report_error(LOG_LEVEL_ERROR, "value must not be empty");
|
||||
}
|
||||
else if (field_ptr.size() < jph.jph_min_length) {
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"value must be at least %lu characters long",
|
||||
jph.jph_min_length);
|
||||
ypc.report_error(buffer);
|
||||
ypc.report_error(LOG_LEVEL_ERROR, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,7 +332,7 @@ void yajlpp_validator_for_int(yajlpp_parse_context &ypc,
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"value must be greater than %lld",
|
||||
jph.jph_min_value);
|
||||
ypc.report_error(buffer);
|
||||
ypc.report_error(LOG_LEVEL_ERROR, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,7 +346,7 @@ void yajlpp_validator_for_double(yajlpp_parse_context &ypc,
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"value must be greater than %lld",
|
||||
jph.jph_min_value);
|
||||
ypc.report_error(buffer);
|
||||
ypc.report_error(LOG_LEVEL_ERROR, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -703,50 +738,58 @@ int yajlpp_parse_context::handle_unused(void *ctx)
|
||||
|
||||
int line_number = ypc->get_line_number();
|
||||
|
||||
if (handler != NULL && strlen(handler->jph_synopsis) > 0 &&
|
||||
if (handler != nullptr && strlen(handler->jph_synopsis) > 0 &&
|
||||
strlen(handler->jph_description) > 0) {
|
||||
|
||||
fprintf(stderr,
|
||||
"warning:%s:line %d\n unexpected data for path -- \n",
|
||||
ypc->report_error(
|
||||
LOG_LEVEL_WARNING,
|
||||
"%s:line %d",
|
||||
ypc->ypc_source.c_str(),
|
||||
line_number);
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " unexpected data for path");
|
||||
|
||||
fprintf(stderr, " %s %s -- %s\n",
|
||||
ypc->report_error(LOG_LEVEL_WARNING,
|
||||
" %s %s -- %s",
|
||||
&ypc->ypc_path[0],
|
||||
handler->jph_synopsis,
|
||||
handler->jph_description
|
||||
);
|
||||
handler->jph_description);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,
|
||||
"warning:%s:line %d\n unexpected path -- \n",
|
||||
else if (ypc->ypc_path[0]) {
|
||||
ypc->report_error(LOG_LEVEL_WARNING,
|
||||
"%s:line %d",
|
||||
ypc->ypc_source.c_str(),
|
||||
line_number);
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " unexpected path --");
|
||||
|
||||
fprintf(stderr, " %s\n", &ypc->ypc_path[0]);
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " %s", &ypc->ypc_path[0]);
|
||||
} else {
|
||||
ypc->report_error(LOG_LEVEL_WARNING,
|
||||
"%s:line %d\n unexpected JSON value",
|
||||
ypc->ypc_source.c_str(),
|
||||
line_number);
|
||||
}
|
||||
|
||||
if (ypc->ypc_callbacks.yajl_boolean != (int (*)(void *, int))yajlpp_parse_context::handle_unused ||
|
||||
ypc->ypc_callbacks.yajl_integer != (int (*)(void *, long long))yajlpp_parse_context::handle_unused ||
|
||||
ypc->ypc_callbacks.yajl_double != (int (*)(void *, double))yajlpp_parse_context::handle_unused ||
|
||||
ypc->ypc_callbacks.yajl_string != (int (*)(void *, const unsigned char *, size_t))yajlpp_parse_context::handle_unused) {
|
||||
fprintf(stderr, " expecting one of the following data types --\n");
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " expecting one of the following data types --");
|
||||
}
|
||||
|
||||
if (ypc->ypc_callbacks.yajl_boolean != (int (*)(void *, int))yajlpp_parse_context::handle_unused) {
|
||||
fprintf(stderr, " boolean\n");
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " boolean");
|
||||
}
|
||||
if (ypc->ypc_callbacks.yajl_integer != (int (*)(void *, long long))yajlpp_parse_context::handle_unused) {
|
||||
fprintf(stderr, " integer\n");
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " integer");
|
||||
}
|
||||
if (ypc->ypc_callbacks.yajl_double != (int (*)(void *, double))yajlpp_parse_context::handle_unused) {
|
||||
fprintf(stderr, " float\n");
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " float");
|
||||
}
|
||||
if (ypc->ypc_callbacks.yajl_string != (int (*)(void *, const unsigned char *, size_t))yajlpp_parse_context::handle_unused) {
|
||||
fprintf(stderr, " string\n");
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " string");
|
||||
}
|
||||
|
||||
if (handler == NULL) {
|
||||
if (handler == nullptr) {
|
||||
const json_path_handler_base *accepted_handlers;
|
||||
|
||||
if (ypc->ypc_sibling_handlers) {
|
||||
@ -755,9 +798,9 @@ int yajlpp_parse_context::handle_unused(void *ctx)
|
||||
accepted_handlers = ypc->ypc_handlers;
|
||||
}
|
||||
|
||||
fprintf(stderr, " accepted paths --\n");
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " accepted paths --");
|
||||
for (int lpc = 0; accepted_handlers[lpc].jph_path[0]; lpc++) {
|
||||
fprintf(stderr, " %s %s -- %s\n",
|
||||
ypc->report_error(LOG_LEVEL_WARNING, " %s %s -- %s",
|
||||
accepted_handlers[lpc].jph_path,
|
||||
accepted_handlers[lpc].jph_synopsis,
|
||||
accepted_handlers[lpc].jph_description);
|
||||
|
101
src/yajlpp.hh
101
src/yajlpp.hh
@ -37,8 +37,10 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
@ -103,6 +105,27 @@ struct yajlpp_provider_context {
|
||||
};
|
||||
};
|
||||
|
||||
class yajlpp_error : public std::exception {
|
||||
public:
|
||||
yajlpp_error(yajl_handle handle, const char *json, size_t len) {
|
||||
auto_mem<unsigned char> yajl_msg;
|
||||
|
||||
yajl_msg = yajl_get_error(handle, 1, (const unsigned char *) json, len);
|
||||
this->msg = (const char *) yajl_msg.in();
|
||||
}
|
||||
|
||||
~yajlpp_error() override {
|
||||
|
||||
}
|
||||
|
||||
const char *what() const noexcept override {
|
||||
return this->msg.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
struct json_path_handler_base {
|
||||
typedef std::pair<const char *, int> enum_value_t;
|
||||
|
||||
@ -147,6 +170,7 @@ struct json_path_handler_base {
|
||||
json_path_handler_base *jph_children;
|
||||
bool jph_kv_pair;
|
||||
std::shared_ptr<pcrepp> jph_pattern;
|
||||
const char * jph_pattern_re{nullptr};
|
||||
size_t jph_min_length;
|
||||
size_t jph_max_length;
|
||||
const enum_value_t *jph_enum_values;
|
||||
@ -275,7 +299,8 @@ struct json_path_handler : public json_path_handler_base {
|
||||
}
|
||||
|
||||
json_path_handler &with_pattern(const char *re) {
|
||||
this->jph_pattern.reset(new pcrepp(re));
|
||||
this->jph_pattern_re = re;
|
||||
this->jph_pattern = std::make_shared<pcrepp>(re);
|
||||
return *this;
|
||||
};
|
||||
|
||||
@ -387,20 +412,13 @@ struct json_path_handler : public json_path_handler_base {
|
||||
class yajlpp_parse_context {
|
||||
public:
|
||||
typedef void (*error_reporter_t)(const yajlpp_parse_context &ypc,
|
||||
lnav_log_level_t level,
|
||||
const char *msg);
|
||||
|
||||
yajlpp_parse_context(const std::string &source,
|
||||
struct json_path_handler *handlers = NULL)
|
||||
: ypc_source(source),
|
||||
ypc_line_number(1),
|
||||
ypc_handlers(handlers),
|
||||
ypc_userdata(NULL),
|
||||
ypc_handle(NULL),
|
||||
ypc_json_text(NULL),
|
||||
ypc_ignore_unused(false),
|
||||
ypc_sibling_handlers(nullptr),
|
||||
ypc_current_handler(nullptr),
|
||||
ypc_error_reporter(nullptr)
|
||||
yajlpp_parse_context(std::string source,
|
||||
struct json_path_handler *handlers = nullptr)
|
||||
: ypc_source(std::move(source)),
|
||||
ypc_handlers(handlers)
|
||||
{
|
||||
this->ypc_path.reserve(4096);
|
||||
this->ypc_path.push_back('\0');
|
||||
@ -422,7 +440,7 @@ public:
|
||||
else {
|
||||
end = this->ypc_path.size() - 1;
|
||||
}
|
||||
if (this->ypc_handlers != NULL) {
|
||||
if (this->ypc_handlers) {
|
||||
len_out = json_ptr::decode(frag_in, &this->ypc_path[start], end - start);
|
||||
retval = frag_in;
|
||||
}
|
||||
@ -495,15 +513,15 @@ public:
|
||||
this->ypc_path.push_back('\0');
|
||||
this->ypc_path_index_stack.clear();
|
||||
this->ypc_array_index.clear();
|
||||
if (jph.jph_callbacks.yajl_null != NULL)
|
||||
if (jph.jph_callbacks.yajl_null != nullptr)
|
||||
this->ypc_callbacks.yajl_null = jph.jph_callbacks.yajl_null;
|
||||
if (jph.jph_callbacks.yajl_boolean != NULL)
|
||||
if (jph.jph_callbacks.yajl_boolean != nullptr)
|
||||
this->ypc_callbacks.yajl_boolean = jph.jph_callbacks.yajl_boolean;
|
||||
if (jph.jph_callbacks.yajl_integer != NULL)
|
||||
if (jph.jph_callbacks.yajl_integer != nullptr)
|
||||
this->ypc_callbacks.yajl_integer = jph.jph_callbacks.yajl_integer;
|
||||
if (jph.jph_callbacks.yajl_double != NULL)
|
||||
if (jph.jph_callbacks.yajl_double != nullptr)
|
||||
this->ypc_callbacks.yajl_double = jph.jph_callbacks.yajl_double;
|
||||
if (jph.jph_callbacks.yajl_string != NULL)
|
||||
if (jph.jph_callbacks.yajl_string != nullptr)
|
||||
this->ypc_callbacks.yajl_string = jph.jph_callbacks.yajl_string;
|
||||
}
|
||||
|
||||
@ -559,38 +577,38 @@ public:
|
||||
return yajl_complete_parse(this->ypc_handle);
|
||||
};
|
||||
|
||||
void report_error(const char *format, ...) {
|
||||
void report_error(lnav_log_level_t level, const char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
if (this->ypc_error_reporter != NULL) {
|
||||
if (this->ypc_error_reporter) {
|
||||
char buffer[1024];
|
||||
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
|
||||
this->ypc_error_reporter(*this, buffer);
|
||||
this->ypc_error_reporter(*this, level, buffer);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
const std::string ypc_source;
|
||||
int ypc_line_number;
|
||||
int ypc_line_number{1};
|
||||
struct json_path_handler *ypc_handlers;
|
||||
void * ypc_userdata;
|
||||
void * ypc_userdata{nullptr};
|
||||
std::stack<void *> ypc_obj_stack;
|
||||
yajl_handle ypc_handle;
|
||||
const unsigned char * ypc_json_text;
|
||||
yajl_handle ypc_handle{nullptr};
|
||||
const unsigned char * ypc_json_text{nullptr};
|
||||
yajl_callbacks ypc_callbacks;
|
||||
yajl_callbacks ypc_alt_callbacks;
|
||||
std::vector<char> ypc_path;
|
||||
std::vector<size_t> ypc_path_index_stack;
|
||||
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;
|
||||
bool ypc_ignore_unused{false};
|
||||
const struct json_path_handler_base *ypc_sibling_handlers{nullptr};
|
||||
const struct json_path_handler_base *ypc_current_handler{nullptr};
|
||||
std::set<std::string> ypc_active_paths;
|
||||
error_reporter_t ypc_error_reporter;
|
||||
error_reporter_t ypc_error_reporter{nullptr};
|
||||
|
||||
void update_callbacks(const json_path_handler_base *handlers = NULL,
|
||||
int child_start = 0);
|
||||
@ -738,4 +756,27 @@ struct json_string {
|
||||
size_t js_len;
|
||||
};
|
||||
|
||||
class yajlpp_gen {
|
||||
public:
|
||||
yajlpp_gen() : yg_handle(yajl_gen_free) {
|
||||
this->yg_handle = yajl_gen_alloc(NULL);
|
||||
};
|
||||
|
||||
operator yajl_gen_t *() {
|
||||
return this->yg_handle.in();
|
||||
};
|
||||
|
||||
string_fragment to_string_fragment() {
|
||||
const unsigned char *buf;
|
||||
size_t len;
|
||||
|
||||
yajl_gen_get_buf(this->yg_handle.in(), &buf, &len);
|
||||
|
||||
return string_fragment((const char *) buf, 0, len);
|
||||
};
|
||||
|
||||
private:
|
||||
auto_mem<yajl_gen_t> yg_handle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
include_directories(../../lbuild/src ../src/ /opt/local/include)
|
||||
include_directories(../../lbuild-debug/src ../src/ /opt/local/include)
|
||||
|
||||
add_executable(lnav_doctests
|
||||
lnav_doctests.cc
|
||||
@ -13,14 +13,14 @@ add_executable(test_reltime test_reltime.cc
|
||||
../src/lnav_log.cc)
|
||||
add_executable(test_date_time_scanner test_date_time_scanner.cc
|
||||
../src/lnav_util.cc
|
||||
../../lbuild/src/time_fmts.cc
|
||||
../../lbuild-debug/src/time_fmts.cc
|
||||
../src/ptimec_rt.cc
|
||||
../src/pcrepp.cc
|
||||
../src/lnav_log.cc
|
||||
../src/spookyhash/SpookyV2.cpp)
|
||||
add_executable(test_abbrev test_abbrev.cc
|
||||
../src/lnav_util.cc
|
||||
../../lbuild/src/time_fmts.cc
|
||||
../../lbuild-debug/src/time_fmts.cc
|
||||
../src/ptimec_rt.cc
|
||||
../src/pcrepp.cc
|
||||
../src/lnav_log.cc
|
||||
|
@ -239,6 +239,7 @@ dist_noinst_SCRIPTS = \
|
||||
test_line_buffer.sh \
|
||||
test_listview.sh \
|
||||
test_logfile.sh \
|
||||
test_meta.sh \
|
||||
test_mvwattrline.sh \
|
||||
test_scripts.sh \
|
||||
test_sessions.sh \
|
||||
@ -376,6 +377,7 @@ TESTS = \
|
||||
test_line_buffer2 \
|
||||
test_line_buffer.sh \
|
||||
test_listview.sh \
|
||||
test_meta.sh \
|
||||
test_grep_proc.sh \
|
||||
test_grep_proc2 \
|
||||
test_hist_source \
|
||||
|
@ -40,17 +40,18 @@
|
||||
|
||||
#include "grep_proc.hh"
|
||||
#include "line_buffer.hh"
|
||||
#include "listview_curses.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class my_source : public grep_proc_source {
|
||||
class my_source : public grep_proc_source<vis_line_t> {
|
||||
|
||||
public:
|
||||
my_source(auto_fd &fd) : ms_offset(0) {
|
||||
this->ms_buffer.set_fd(fd);
|
||||
};
|
||||
|
||||
bool grep_value_for_line(int line_number, string &value_out) {
|
||||
bool grep_value_for_line(vis_line_t line_number, string &value_out) {
|
||||
bool retval = false;
|
||||
|
||||
try {
|
||||
@ -77,27 +78,27 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class my_sink : public grep_proc_sink {
|
||||
class my_sink : public grep_proc_sink<vis_line_t> {
|
||||
|
||||
public:
|
||||
my_sink() : ms_finished(false) { };
|
||||
|
||||
void grep_match(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
void grep_match(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end) {
|
||||
printf("%d:%d:%d\n", (int)line, start, end);
|
||||
};
|
||||
|
||||
void grep_capture(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
void grep_capture(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end,
|
||||
char *capture) {
|
||||
fprintf(stderr, "%d(%d:%d)%s\n", (int)line, start, end, capture);
|
||||
};
|
||||
|
||||
void grep_end(grep_proc &gp) {
|
||||
void grep_end(grep_proc<vis_line_t> &gp) {
|
||||
this->ms_finished = true;
|
||||
};
|
||||
|
||||
@ -131,11 +132,11 @@ int main(int argc, char *argv[])
|
||||
my_source ms(fd);
|
||||
my_sink msink;
|
||||
|
||||
grep_proc gp(code, ms);
|
||||
grep_proc<vis_line_t> gp(code, ms);
|
||||
|
||||
gp.set_sink(&msink);
|
||||
gp.queue_request();
|
||||
gp.start();
|
||||
gp.set_sink(&msink);
|
||||
|
||||
while (!msink.ms_finished) {
|
||||
vector<struct pollfd> pollfds;
|
||||
|
@ -50,14 +50,14 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
class my_source : public grep_proc_source {
|
||||
class my_source : public grep_proc_source<vis_line_t> {
|
||||
|
||||
public:
|
||||
my_source(auto_fd &fd) : ms_offset(0) {
|
||||
this->ms_buffer.set_fd(fd);
|
||||
};
|
||||
|
||||
bool grep_value_for_line(int line_number, string &value_out) {
|
||||
bool grep_value_for_line(vis_line_t line_number, string &value_out) {
|
||||
bool retval = false;
|
||||
|
||||
try {
|
||||
@ -131,11 +131,11 @@ int main(int argc, char *argv[])
|
||||
vis_bookmarks bm;
|
||||
sequence_sink ss(sm, bm[&SEQUENCE]);
|
||||
|
||||
grep_proc gp(code, ms);
|
||||
grep_proc<vis_line_t> gp(code, ms);
|
||||
|
||||
gp.set_sink(&ss);
|
||||
gp.queue_request();
|
||||
gp.start();
|
||||
gp.set_sink(&ss);
|
||||
|
||||
while (bm[&SEQUENCE].size() == 0) {
|
||||
vector<struct pollfd> pollfds;
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "lnav.hh"
|
||||
#include "auto_mem.hh"
|
||||
#include "sqlite-extension-func.hh"
|
||||
@ -46,14 +48,17 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
auto_mem<sqlite3> db(sqlite3_close);
|
||||
std::string stmt;
|
||||
|
||||
log_argv(argc, argv);
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "error: expecting an SQL statement\n");
|
||||
retval = EXIT_FAILURE;
|
||||
if (argc == 2) {
|
||||
stmt = argv[1];
|
||||
} else {
|
||||
std::getline(std::cin, stmt, '\0');
|
||||
}
|
||||
else if (sqlite3_open(":memory:", db.out()) != SQLITE_OK) {
|
||||
|
||||
if (sqlite3_open(":memory:", db.out()) != SQLITE_OK) {
|
||||
fprintf(stderr, "error: unable to make sqlite memory database\n");
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
@ -73,7 +78,7 @@ int main(int argc, char *argv[])
|
||||
register_regexp_vtab(db.in());
|
||||
|
||||
if (sqlite3_exec(db.in(),
|
||||
argv[1],
|
||||
stmt.c_str(),
|
||||
sql_callback,
|
||||
&state,
|
||||
errmsg.out()) != SQLITE_OK) {
|
||||
|
@ -472,11 +472,32 @@ COMMANDS
|
||||
relative-goto <line#|N%>
|
||||
Move the current view up or down by the given amount.
|
||||
|
||||
next-mark error|warning|search|user|file|partition
|
||||
comment <message>
|
||||
Add a comment to the top line in the log view. The
|
||||
comment will be saved in the session and will be available
|
||||
the next time the file is loaded. Searches will also scan
|
||||
the comment for any matches.
|
||||
|
||||
clear-comment Clear the comment that is attached to the top line in the
|
||||
log view.
|
||||
|
||||
tag <tag1> [<tag2> [... <tagN>]]
|
||||
Attach a tag to the top line in the log view. The tags are
|
||||
prefixed with a '#', if they don't have one already. And,
|
||||
like comments, they are saved in the session and
|
||||
searchable.
|
||||
|
||||
untag <tag1> [<tag2> [... <tagN>]]
|
||||
Detach a tag from the top line in the log view.
|
||||
|
||||
delete-tags <tag1> [<tag2> [... <tagN>]]
|
||||
Detach the tags from all log lines.
|
||||
|
||||
next-mark error|warning|search|user|file|meta
|
||||
Move to the next bookmark of the given type in the
|
||||
current view.
|
||||
|
||||
prev-mark error|warning|search|user|file|partition
|
||||
prev-mark error|warning|search|user|file|meta
|
||||
Move to the previous bookmark of the given type in the
|
||||
current view.
|
||||
|
||||
@ -937,7 +958,8 @@ Synopsis
|
||||
abs(x) -- Return the absolute value of the argument
|
||||
Parameter
|
||||
x The number to convert
|
||||
|
||||
See Also
|
||||
avg(), max(), min(), round(), sum(), total()
|
||||
Example
|
||||
#1 ;SELECT abs(-1)
|
||||
|
||||
@ -947,7 +969,8 @@ Synopsis
|
||||
avg(X) -- Returns the average value of all non-NULL numbers within a group.
|
||||
Parameter
|
||||
X The value to compute the average of.
|
||||
|
||||
See Also
|
||||
abs(), max(), min(), round(), sum(), total()
|
||||
Examples
|
||||
#1 ;SELECT avg(ex_duration) FROM lnav_example_log
|
||||
|
||||
@ -961,7 +984,8 @@ Synopsis
|
||||
basename(path) -- Extract the base portion of a pathname.
|
||||
Parameter
|
||||
path The path
|
||||
|
||||
See Also
|
||||
dirname(), joinpath(), readlink(), realpath()
|
||||
Examples
|
||||
#1 ;SELECT basename('foobar')
|
||||
|
||||
@ -995,7 +1019,10 @@ Synopsis
|
||||
unicode code point values
|
||||
Parameter
|
||||
X The unicode code point values
|
||||
|
||||
See Also
|
||||
endswith(), extract(), group_concat(), instr(), leftstr(), length(), lower(),
|
||||
ltrim(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Example
|
||||
#1 ;SELECT char(0x48, 0x49)
|
||||
|
||||
@ -1033,7 +1060,8 @@ Synopsis
|
||||
Parameters
|
||||
timestring The string to convert to a date.
|
||||
modifier A transformation that is applied to the value to the left.
|
||||
|
||||
See Also
|
||||
datetime(), julianday(), strftime(), time(), timediff(), timeslice()
|
||||
Examples
|
||||
#1 ;SELECT date('2017-01-02T03:04:05')
|
||||
|
||||
@ -1051,7 +1079,8 @@ Synopsis
|
||||
Parameters
|
||||
timestring The string to convert to a date with time.
|
||||
modifier A transformation that is applied to the value to the left.
|
||||
|
||||
See Also
|
||||
date(), julianday(), strftime(), time(), timediff(), timeslice()
|
||||
Examples
|
||||
#1 ;SELECT datetime('2017-01-02T03:04:05')
|
||||
|
||||
@ -1067,7 +1096,8 @@ Synopsis
|
||||
dirname(path) -- Extract the directory portion of a pathname.
|
||||
Parameter
|
||||
path The path
|
||||
|
||||
See Also
|
||||
basename(), joinpath(), readlink(), realpath()
|
||||
Examples
|
||||
#1 ;SELECT dirname('foo/bar')
|
||||
|
||||
@ -1090,7 +1120,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to test
|
||||
suffix The suffix to check in the string
|
||||
|
||||
See Also
|
||||
char(), extract(), group_concat(), instr(), leftstr(), length(), lower(),
|
||||
ltrim(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT endswith('notbad.jpg', '.jpg')
|
||||
|
||||
@ -1103,7 +1136,10 @@ Synopsis
|
||||
extract(str) -- Automatically Parse and extract data from a string
|
||||
Parameter
|
||||
str The string to parse
|
||||
|
||||
See Also
|
||||
char(), endswith(), group_concat(), instr(), leftstr(), length(), lower(),
|
||||
ltrim(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT extract('foo=1 bar=2 name="Rolo Tomassi"')
|
||||
|
||||
@ -1116,7 +1152,8 @@ Synopsis
|
||||
gethostbyaddr(hostname) -- Get the IP address for the given hostname
|
||||
Parameter
|
||||
hostname The DNS hostname to lookup.
|
||||
|
||||
See Also
|
||||
gethostbyname()
|
||||
Example
|
||||
#1 ;SELECT gethostbyaddr('127.0.0.1')
|
||||
|
||||
@ -1126,7 +1163,8 @@ Synopsis
|
||||
gethostbyname(hostname) -- Get the IP address for the given hostname
|
||||
Parameter
|
||||
hostname The DNS hostname to lookup.
|
||||
|
||||
See Also
|
||||
gethostbyaddr()
|
||||
Example
|
||||
#1 ;SELECT gethostbyname('localhost')
|
||||
|
||||
@ -1149,7 +1187,10 @@ Synopsis
|
||||
Parameters
|
||||
X The value to concatenate.
|
||||
sep The separator to place between the values.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), instr(), leftstr(), length(), lower(), ltrim(),
|
||||
printf(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
|
||||
rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT group_concat(ex_procname) FROM lnav_example_log
|
||||
|
||||
@ -1191,7 +1232,10 @@ Synopsis
|
||||
Parameters
|
||||
haystack The string to search within
|
||||
needle The string to look for in the haystack
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), leftstr(), length(), lower(),
|
||||
ltrim(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Example
|
||||
#1 ;SELECT instr('abc', 'b')
|
||||
|
||||
@ -1202,7 +1246,8 @@ Synopsis
|
||||
Parameters
|
||||
json The JSON object to query.
|
||||
ptr The JSON-Pointer to lookup in the object.
|
||||
|
||||
See Also
|
||||
json_contains()
|
||||
Examples
|
||||
#1 ;SELECT jget('1', '')
|
||||
|
||||
@ -1217,7 +1262,8 @@ Parameter
|
||||
path One or more path components to join together. If an argument starts
|
||||
with a forward or backward slash, it will be considered an absolute
|
||||
path and any preceding elements will be ignored.
|
||||
|
||||
See Also
|
||||
basename(), dirname(), readlink(), realpath()
|
||||
Examples
|
||||
#1 ;SELECT joinpath('foo', 'bar')
|
||||
|
||||
@ -1232,13 +1278,29 @@ Examples
|
||||
|
||||
|
||||
|
||||
Synopsis
|
||||
json_contains(json, value) --
|
||||
Parameters
|
||||
json The JSON value to query.
|
||||
value The value to look for in the first argument
|
||||
See Also
|
||||
jget()
|
||||
Examples
|
||||
#1 ;SELECT json_contains('[1, 2, 3]', 4)
|
||||
|
||||
|
||||
#2 ;SELECT json_contains('["abc", "def"]', 'def')
|
||||
|
||||
|
||||
|
||||
Synopsis
|
||||
julianday(timestring, modifier, ...) -- Returns the number of days since noon
|
||||
in Greenwich on November 24, 4714 B.C.
|
||||
Parameters
|
||||
timestring The string to convert to a date with time.
|
||||
modifier A transformation that is applied to the value to the left.
|
||||
|
||||
See Also
|
||||
date(), datetime(), strftime(), time(), timediff(), timeslice()
|
||||
Examples
|
||||
#1 ;SELECT julianday('2017-01-02T03:04:05')
|
||||
|
||||
@ -1261,7 +1323,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to return subset.
|
||||
N The number of characters from the left side of the string to return.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), length(), lower(),
|
||||
ltrim(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT leftstr('abc', 1)
|
||||
|
||||
@ -1275,7 +1340,10 @@ Synopsis
|
||||
string prior to the first NUL character
|
||||
Parameter
|
||||
str The string to determine the length of
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), lower(),
|
||||
ltrim(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Example
|
||||
#1 ;SELECT length('abc')
|
||||
|
||||
@ -1334,7 +1402,10 @@ Synopsis
|
||||
converted to lower case.
|
||||
Parameter
|
||||
str The string to convert.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
ltrim(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Example
|
||||
#1 ;SELECT lower('AbC')
|
||||
|
||||
@ -1347,7 +1418,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to trim characters from the left side
|
||||
chars The characters to trim. Defaults to spaces.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), printf(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT ltrim(' abc')
|
||||
|
||||
@ -1362,7 +1436,8 @@ Synopsis
|
||||
Parameter
|
||||
X The numbers to find the maximum of. If only one argument is given, this
|
||||
function operates as an aggregate.
|
||||
|
||||
See Also
|
||||
abs(), avg(), min(), round(), sum(), total()
|
||||
Examples
|
||||
#1 ;SELECT max(2, 1, 3)
|
||||
|
||||
@ -1377,7 +1452,8 @@ Synopsis
|
||||
Parameter
|
||||
X The numbers to find the minimum of. If only one argument is given, this
|
||||
function operates as an aggregate.
|
||||
|
||||
See Also
|
||||
abs(), avg(), max(), round(), sum(), total()
|
||||
Examples
|
||||
#1 ;SELECT min(2, 1, 3)
|
||||
|
||||
@ -1408,7 +1484,10 @@ Synopsis
|
||||
Parameters
|
||||
format The format of the string to return.
|
||||
X The argument to substitute at a given position in the format.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), regexp_match(), regexp_replace(), replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT printf('Hello, %s!', 'World')
|
||||
|
||||
@ -1449,14 +1528,16 @@ Synopsis
|
||||
readlink(path) -- Read the target of a symbolic link.
|
||||
Parameter
|
||||
path The path to the symbolic link.
|
||||
|
||||
See Also
|
||||
basename(), dirname(), joinpath(), realpath()
|
||||
|
||||
Synopsis
|
||||
realpath(path) -- Returns the resolved version of the given path, expanding
|
||||
symbolic links and resolving '.' and '..' references.
|
||||
Parameter
|
||||
path The path to resolve.
|
||||
|
||||
See Also
|
||||
basename(), dirname(), joinpath(), readlink()
|
||||
|
||||
Synopsis
|
||||
regexp(re, str) -- Test if a string matches a regular expression
|
||||
@ -1471,7 +1552,11 @@ Synopsis
|
||||
Parameters
|
||||
re The regular expression to use
|
||||
str The string to test against the regular expression
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_replace(), regexp_replace(), replace(),
|
||||
replicate(), reverse(), rightstr(), rtrim(), startswith(), substr(), trim(),
|
||||
upper()
|
||||
Examples
|
||||
#1 ;SELECT regexp_match('(\d+)', '123')
|
||||
|
||||
@ -1491,7 +1576,11 @@ Parameters
|
||||
re The regular expression to match
|
||||
repl The replacement string. You can reference capture groups with a
|
||||
backslash followed by the number of the group, starting with 1.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_match(), replace(),
|
||||
replicate(), reverse(), rightstr(), rtrim(), startswith(), substr(), trim(),
|
||||
upper()
|
||||
Examples
|
||||
#1 ;SELECT regexp_replace('Hello, World!', '^(\w+)', 'Goodbye')
|
||||
|
||||
@ -1508,7 +1597,10 @@ Parameters
|
||||
str The string to perform substitutions on.
|
||||
old The string to be replaced.
|
||||
replacement The string to replace any occurrences of the old string with.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replicate(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT replace('abc', 'x', 'z')
|
||||
|
||||
@ -1522,7 +1614,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to replicate.
|
||||
N The number of times to replicate the string.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
reverse(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Example
|
||||
#1 ;SELECT replicate('abc', 3)
|
||||
|
||||
@ -1532,7 +1627,10 @@ Synopsis
|
||||
reverse(str) -- Returns the reverse of the given string.
|
||||
Parameter
|
||||
str The string to reverse.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
replicate(), rightstr(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Example
|
||||
#1 ;SELECT reverse('abc')
|
||||
|
||||
@ -1544,7 +1642,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to return subset.
|
||||
N The number of characters from the right side of the string to return.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
replicate(), reverse(), rtrim(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT rightstr('abc', 1)
|
||||
|
||||
@ -1559,7 +1660,8 @@ Synopsis
|
||||
Parameters
|
||||
num The value to round.
|
||||
digits The number of digits to the right of the decimal to round to.
|
||||
|
||||
See Also
|
||||
abs(), avg(), max(), min(), sum(), total()
|
||||
Examples
|
||||
#1 ;SELECT round(123.456)
|
||||
|
||||
@ -1578,7 +1680,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to trim characters from the right side
|
||||
chars The characters to trim. Defaults to spaces.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
replicate(), reverse(), rightstr(), startswith(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT ltrim('abc ')
|
||||
|
||||
@ -1620,7 +1725,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to test
|
||||
prefix The prefix to check in the string
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
replicate(), reverse(), rightstr(), rtrim(), substr(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT startswith('foobar', 'foo')
|
||||
|
||||
@ -1637,7 +1745,8 @@ Parameters
|
||||
strftime() standard C library.
|
||||
timestring The string to convert to a date with time.
|
||||
modifier A transformation that is applied to the value to the left.
|
||||
|
||||
See Also
|
||||
date(), datetime(), julianday(), time(), timediff(), timeslice()
|
||||
Examples
|
||||
#1 ;SELECT strftime('%Y', '2017-01-02T03:04:05')
|
||||
|
||||
@ -1660,7 +1769,10 @@ Parameters
|
||||
size The size of the substring. If not given, then all characters through
|
||||
the end of the string are returned. If the value is negative, then
|
||||
the characters before the start are returned.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
replicate(), reverse(), rightstr(), rtrim(), startswith(), trim(), upper()
|
||||
Examples
|
||||
#1 ;SELECT substr('abc', 2)
|
||||
|
||||
@ -1679,7 +1791,8 @@ Synopsis
|
||||
sum(X) -- Returns the sum of the values in the group as an integer.
|
||||
Parameter
|
||||
X The values to add.
|
||||
|
||||
See Also
|
||||
abs(), avg(), max(), min(), round(), total()
|
||||
Example
|
||||
#1 ;SELECT sum(ex_duration) FROM lnav_example_log
|
||||
|
||||
@ -1691,7 +1804,8 @@ Synopsis
|
||||
Parameters
|
||||
timestring The string to convert to a time.
|
||||
modifier A transformation that is applied to the value to the left.
|
||||
|
||||
See Also
|
||||
date(), datetime(), julianday(), strftime(), timediff(), timeslice()
|
||||
Examples
|
||||
#1 ;SELECT time('2017-01-02T03:04:05')
|
||||
|
||||
@ -1708,7 +1822,8 @@ Synopsis
|
||||
Parameters
|
||||
time1 The first timestamp
|
||||
time2 The timestamp to subtract from the first
|
||||
|
||||
See Also
|
||||
date(), datetime(), julianday(), strftime(), time(), timeslice()
|
||||
Examples
|
||||
#1 ;SELECT timediff('2017-02-03T04:05:06', '2017-02-03T04:05:00')
|
||||
|
||||
@ -1723,7 +1838,8 @@ Synopsis
|
||||
Parameters
|
||||
time The timestamp to get the time slice for.
|
||||
slice The size of the time slices
|
||||
|
||||
See Also
|
||||
date(), datetime(), julianday(), strftime(), time(), timediff()
|
||||
Examples
|
||||
#1 ;SELECT timeslice('2017-01-01T05:05:00', '10m')
|
||||
|
||||
@ -1737,7 +1853,8 @@ Synopsis
|
||||
total(X) -- Returns the sum of the values in the group as a floating-point.
|
||||
Parameter
|
||||
X The values to add.
|
||||
|
||||
See Also
|
||||
abs(), avg(), max(), min(), round(), sum()
|
||||
Example
|
||||
#1 ;SELECT total(ex_duration) FROM lnav_example_log
|
||||
|
||||
@ -1755,7 +1872,10 @@ Synopsis
|
||||
Parameters
|
||||
str The string to trim characters from the left and right sides.
|
||||
chars The characters to trim. Defaults to spaces.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
replicate(), reverse(), rightstr(), rtrim(), startswith(), substr(), upper()
|
||||
Examples
|
||||
#1 ;SELECT trim(' abc ')
|
||||
|
||||
@ -1800,7 +1920,10 @@ Synopsis
|
||||
converted to upper case.
|
||||
Parameter
|
||||
str The string to convert.
|
||||
|
||||
See Also
|
||||
char(), endswith(), extract(), group_concat(), instr(), leftstr(), length(),
|
||||
lower(), ltrim(), printf(), regexp_match(), regexp_replace(), replace(),
|
||||
replicate(), reverse(), rightstr(), rtrim(), startswith(), substr(), trim()
|
||||
Example
|
||||
#1 ;SELECT upper('aBc')
|
||||
|
||||
@ -1843,6 +1966,30 @@ Example
|
||||
|
||||
|
||||
|
||||
Synopsis
|
||||
CREATE [TEMP] VIEW [IF NOT EXISTS] [schema-name.] view-name AS select-stmt
|
||||
|
||||
Assign a name to a SELECT statement
|
||||
Parameters
|
||||
IF NOT EXISTS Do not create the view if it already exists
|
||||
schema-name. The database to create the view in
|
||||
view-name The name of the view
|
||||
select-stmt The SELECT statement the view represents
|
||||
|
||||
|
||||
Synopsis
|
||||
DELETE FROM table-name [WHERE cond]
|
||||
|
||||
Delete rows from a table
|
||||
Parameters
|
||||
table-name The name of the table
|
||||
cond The conditions used to delete the rows.
|
||||
|
||||
Example
|
||||
#1 ;SELECT * FROM syslog_log
|
||||
|
||||
|
||||
|
||||
Synopsis
|
||||
DETACH DATABASE schema-name
|
||||
|
||||
@ -1855,6 +2002,13 @@ Example
|
||||
|
||||
|
||||
|
||||
Synopsis
|
||||
DROP VIEW [IF EXISTS] [schema-name.] view-name
|
||||
|
||||
Drop a view
|
||||
Parameters
|
||||
|
||||
|
||||
Synopsis
|
||||
SELECT result-column1 [, ... result-columnN] [FROM table1 [, ... tableN]]
|
||||
[WHERE cond]
|
||||
|
@ -113,7 +113,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "include nonexistent" <<EOF
|
||||
error: unknown script -- nonexistent.lnav -- file not found
|
||||
error:command-option:1:unknown script -- nonexistent.lnav -- file not found
|
||||
EOF
|
||||
|
||||
|
||||
@ -457,6 +457,8 @@ check_output "write-json-to is not working" <<EOF
|
||||
"log_idle_msecs": 0,
|
||||
"log_level": "info",
|
||||
"log_mark": 0,
|
||||
"log_comment": null,
|
||||
"log_tags": null,
|
||||
"c_ip": "192.168.202.254",
|
||||
"cs_method": "GET",
|
||||
"cs_referer": "-",
|
||||
@ -475,6 +477,8 @@ check_output "write-json-to is not working" <<EOF
|
||||
"log_idle_msecs": 3000,
|
||||
"log_level": "error",
|
||||
"log_mark": 0,
|
||||
"log_comment": null,
|
||||
"log_tags": null,
|
||||
"c_ip": "192.168.202.254",
|
||||
"cs_method": "GET",
|
||||
"cs_referer": "-",
|
||||
@ -493,6 +497,8 @@ check_output "write-json-to is not working" <<EOF
|
||||
"log_idle_msecs": 0,
|
||||
"log_level": "info",
|
||||
"log_mark": 0,
|
||||
"log_comment": null,
|
||||
"log_tags": null,
|
||||
"c_ip": "192.168.202.254",
|
||||
"cs_method": "GET",
|
||||
"cs_referer": "-",
|
||||
|
@ -10,18 +10,18 @@ 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
|
||||
warning: unexpected path --
|
||||
warning: /invalid_key_log/value/test/identifiers
|
||||
warning: accepted paths --
|
||||
warning: kind string|integer|float|boolean|json|quoted -- The type of data in the field
|
||||
warning: collate <function> -- The collating function to use for this column
|
||||
warning: unit/ -- Unit definitions for this field
|
||||
warning: identifier <bool> -- Indicates whether or not this field contains an identifier that should be highlighted
|
||||
warning: foreign-key <bool> -- Indicates whether or not this field should be treated as a foreign key for row in another table
|
||||
warning: hidden <bool> -- Indicates whether or not this field should be hidden
|
||||
warning: action-list# <string> -- Actions to execute when this field is clicked on
|
||||
warning: rewriter <command> -- A command that will rewrite this field when pretty-printing
|
||||
warning: 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) ------^
|
||||
@ -57,13 +57,13 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_leveltest.0
|
||||
|
||||
check_output "levels are not correct?" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark
|
||||
0,<NULL>,2016-06-30 12:00:01.000,0,trace,0
|
||||
1,<NULL>,2016-06-30 12:00:02.000,1000,debug,0
|
||||
2,<NULL>,2016-06-30 12:00:03.000,1000,debug2,0
|
||||
3,<NULL>,2016-06-30 12:00:04.000,1000,debug3,0
|
||||
4,<NULL>,2016-06-30 12:00:05.000,1000,info,0
|
||||
5,<NULL>,2016-06-30 12:00:06.000,1000,warning,0
|
||||
6,<NULL>,2016-06-30 12:00:07.000,1000,fatal,0
|
||||
7,<NULL>,2016-06-30 12:00:08.000,1000,info,0
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags
|
||||
0,<NULL>,2016-06-30 12:00:01.000,0,trace,0,<NULL>,<NULL>
|
||||
1,<NULL>,2016-06-30 12:00:02.000,1000,debug,0,<NULL>,<NULL>
|
||||
2,<NULL>,2016-06-30 12:00:03.000,1000,debug2,0,<NULL>,<NULL>
|
||||
3,<NULL>,2016-06-30 12:00:04.000,1000,debug3,0,<NULL>,<NULL>
|
||||
4,<NULL>,2016-06-30 12:00:05.000,1000,info,0,<NULL>,<NULL>
|
||||
5,<NULL>,2016-06-30 12:00:06.000,1000,warning,0,<NULL>,<NULL>
|
||||
6,<NULL>,2016-06-30 12:00:07.000,1000,fatal,0,<NULL>,<NULL>
|
||||
7,<NULL>,2016-06-30 12:00:08.000,1000,info,0,<NULL>,<NULL>
|
||||
EOF
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "grep_proc.hh"
|
||||
#include "listview_curses.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -53,12 +54,12 @@ static struct {
|
||||
{ 2, "" },
|
||||
};
|
||||
|
||||
class my_source : public grep_proc_source {
|
||||
class my_source : public grep_proc_source<vis_line_t> {
|
||||
|
||||
public:
|
||||
my_source() : ms_current_line(0) { };
|
||||
|
||||
bool grep_value_for_line(int line_number, string &value_out) {
|
||||
bool grep_value_for_line(vis_line_t line_number, string &value_out) {
|
||||
bool retval = true;
|
||||
|
||||
assert(line_number == MS_LINES[this->ms_current_line].l_number);
|
||||
@ -72,32 +73,32 @@ public:
|
||||
int ms_current_line;
|
||||
};
|
||||
|
||||
class my_sleeper_source : public grep_proc_source {
|
||||
bool grep_value_for_line(int line_number, string &value_out) {
|
||||
class my_sleeper_source : public grep_proc_source<vis_line_t> {
|
||||
bool grep_value_for_line(vis_line_t line_number, string &value_out) {
|
||||
sleep(1000);
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
class my_sink : public grep_proc_sink {
|
||||
class my_sink : public grep_proc_sink<vis_line_t> {
|
||||
|
||||
public:
|
||||
my_sink() : ms_finished(false) { };
|
||||
|
||||
void grep_match(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
void grep_match(grep_proc<vis_line_t> &gp,
|
||||
vis_line_t line,
|
||||
int start,
|
||||
int end) {
|
||||
};
|
||||
|
||||
void grep_end(grep_proc &gp) {
|
||||
void grep_end(grep_proc<vis_line_t> &gp) {
|
||||
this->ms_finished = true;
|
||||
};
|
||||
|
||||
bool ms_finished;
|
||||
};
|
||||
|
||||
static void looper(grep_proc &gp)
|
||||
static void looper(grep_proc<vis_line_t> &gp)
|
||||
{
|
||||
my_sink msink;
|
||||
|
||||
@ -129,17 +130,17 @@ int main(int argc, char *argv[])
|
||||
|
||||
{
|
||||
my_source ms;
|
||||
grep_proc gp(code, ms);
|
||||
grep_proc<vis_line_t> gp(code, ms);
|
||||
|
||||
gp.queue_request(grep_line_t(10), grep_line_t(14));
|
||||
gp.queue_request(grep_line_t(0), grep_line_t(3));
|
||||
gp.queue_request(10_vl, 14_vl);
|
||||
gp.queue_request(0_vl, 3_vl);
|
||||
gp.start();
|
||||
looper(gp);
|
||||
}
|
||||
|
||||
{
|
||||
my_sleeper_source mss;
|
||||
grep_proc *gp = new grep_proc(code, mss);
|
||||
grep_proc<vis_line_t> *gp = new grep_proc<vis_line_t>(code, mss);
|
||||
int status;
|
||||
|
||||
gp->queue_request();
|
||||
|
@ -122,20 +122,20 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_json.json
|
||||
|
||||
check_output "log levels not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,user
|
||||
0,<NULL>,2013-09-06 20:00:48.124,0,trace,0,<NULL>
|
||||
1,<NULL>,2013-09-06 20:00:49.124,1000,info,0,<NULL>
|
||||
2,<NULL>,2013-09-06 22:00:49.124,7200000,info,0,steve@example.com
|
||||
4,<NULL>,2013-09-06 22:00:59.124,10000,debug5,0,<NULL>
|
||||
5,<NULL>,2013-09-06 22:00:59.124,0,debug4,0,<NULL>
|
||||
6,<NULL>,2013-09-06 22:00:59.124,0,debug3,0,<NULL>
|
||||
7,<NULL>,2013-09-06 22:00:59.124,0,debug2,0,<NULL>
|
||||
8,<NULL>,2013-09-06 22:00:59.124,0,debug,0,<NULL>
|
||||
9,<NULL>,2013-09-06 22:01:49.124,50000,stats,0,<NULL>
|
||||
10,<NULL>,2013-09-06 22:01:49.124,0,warning,0,<NULL>
|
||||
11,<NULL>,2013-09-06 22:01:49.124,0,error,0,<NULL>
|
||||
12,<NULL>,2013-09-06 22:01:49.124,0,critical,0,<NULL>
|
||||
13,<NULL>,2013-09-06 22:01:49.124,0,fatal,0,<NULL>
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,user
|
||||
0,<NULL>,2013-09-06 20:00:48.124,0,trace,0,<NULL>,<NULL>,<NULL>
|
||||
1,<NULL>,2013-09-06 20:00:49.124,1000,info,0,<NULL>,<NULL>,<NULL>
|
||||
2,<NULL>,2013-09-06 22:00:49.124,7200000,info,0,<NULL>,<NULL>,steve@example.com
|
||||
4,<NULL>,2013-09-06 22:00:59.124,10000,debug5,0,<NULL>,<NULL>,<NULL>
|
||||
5,<NULL>,2013-09-06 22:00:59.124,0,debug4,0,<NULL>,<NULL>,<NULL>
|
||||
6,<NULL>,2013-09-06 22:00:59.124,0,debug3,0,<NULL>,<NULL>,<NULL>
|
||||
7,<NULL>,2013-09-06 22:00:59.124,0,debug2,0,<NULL>,<NULL>,<NULL>
|
||||
8,<NULL>,2013-09-06 22:00:59.124,0,debug,0,<NULL>,<NULL>,<NULL>
|
||||
9,<NULL>,2013-09-06 22:01:49.124,50000,stats,0,<NULL>,<NULL>,<NULL>
|
||||
10,<NULL>,2013-09-06 22:01:49.124,0,warning,0,<NULL>,<NULL>,<NULL>
|
||||
11,<NULL>,2013-09-06 22:01:49.124,0,error,0,<NULL>,<NULL>,<NULL>
|
||||
12,<NULL>,2013-09-06 22:01:49.124,0,critical,0,<NULL>,<NULL>,<NULL>
|
||||
13,<NULL>,2013-09-06 22:01:49.124,0,fatal,0,<NULL>,<NULL>,<NULL>
|
||||
EOF
|
||||
|
||||
|
||||
@ -157,10 +157,10 @@ run_test ${lnav_test} -n -d /tmp/lnav.err \
|
||||
${test_dir}/logfile_json2.json
|
||||
|
||||
check_output "log levels not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,cl,user
|
||||
0,<NULL>,2013-09-06 20:00:49.124,0,info,0,com.exmaple.foo,<NULL>
|
||||
1,<NULL>,2013-09-06 22:00:49.124,7200000,info,0,com.exmaple.foo,steve@example.com
|
||||
3,<NULL>,2013-09-06 22:01:49.124,60000,error,0,com.exmaple.foo,<NULL>
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,cl,user
|
||||
0,<NULL>,2013-09-06 20:00:49.124,0,info,0,<NULL>,<NULL>,com.exmaple.foo,<NULL>
|
||||
1,<NULL>,2013-09-06 22:00:49.124,7200000,info,0,<NULL>,<NULL>,com.exmaple.foo,steve@example.com
|
||||
3,<NULL>,2013-09-06 22:01:49.124,60000,error,0,<NULL>,<NULL>,com.exmaple.foo,<NULL>
|
||||
EOF
|
||||
|
||||
|
||||
@ -219,20 +219,20 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_nested_json.json
|
||||
|
||||
check_output "log levels not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,@fields/user
|
||||
0,<NULL>,2013-09-06 20:00:48.124,0,trace,0,<NULL>
|
||||
2,<NULL>,2013-09-06 20:00:49.124,1000,info,0,<NULL>
|
||||
4,<NULL>,2013-09-06 22:00:49.124,7200000,info,0,steve@example.com
|
||||
7,<NULL>,2013-09-06 22:00:59.124,10000,debug5,0,<NULL>
|
||||
9,<NULL>,2013-09-06 22:00:59.124,0,debug4,0,<NULL>
|
||||
11,<NULL>,2013-09-06 22:00:59.124,0,debug3,0,<NULL>
|
||||
13,<NULL>,2013-09-06 22:00:59.124,0,debug2,0,<NULL>
|
||||
15,<NULL>,2013-09-06 22:00:59.124,0,debug,0,<NULL>
|
||||
17,<NULL>,2013-09-06 22:01:49.124,50000,stats,0,<NULL>
|
||||
19,<NULL>,2013-09-06 22:01:49.124,0,warning,0,<NULL>
|
||||
21,<NULL>,2013-09-06 22:01:49.124,0,error,0,<NULL>
|
||||
23,<NULL>,2013-09-06 22:01:49.124,0,critical,0,<NULL>
|
||||
25,<NULL>,2013-09-06 22:01:49.124,0,fatal,0,<NULL>
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,@fields/user
|
||||
0,<NULL>,2013-09-06 20:00:48.124,0,trace,0,<NULL>,<NULL>,<NULL>
|
||||
2,<NULL>,2013-09-06 20:00:49.124,1000,info,0,<NULL>,<NULL>,<NULL>
|
||||
4,<NULL>,2013-09-06 22:00:49.124,7200000,info,0,<NULL>,<NULL>,steve@example.com
|
||||
7,<NULL>,2013-09-06 22:00:59.124,10000,debug5,0,<NULL>,<NULL>,<NULL>
|
||||
9,<NULL>,2013-09-06 22:00:59.124,0,debug4,0,<NULL>,<NULL>,<NULL>
|
||||
11,<NULL>,2013-09-06 22:00:59.124,0,debug3,0,<NULL>,<NULL>,<NULL>
|
||||
13,<NULL>,2013-09-06 22:00:59.124,0,debug2,0,<NULL>,<NULL>,<NULL>
|
||||
15,<NULL>,2013-09-06 22:00:59.124,0,debug,0,<NULL>,<NULL>,<NULL>
|
||||
17,<NULL>,2013-09-06 22:01:49.124,50000,stats,0,<NULL>,<NULL>,<NULL>
|
||||
19,<NULL>,2013-09-06 22:01:49.124,0,warning,0,<NULL>,<NULL>,<NULL>
|
||||
21,<NULL>,2013-09-06 22:01:49.124,0,error,0,<NULL>,<NULL>,<NULL>
|
||||
23,<NULL>,2013-09-06 22:01:49.124,0,critical,0,<NULL>,<NULL>,<NULL>
|
||||
25,<NULL>,2013-09-06 22:01:49.124,0,fatal,0,<NULL>,<NULL>,<NULL>
|
||||
EOF
|
||||
|
||||
|
||||
@ -266,8 +266,8 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_json3.json
|
||||
|
||||
check_output "json log3 format is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,client_ip,request/method,request/size,request/uri,response/status
|
||||
0,<NULL>,2017-03-24 20:06:26.240,0,info,0,1.1.1.1,GET,166,/example/uri/5,200
|
||||
1,<NULL>,2017-03-24 20:12:47.764,381524,critical,0,1.1.1.1,GET,166,/example/uri/5,500
|
||||
2,<NULL>,2017-03-24 20:15:31.694,163930,warning,0,1.1.1.1,GET,166,/example/uri/5,400
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,client_ip,request/method,request/size,request/uri,response/status
|
||||
0,<NULL>,2017-03-24 20:06:26.240,0,info,0,<NULL>,<NULL>,1.1.1.1,GET,166,/example/uri/5,200
|
||||
1,<NULL>,2017-03-24 20:12:47.764,381524,critical,0,<NULL>,<NULL>,1.1.1.1,GET,166,/example/uri/5,500
|
||||
2,<NULL>,2017-03-24 20:15:31.694,163930,warning,0,<NULL>,<NULL>,1.1.1.1,GET,166,/example/uri/5,400
|
||||
EOF
|
||||
|
137
test/test_meta.sh
Normal file
137
test/test_meta.sh
Normal file
@ -0,0 +1,137 @@
|
||||
#! /bin/bash
|
||||
|
||||
lnav_test="${top_builddir}/src/lnav-test"
|
||||
|
||||
export HOME="./meta-sessions"
|
||||
rm -rf "./meta-sessions"
|
||||
mkdir -p $HOME
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":comment Hello, World!" \
|
||||
-c ":tag foo" \
|
||||
-c ":save-session" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output ":tag did not work?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
+ Hello, World!
|
||||
+ #foo
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":load-session" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "tag was not saved in session?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
+ Hello, World!
|
||||
+ #foo
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":load-session" \
|
||||
-c ":untag #foo" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output ":untag did not work?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
+ Hello, World!
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":load-session" \
|
||||
-c ":clear-comment" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output ":clear-comment did not work?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
+ #foo
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":goto 2" \
|
||||
-c "/foo" \
|
||||
-c ":tag #foo" \
|
||||
-c ":goto 0" \
|
||||
-c ":next-mark search" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "searching for a tag did not work?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
+ #foo
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":load-session" \
|
||||
-c ";SELECT log_line, log_comment, log_tags FROM access_log" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "metadata columns are not working?" <<EOF
|
||||
log_line log_comment log_tags
|
||||
0 Hello, World! ["#foo"]
|
||||
1 <NULL> <NULL>
|
||||
2 <NULL> <NULL>
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ";UPDATE access_log SET log_tags = json_array('#foo') WHERE log_line = 1" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "updating log_tags is not working?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
+ #foo
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ";UPDATE access_log SET log_comment = 'Hello, World!' WHERE log_line = 1" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "updating log_comment is not working?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
+ Hello, World!
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ";UPDATE access_log SET log_tags = 1 WHERE log_line = 1" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "updating log_tags is not working?" <<EOF
|
||||
error:command-option:1:command-option:line 1
|
||||
unexpected JSON value
|
||||
accepted paths --
|
||||
# <tag> -- A tag for the log line
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":tag foo" \
|
||||
-c ";UPDATE access_log SET log_tags = null" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "clearing log_tags is not working?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
-c ":comment foo" \
|
||||
-c ";UPDATE access_log SET log_comment = null" \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "clearing log_tags is not working?" <<EOF
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:26 +0000] "GET /vmw/cgi/tramp HTTP/1.0" 200 134 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkboot.gz HTTP/1.0" 404 46210 "-" "gPXE/0.9.7"
|
||||
192.168.202.254 - - [20/Jul/2009:22:59:29 +0000] "GET /vmw/vSphere/default/vmkernel.gz HTTP/1.0" 200 78929 "-" "gPXE/0.9.7"
|
||||
EOF
|
146
test/test_sql.sh
146
test/test_sql.sh
@ -34,12 +34,12 @@ run_test env TZ=UTC ${lnav_test} -n \
|
||||
${test_dir}/logfile_bro_http.log.0
|
||||
|
||||
check_output "bro logs are not recognized?" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,bro_ts,bro_uid,bro_id_orig_h,bro_id_orig_p,bro_id_resp_h,bro_id_resp_p,bro_trans_depth,bro_method,bro_host,bro_uri,bro_referrer,bro_version,bro_user_agent,bro_request_body_len,bro_response_body_len,bro_status_code,bro_status_msg,bro_info_code,bro_info_msg,bro_tags,bro_username,bro_password,bro_proxied,bro_orig_fuids,bro_orig_filenames,bro_orig_mime_types,bro_resp_fuids,bro_resp_filenames,bro_resp_mime_types
|
||||
0,<NULL>,2011-11-03 00:19:26.452,0,info,0,1320279566.452687,CwFs1P2UcUdlSxD2La,192.168.2.76,52026,132.235.215.119,80,1,GET,www.reddit.com,/,<NULL>,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,109978,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,Ftw3fJ2JJF3ntMTL2,<NULL>,text/html
|
||||
1,<NULL>,2011-11-03 00:19:26.831,379,info,0,1320279566.831619,CJxSUgkInyKSHiju1,192.168.2.76,52030,72.21.211.173,80,1,GET,e.thumbs.redditmedia.com,/E-pbDbmiBclPkDaX.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,2300,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,FFTf9Zdgk3YkfCKo3,<NULL>,image/jpeg
|
||||
2,<NULL>,2011-11-03 00:19:26.831,0,info,0,1320279566.831563,CJwUi9bdB9c1lLW44,192.168.2.76,52029,72.21.211.173,80,1,GET,f.thumbs.redditmedia.com,/BP5bQfy4o-C7cF6A.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,2272,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,FfXtOj3o7aub4vbs2j,<NULL>,image/jpeg
|
||||
3,<NULL>,2011-11-03 00:19:26.831,0,info,0,1320279566.831473,CoX7zA3OJKGUOSCBY2,192.168.2.76,52027,72.21.211.173,80,1,GET,e.thumbs.redditmedia.com,/SVUtep3Rhg5FTRn4.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,2562,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,F21Ybs3PTqS6O4Q2Zh,<NULL>,image/jpeg
|
||||
4,<NULL>,2011-11-03 00:19:26.831,0,info,0,1320279566.831643,CT0JIh479jXIGt0Po1,192.168.2.76,52031,72.21.211.173,80,1,GET,f.thumbs.redditmedia.com,/uuy31444rLSyKdHS.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,1595,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,Fdk0MZ1wQmKWAJ4WH4,<NULL>,image/jpeg
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,bro_ts,bro_uid,bro_id_orig_h,bro_id_orig_p,bro_id_resp_h,bro_id_resp_p,bro_trans_depth,bro_method,bro_host,bro_uri,bro_referrer,bro_version,bro_user_agent,bro_request_body_len,bro_response_body_len,bro_status_code,bro_status_msg,bro_info_code,bro_info_msg,bro_tags,bro_username,bro_password,bro_proxied,bro_orig_fuids,bro_orig_filenames,bro_orig_mime_types,bro_resp_fuids,bro_resp_filenames,bro_resp_mime_types
|
||||
0,<NULL>,2011-11-03 00:19:26.452,0,info,0,<NULL>,<NULL>,1320279566.452687,CwFs1P2UcUdlSxD2La,192.168.2.76,52026,132.235.215.119,80,1,GET,www.reddit.com,/,<NULL>,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,109978,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,Ftw3fJ2JJF3ntMTL2,<NULL>,text/html
|
||||
1,<NULL>,2011-11-03 00:19:26.831,379,info,0,<NULL>,<NULL>,1320279566.831619,CJxSUgkInyKSHiju1,192.168.2.76,52030,72.21.211.173,80,1,GET,e.thumbs.redditmedia.com,/E-pbDbmiBclPkDaX.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,2300,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,FFTf9Zdgk3YkfCKo3,<NULL>,image/jpeg
|
||||
2,<NULL>,2011-11-03 00:19:26.831,0,info,0,<NULL>,<NULL>,1320279566.831563,CJwUi9bdB9c1lLW44,192.168.2.76,52029,72.21.211.173,80,1,GET,f.thumbs.redditmedia.com,/BP5bQfy4o-C7cF6A.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,2272,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,FfXtOj3o7aub4vbs2j,<NULL>,image/jpeg
|
||||
3,<NULL>,2011-11-03 00:19:26.831,0,info,0,<NULL>,<NULL>,1320279566.831473,CoX7zA3OJKGUOSCBY2,192.168.2.76,52027,72.21.211.173,80,1,GET,e.thumbs.redditmedia.com,/SVUtep3Rhg5FTRn4.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,2562,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,F21Ybs3PTqS6O4Q2Zh,<NULL>,image/jpeg
|
||||
4,<NULL>,2011-11-03 00:19:26.831,0,info,0,<NULL>,<NULL>,1320279566.831643,CT0JIh479jXIGt0Po1,192.168.2.76,52031,72.21.211.173,80,1,GET,f.thumbs.redditmedia.com,/uuy31444rLSyKdHS.jpg,http://www.reddit.com/,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,1595,200,OK,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,Fdk0MZ1wQmKWAJ4WH4,<NULL>,image/jpeg
|
||||
EOF
|
||||
|
||||
run_test env TZ=UTC ${lnav_test} -n \
|
||||
@ -48,8 +48,8 @@ run_test env TZ=UTC ${lnav_test} -n \
|
||||
${test_dir}/logfile_bro_http.log.0
|
||||
|
||||
check_output "bro logs are not recognized?" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,bro_ts,bro_uid,bro_id_orig_h,bro_id_orig_p,bro_id_resp_h,bro_id_resp_p,bro_trans_depth,bro_method,bro_host,bro_uri,bro_referrer,bro_version,bro_user_agent,bro_request_body_len,bro_response_body_len,bro_status_code,bro_status_msg,bro_info_code,bro_info_msg,bro_tags,bro_username,bro_password,bro_proxied,bro_orig_fuids,bro_orig_filenames,bro_orig_mime_types,bro_resp_fuids,bro_resp_filenames,bro_resp_mime_types
|
||||
118,<NULL>,2011-11-03 00:19:49.337,18,error,0,1320279589.337053,CBHHuR1xFnm5C5CQBc,192.168.2.76,52074,74.125.225.76,80,1,GET,i4.ytimg.com,/vi/gDbg_GeuiSY/hqdefault.jpg,<NULL>,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,893,404,Not Found,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,F2GiAw3j1m22R2yIg2,<NULL>,image/jpeg
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,bro_ts,bro_uid,bro_id_orig_h,bro_id_orig_p,bro_id_resp_h,bro_id_resp_p,bro_trans_depth,bro_method,bro_host,bro_uri,bro_referrer,bro_version,bro_user_agent,bro_request_body_len,bro_response_body_len,bro_status_code,bro_status_msg,bro_info_code,bro_info_msg,bro_tags,bro_username,bro_password,bro_proxied,bro_orig_fuids,bro_orig_filenames,bro_orig_mime_types,bro_resp_fuids,bro_resp_filenames,bro_resp_mime_types
|
||||
118,<NULL>,2011-11-03 00:19:49.337,18,error,0,<NULL>,<NULL>,1320279589.337053,CBHHuR1xFnm5C5CQBc,192.168.2.76,52074,74.125.225.76,80,1,GET,i4.ytimg.com,/vi/gDbg_GeuiSY/hqdefault.jpg,<NULL>,1.1,Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1,0,893,404,Not Found,<NULL>,<NULL>,,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,<NULL>,F2GiAw3j1m22R2yIg2,<NULL>,image/jpeg
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -188,10 +188,10 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "setting log_part is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,middle,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,middle,2009-07-20 22:59:29.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,middle,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,middle,2009-07-20 22:59:29.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -202,10 +202,10 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "setting log_part is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -216,10 +216,10 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "setting log_part is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,middle,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,middle,2009-07-20 22:59:29.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,middle,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,middle,2009-07-20 22:59:29.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
EOF
|
||||
|
||||
|
||||
@ -242,10 +242,10 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "access_log table is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
EOF
|
||||
|
||||
|
||||
@ -255,8 +255,8 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "loglevel collator is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -280,11 +280,11 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_syslog.0
|
||||
|
||||
check_output "syslog_log table is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version
|
||||
0,<NULL>,2013-11-03 09:23:38.000,0,error,0,veridian,<NULL>,7998,<NULL>,automount,<NULL>,<NULL>
|
||||
1,<NULL>,2013-11-03 09:23:38.000,0,info,0,veridian,<NULL>,16442,<NULL>,automount,<NULL>,<NULL>
|
||||
2,<NULL>,2013-11-03 09:23:38.000,0,error,0,veridian,<NULL>,7999,<NULL>,automount,<NULL>,<NULL>
|
||||
3,<NULL>,2013-11-03 09:47:02.000,1404000,info,0,veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,<NULL>
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version
|
||||
0,<NULL>,2013-11-03 09:23:38.000,0,error,0,<NULL>,<NULL>,veridian,<NULL>,7998,<NULL>,automount,<NULL>,<NULL>
|
||||
1,<NULL>,2013-11-03 09:23:38.000,0,info,0,<NULL>,<NULL>,veridian,<NULL>,16442,<NULL>,automount,<NULL>,<NULL>
|
||||
2,<NULL>,2013-11-03 09:23:38.000,0,error,0,<NULL>,<NULL>,veridian,<NULL>,7999,<NULL>,automount,<NULL>,<NULL>
|
||||
3,<NULL>,2013-11-03 09:47:02.000,1404000,info,0,<NULL>,<NULL>,veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,<NULL>
|
||||
EOF
|
||||
|
||||
|
||||
@ -294,8 +294,8 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_syslog.0
|
||||
|
||||
check_output "log_time collation is wrong" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version
|
||||
3,<NULL>,2013-11-03 09:47:02.000,1404000,info,0,veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,<NULL>
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version
|
||||
3,<NULL>,2013-11-03 09:47:02.000,1404000,info,0,<NULL>,<NULL>,veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,<NULL>
|
||||
EOF
|
||||
|
||||
|
||||
@ -306,8 +306,8 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_syslog.0
|
||||
|
||||
check_output "logline table is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version,log_msg_instance,col_0,TTY,PWD,USER,COMMAND
|
||||
0,<NULL>,2013-11-03 09:47:02.000,0,info,0,veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,<NULL>,0,timstack,pts/6,/auto/wstimstack/rpms/lbuild/test,root,/usr/bin/tail /var/log/messages
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version,log_msg_instance,col_0,TTY,PWD,USER,COMMAND
|
||||
0,<NULL>,2013-11-03 09:47:02.000,0,info,0,<NULL>,<NULL>,veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,<NULL>,0,timstack,pts/6,/auto/wstimstack/rpms/lbuild/test,root,/usr/bin/tail /var/log/messages
|
||||
EOF
|
||||
|
||||
|
||||
@ -318,8 +318,8 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_syslog.1
|
||||
|
||||
check_output "logline table is not working" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version,log_msg_instance,col_0
|
||||
1,<NULL>,2006-12-03 09:23:38.000,0,info,0,veridian,<NULL>,16442,<NULL>,automount,<NULL>,<NULL>,0,/auto/opt
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,syslog_version,log_msg_instance,col_0
|
||||
1,<NULL>,2006-12-03 09:23:38.000,0,info,0,<NULL>,<NULL>,veridian,<NULL>,16442,<NULL>,automount,<NULL>,<NULL>,0,/auto/opt
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -386,7 +386,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "insert into environ table works" <<EOF
|
||||
error: A non-empty name and value must be provided when inserting an environment variable
|
||||
error:command-option:1:A non-empty name and value must be provided when inserting an environment variable
|
||||
EOF
|
||||
|
||||
check_output "insert into environ table works" <<EOF
|
||||
@ -398,7 +398,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "insert into environ table works" <<EOF
|
||||
error: A non-empty name and value must be provided when inserting an environment variable
|
||||
error:command-option:1:A non-empty name and value must be provided when inserting an environment variable
|
||||
EOF
|
||||
|
||||
check_output "insert into environ table works" <<EOF
|
||||
@ -410,7 +410,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "insert into environ table works" <<EOF
|
||||
error: A non-empty name and value must be provided when inserting an environment variable
|
||||
error:command-option:1:A non-empty name and value must be provided when inserting an environment variable
|
||||
EOF
|
||||
|
||||
check_output "insert into environ table works" <<EOF
|
||||
@ -422,7 +422,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "insert into environ table works" <<EOF
|
||||
error: Environment variable names cannot contain an equals sign (=)
|
||||
error:command-option:1:Environment variable names cannot contain an equals sign (=)
|
||||
EOF
|
||||
|
||||
check_output "insert into environ table works" <<EOF
|
||||
@ -434,7 +434,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "insert into environ table works" <<EOF
|
||||
error: An environment variable with the name 'SQL_ENV_VALUE' already exists
|
||||
error:command-option:1:An environment variable with the name 'SQL_ENV_VALUE' already exists
|
||||
EOF
|
||||
|
||||
check_output "insert into environ table works" <<EOF
|
||||
@ -557,7 +557,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "updating lnav_views.top_time with a bad time works?" <<EOF
|
||||
error: Invalid time: bad-time
|
||||
error:command-option:1:Invalid time: bad-time
|
||||
EOF
|
||||
|
||||
|
||||
@ -618,7 +618,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "errors are not reported" <<EOF
|
||||
error: no such table: nonexistent_table
|
||||
error:command-option:1:no such table: nonexistent_table
|
||||
EOF
|
||||
|
||||
check_output "errors are not reported" <<EOF
|
||||
@ -630,7 +630,7 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_error_output "errors are not reported" <<EOF
|
||||
error: attempt to write a readonly database
|
||||
error:command-option:1:attempt to write a readonly database
|
||||
EOF
|
||||
|
||||
check_output "errors are not reported" <<EOF
|
||||
@ -645,10 +645,10 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "partition-name does not work" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,middle,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,middle,2009-07-20 22:59:29.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,middle,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,middle,2009-07-20 22:59:29.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
EOF
|
||||
|
||||
|
||||
@ -661,10 +661,10 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "clear-partition does not work" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -677,10 +677,10 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_access_log.0
|
||||
|
||||
check_output "clear-partition does not work when in the middle of a part" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
0,<NULL>,2009-07-20 22:59:26.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/cgi/tramp,gPXE/0.9.7,-,HTTP/1.0,134,200
|
||||
1,<NULL>,2009-07-20 22:59:29.000,3000,error,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkboot.gz,gPXE/0.9.7,-,HTTP/1.0,46210,404
|
||||
2,<NULL>,2009-07-20 22:59:29.000,0,info,0,<NULL>,<NULL>,192.168.202.254,GET,-,<NULL>,/vmw/vSphere/default/vmkernel.gz,gPXE/0.9.7,-,HTTP/1.0,78929,200
|
||||
EOF
|
||||
|
||||
|
||||
@ -698,6 +698,8 @@ check_output "" <<EOF
|
||||
"log_idle_msecs": 0,
|
||||
"log_level": "info",
|
||||
"log_mark": 0,
|
||||
"log_comment": null,
|
||||
"log_tags": null,
|
||||
"contextid": "82e87195d704585501",
|
||||
"data": "http://localhost:8086|/|<samlp:Response xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\"s2daac0735bf476f4560aab81104b623bedfb0cbc0\" InResponseTo=\"84cbf2be33f6410bbe55877545a93f02\" Version=\"2.0\" IssueInstant=\"2014-06-15T01:04:52Z\" Destination=\"http://localhost:8086/api/1/rest/admin/org/530e42ccd6f45fd16d0d0717/saml/consume\"><saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">http://openam.vagrant.dev/openam</saml:Issuer><samlp:Status xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">\\\\n<samlp:StatusCode xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"\\\\nValue=\"urn:oasis:names:tc:SAML:2.0:status:Success\">\\\\n</samlp:StatusCode>\\\\n</samlp:Status><saml:Assertion xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"s2a0bee0da937e236167e99b209802056033816ac2\" IssueInstant=\"2014-06-15T01:04:52Z\" Version=\"2.0\">\\\\n<saml:Issuer>http://openam.vagrant.dev/openam</saml:Issuer><ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\\\\n<ds:SignedInfo>\\\\n<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\\\\n<ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/>\\\\n<ds:Reference URI=\"#s2a0bee0da937e236167e99b209802056033816ac2\">\\\\n<ds:Transforms>\\\\n<ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/>\\\\n<ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\\\\n</ds:Transforms>\\\\n<ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>\\\\n<ds:DigestValue>4uSmVzjovUdQd3px/RcnoxQBsqE=</ds:DigestValue>\\\\n</ds:Reference>\\\\n</ds:SignedInfo>\\\\n<ds:SignatureValue>\\\\nhm/grge36uA6j1OWif2bTcvVTwESjmuJa27NxepW0AiV5YlcsHDl7RAIk6k/CjsSero3bxGbm56m\\\\nYncOEi9F1Tu7dS0bfx+vhm/kKTPgwZctf4GWn4qQwP+KeoZywbNj9ShsYJ+zPKzXwN4xBSuPjMxP\\\\nNf5szzjEWpOndQO/uDs=\\\\n</ds:SignatureValue>\\\\n<ds:KeyInfo>\\\\n<ds:X509Data>\\\\n<ds:X509Certificate>\\\\nMIICQDCCAakCBEeNB0swDQYJKoZIhvcNAQEEBQAwZzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNh\\\\nbGlmb3JuaWExFDASBgNVBAcTC1NhbnRhIENsYXJhMQwwCgYDVQQKEwNTdW4xEDAOBgNVBAsTB09w\\\\nZW5TU08xDTALBgNVBAMTBHRlc3QwHhcNMDgwMTE1MTkxOTM5WhcNMTgwMTEyMTkxOTM5WjBnMQsw\\\\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLU2FudGEgQ2xhcmExDDAK\\\\nBgNVBAoTA1N1bjEQMA4GA1UECxMHT3BlblNTTzENMAsGA1UEAxMEdGVzdDCBnzANBgkqhkiG9w0B\\\\nAQEFAAOBjQAwgYkCgYEArSQc/U75GB2AtKhbGS5piiLkmJzqEsp64rDxbMJ+xDrye0EN/q1U5Of+\\\\nRkDsaN/igkAvV1cuXEgTL6RlafFPcUX7QxDhZBhsYF9pbwtMzi4A4su9hnxIhURebGEmxKW9qJNY\\\\nJs0Vo5+IgjxuEWnjnnVgHTs1+mq5QYTA7E6ZyL8CAwEAATANBgkqhkiG9w0BAQQFAAOBgQB3Pw/U\\\\nQzPKTPTYi9upbFXlrAKMwtFf2OW4yvGWWvlcwcNSZJmTJ8ARvVYOMEVNbsT4OFcfu2/PeYoAdiDA\\\\ncGy/F2Zuj8XJJpuQRSE6PtQqBuDEHjjmOQJ0rV/r8mO1ZCtHRhpZ5zYRjhRC9eCbjx9VrFax0JDC\\\\n/FfwWigmrW0Y0Q==\\\\n</ds:X509Certificate>\\\\n</ds:X509Data>\\\\n</ds:KeyInfo>\\\\n</ds:Signature><saml:Subject>\\\\n<saml:NameID Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\" NameQualifier=\"http://openam.vagrant.dev/openam\">user@example.com</saml:NameID><saml:SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\">\\\\n<saml:SubjectConfirmationData InResponseTo=\"84cbf2be33f6410bbe55877545a93f02\" NotOnOrAfter=\"2014-06-15T01:14:52Z\" Recipient=\"http://localhost:8086/api/1/rest/admin/org/530e42ccd6f45fd16d0d0717/saml/consume\"/></saml:SubjectConfirmation>\\\\n</saml:Subject><saml:Conditions NotBefore=\"2014-06-15T00:54:52Z\" NotOnOrAfter=\"2014-06-15T01:14:52Z\">\\\\n<saml:AudienceRestriction>\\\\n<saml:Audience>http://localhost:8086</saml:Audience>\\\\n</saml:AudienceRestriction>\\\\n</saml:Conditions>\\\\n<saml:AuthnStatement AuthnInstant=\"2014-06-15T01:00:25Z\" SessionIndex=\"s2f9b4d4b453d12b40ef3905cc959cdb40579c2301\"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion></samlp:Response>",
|
||||
"domain": "dc=openam",
|
||||
@ -716,6 +718,8 @@ check_output "" <<EOF
|
||||
"log_idle_msecs": 0,
|
||||
"log_level": "trace",
|
||||
"log_mark": 0,
|
||||
"log_comment": null,
|
||||
"log_tags": null,
|
||||
"contextid": "ec5708a7f199678a01",
|
||||
"data": "vagrant|/",
|
||||
"domain": "dc=openam",
|
||||
@ -767,22 +771,22 @@ EOF
|
||||
|
||||
|
||||
cat ${test_dir}/logfile_syslog.0 | run_test ${lnav_test} -n \
|
||||
-c ";select * from syslog_log where log_procname = 'automount'"
|
||||
-c ";select log_time from syslog_log where log_procname = 'automount'"
|
||||
|
||||
check_output "querying against stdin is not working?" <<EOF
|
||||
log_line log_part log_time log_idle_msecs log_level log_mark log_hostname log_msgid log_pid log_pri log_procname log_struct syslog_version
|
||||
0 <NULL> 2018-11-03 09:23:38.000 0 error 0 veridian <NULL> 7998 <NULL> automount <NULL> <NULL>
|
||||
1 <NULL> 2018-11-03 09:23:38.000 0 info 0 veridian <NULL> 16442 <NULL> automount <NULL> <NULL>
|
||||
2 <NULL> 2018-11-03 09:23:38.000 0 error 0 veridian <NULL> 7999 <NULL> automount <NULL> <NULL>
|
||||
log_time
|
||||
2018-11-03 09:23:38.000
|
||||
2018-11-03 09:23:38.000
|
||||
2018-11-03 09:23:38.000
|
||||
EOF
|
||||
|
||||
|
||||
cat ${test_dir}/logfile_syslog.0 | run_test ${lnav_test} -n \
|
||||
-c ";select * from syslog_log where log_procname = 'sudo'"
|
||||
-c ";select log_time from syslog_log where log_procname = 'sudo'"
|
||||
|
||||
check_output "single result is not working?" <<EOF
|
||||
log_line log_part log_time log_idle_msecs log_level log_mark log_hostname log_msgid log_pid log_pri log_procname log_struct syslog_version
|
||||
3 <NULL> 2018-11-03 09:47:02.000 1404000 info 0 veridian <NULL> <NULL> <NULL> sudo <NULL> <NULL>
|
||||
log_time
|
||||
2018-11-03 09:47:02.000
|
||||
EOF
|
||||
|
||||
# Create a dummy database for the next couple of tests to consume.
|
||||
@ -831,7 +835,7 @@ run_test ${lnav_test} -n \
|
||||
empty
|
||||
|
||||
check_error_output "LNAVSECURE mode bypassed" <<EOF
|
||||
error: not authorized
|
||||
error:command-option:1:not authorized
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -839,7 +843,7 @@ run_test ${lnav_test} -n \
|
||||
empty
|
||||
|
||||
check_error_output "LNAVSECURE mode bypassed (':' adorned)" <<EOF
|
||||
error: not authorized
|
||||
error:command-option:1:not authorized
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -847,7 +851,7 @@ run_test ${lnav_test} -n \
|
||||
empty
|
||||
|
||||
check_error_output "LNAVSECURE mode bypassed (filepath)" <<EOF
|
||||
error: not authorized
|
||||
error:command-option:1:not authorized
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n \
|
||||
@ -855,7 +859,7 @@ run_test ${lnav_test} -n \
|
||||
empty
|
||||
|
||||
check_error_output "LNAVSECURE mode bypassed (URI)" <<EOF
|
||||
error: not authorized
|
||||
error:command-option:1:not authorized
|
||||
EOF
|
||||
|
||||
unset LNAVSECURE
|
||||
@ -868,8 +872,8 @@ run_test ${lnav_test} -n \
|
||||
${test_dir}/logfile_syslog_with_access_log.0
|
||||
|
||||
check_output "access_log not found within syslog file" <<EOF
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
1,<NULL>,2015-03-24 14:02:50.000,6927348000,info,0,127.0.0.1,GET,<NULL>,<NULL>,/includes/js/combined-javascript.js,<NULL>,-,HTTP/1.1,65508,200
|
||||
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,c_ip,cs_method,cs_referer,cs_uri_query,cs_uri_stem,cs_user_agent,cs_username,cs_version,sc_bytes,sc_status
|
||||
1,<NULL>,2015-03-24 14:02:50.000,6927348000,info,0,<NULL>,<NULL>,127.0.0.1,GET,<NULL>,<NULL>,/includes/js/combined-javascript.js,<NULL>,-,HTTP/1.1,65508,200
|
||||
EOF
|
||||
|
||||
|
||||
|
@ -1,5 +1,57 @@
|
||||
#! /bin/bash
|
||||
|
||||
run_test ./drive_sql "select json_contains('4', 4)"
|
||||
|
||||
check_output "json_contains does not work" <<EOF
|
||||
Row 0:
|
||||
Column json_contains('4', 4): 1
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql "select json_contains('4', 2)"
|
||||
|
||||
check_output "json_contains does not work" <<EOF
|
||||
Row 0:
|
||||
Column json_contains('4', 2): 0
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql <<EOF
|
||||
select json_contains('"hi"', 'hi')
|
||||
EOF
|
||||
|
||||
check_output "json_contains does not work" <<EOF
|
||||
Row 0:
|
||||
Column json_contains('"hi"', 'hi'): 1
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql <<EOF
|
||||
select json_contains('["hi", "bye"]', 'hola') as res
|
||||
EOF
|
||||
|
||||
check_output "json_contains does not work" <<EOF
|
||||
Row 0:
|
||||
Column res: 0
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql <<EOF
|
||||
select json_contains('["hi", "bye", "solong"]', 'bye') as res
|
||||
EOF
|
||||
|
||||
check_output "json_contains does not work" <<EOF
|
||||
Row 0:
|
||||
Column res: 1
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql <<EOF
|
||||
select json_contains('["hi", "bye", "solong]', 'bye') as res
|
||||
EOF
|
||||
|
||||
check_error_output "json_contains does not work" <<EOF
|
||||
error: sqlite3_exec failed -- parse error: premature EOF
|
||||
["hi", "bye", "solong]
|
||||
(right here) ------^
|
||||
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql "select jget('4', '')"
|
||||
|
||||
check_output "jget root does not work" <<EOF
|
||||
|
Loading…
Reference in New Issue
Block a user