mirror of https://github.com/tstack/lnav.git
random fixes
This commit is contained in:
parent
815cd2adf2
commit
335dbadb22
|
@ -23,7 +23,9 @@ HELP_SRC = help.cc
|
|||
endif
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(SQLITE3_LDFLAGS)
|
||||
$(SQLITE3_LDFLAGS) \
|
||||
-pthread \
|
||||
-static
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
$(SQLITE3_CFLAGS) \
|
||||
|
|
|
@ -206,7 +206,9 @@ noinst_LIBRARIES = libdiag.a
|
|||
@HAVE_OBJCOPY_FALSE@HELP_SRC = help.cc
|
||||
@HAVE_OBJCOPY_TRUE@HELP_SRC =
|
||||
AM_LDFLAGS = \
|
||||
$(SQLITE3_LDFLAGS)
|
||||
$(SQLITE3_LDFLAGS) \
|
||||
-pthread \
|
||||
-static
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
$(SQLITE3_CFLAGS) \
|
||||
|
|
|
@ -13,6 +13,20 @@ public:
|
|||
|
||||
~db_label_source() { };
|
||||
|
||||
void hist_label_for_group(int group, std::string &label_out) {
|
||||
label_out.clear();
|
||||
for (int lpc = 0; lpc < this->dls_headers.size(); lpc++) {
|
||||
int before, total_fill =
|
||||
this->dls_column_sizes[lpc] - this->dls_headers[lpc].length();
|
||||
|
||||
before = total_fill / 2;
|
||||
total_fill -= before;
|
||||
label_out.append(before, ' ');
|
||||
label_out.append(this->dls_headers[lpc]);
|
||||
label_out.append(total_fill, ' ');
|
||||
}
|
||||
};
|
||||
|
||||
void hist_label_for_bucket(int bucket_start_value,
|
||||
const hist_source::bucket_t &bucket,
|
||||
std::string &label_out) {
|
||||
|
@ -40,7 +54,19 @@ public:
|
|||
this->dls_column_sizes[index] =
|
||||
std::max(this->dls_column_sizes[index], strlen(colstr) + 1);
|
||||
};
|
||||
|
||||
void push_header(const std::string &colstr) {
|
||||
int index = this->dls_headers.size();
|
||||
|
||||
this->dls_headers.push_back(colstr);
|
||||
if (this->dls_headers.size() > this->dls_column_sizes.size()) {
|
||||
this->dls_column_sizes.push_back(1);
|
||||
}
|
||||
this->dls_column_sizes[index] =
|
||||
std::max(this->dls_column_sizes[index], colstr.length() + 1);
|
||||
}
|
||||
|
||||
std::vector< std::string > dls_headers;
|
||||
std::vector< std::vector< std::string > > dls_rows;
|
||||
std::vector< size_t > dls_column_sizes;
|
||||
};
|
||||
|
|
|
@ -159,7 +159,7 @@ void grep_proc::start(void)
|
|||
line_value.clear();
|
||||
done = !this->gp_source.grep_value_for_line(line, line_value);
|
||||
if (!done) {
|
||||
pcre_context_static<10> pc;
|
||||
pcre_context_static<60> pc;
|
||||
pcre_input pi(line_value);
|
||||
|
||||
while (this->gp_pcre.match(pc, pi)) {
|
||||
|
@ -172,6 +172,13 @@ void grep_proc::start(void)
|
|||
m = pc.all();
|
||||
fprintf(stdout, "[%d:%d]\n", m->m_begin, m->m_end);
|
||||
for (pc_iter = pc.begin(); pc_iter != pc.end(); pc_iter++) {
|
||||
if (pc_iter->m_begin < 0) {
|
||||
/* If the capture was conditional, pcre will
|
||||
* return a -1 here.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stdout,
|
||||
"(%d:%d)",
|
||||
pc_iter->m_begin,
|
||||
|
|
68
src/help.txt
68
src/help.txt
|
@ -182,6 +182,9 @@ through the file.
|
|||
that can be used in queries. See the SQL section
|
||||
below for more information.
|
||||
|
||||
. Switch to/from the sql result view.
|
||||
|
||||
|
||||
COMMANDS
|
||||
--------
|
||||
|
||||
|
@ -233,7 +236,66 @@ COMMANDS
|
|||
write-to <file> Write any marked lines to the given file.
|
||||
|
||||
|
||||
SQL
|
||||
---
|
||||
SQL QUERIES
|
||||
-----------
|
||||
|
||||
WRITE ME
|
||||
Lnav has support for performing SQL queries on log files using the
|
||||
Sqlite3 "virtual" table feature. For all supported log file types,
|
||||
lnav will create tables that can be queried using the subset of SQL
|
||||
that is supported by Sqlite3. For example, to get the top ten URLs
|
||||
being accessed in any loaded Apache log files, you can execute:
|
||||
|
||||
;select cs_uri_stem, count(*) as total from access_log
|
||||
group by cs_uri_stem order by total desc limit 10;
|
||||
|
||||
The query result view shows the results as text and graphs any number
|
||||
values found in the result, much like the histogram view.
|
||||
|
||||
The basic set of log file tables are:
|
||||
|
||||
syslog_log, generic_log
|
||||
Contains any syslog lines and any lines picked up
|
||||
by the generic log file parser.
|
||||
|
||||
line_number The line number in the file, starting at zero.
|
||||
path The full path to the file.
|
||||
log_time The time of the log entry.
|
||||
level The log level (e.g. info, error, etc...).
|
||||
raw_line The raw line of text.
|
||||
|
||||
The following tables include the basic columns as listed above and
|
||||
include a few more columns since the log file format is more
|
||||
structured.
|
||||
|
||||
access_log Contains Apache log file lines. The column names
|
||||
are the same as those in the Microsoft LogParser.
|
||||
|
||||
c_ip The client IP address.
|
||||
cs_username The client user name.
|
||||
cs_method The HTTP method.
|
||||
cs_uri_stem The stem portion of the URI.
|
||||
cs_uri_query The query portion of the URI.
|
||||
cs_version The HTTP version string.
|
||||
sc_status The status number returned to the client.
|
||||
sc_bytes The number of bytes sent to the client.
|
||||
cs_referrer The URL of the referring page.
|
||||
cs_user_agent The user agent string.
|
||||
|
||||
strace_log Contains strace log file lines. Currently, you
|
||||
need to run strace with the "-tt -T" options.
|
||||
|
||||
funcname The name of the syscall.
|
||||
result The result code.
|
||||
duration The amount of time spent in the syscall.
|
||||
arg0 - arg9 The arguments passed to the syscall.
|
||||
|
||||
These tables are created dynamically and not stored in memory or on
|
||||
disk. If you would like to persist some information from the tables,
|
||||
you can attach another database and create tables in that database.
|
||||
For example, if you wanted to save the results from the earlier
|
||||
example of a top ten query into the "/tmp/topten.db" file, you can do:
|
||||
|
||||
;attach database "/tmp/topten.db" as topten;
|
||||
;create table topten as select cs_uri_stem, count(*) as total
|
||||
from access_log group by cs_uri_stem order by total desc
|
||||
limit 10;
|
||||
|
|
|
@ -29,6 +29,10 @@ void hist_source::text_value_for_line(textview_curses &tc,
|
|||
|
||||
tc.get_dimensions(height, width);
|
||||
value_out.insert((unsigned int)0, width, '-');
|
||||
|
||||
if (this->hs_label_source != NULL) {
|
||||
this->hs_label_source->hist_label_for_group(grow, value_out);
|
||||
}
|
||||
this->hs_token_bucket = NULL;
|
||||
}
|
||||
else {
|
||||
|
|
146
src/lnav.cc
146
src/lnav.cc
|
@ -278,8 +278,6 @@ static struct {
|
|||
|
||||
auto_ptr<grep_highlighter> ld_grep_child[LG__MAX];
|
||||
|
||||
auto_temp_file ld_db_file;
|
||||
|
||||
log_vtab_manager *ld_vtab_manager;
|
||||
session *ld_sql;
|
||||
} lnav_data;
|
||||
|
@ -1302,7 +1300,7 @@ public:
|
|||
|
||||
bool matches(string line)
|
||||
{
|
||||
static const int MATCH_COUNT = 30;
|
||||
static const int MATCH_COUNT = 20 * 3;
|
||||
int matches[MATCH_COUNT], rc;
|
||||
bool retval;
|
||||
|
||||
|
@ -1596,6 +1594,7 @@ static void rl_callback(void *dummy, readline_curses *rc)
|
|||
char buffer[128];
|
||||
|
||||
hs.clear();
|
||||
dls.dls_headers.clear();
|
||||
dls.dls_rows.clear();
|
||||
for (rowset<row>::const_iterator it = rs.begin();
|
||||
it != rs.end();
|
||||
|
@ -1608,6 +1607,7 @@ static void rl_callback(void *dummy, readline_curses *rc)
|
|||
if (!header_done) {
|
||||
fprintf(stderr, "<%s> ", props.get_name().c_str());
|
||||
fprintf(stderr, " dt %d\n", props.get_data_type());
|
||||
dls.push_header(props.get_name());
|
||||
hs.set_role_for_type(bucket_type_t(lpc),
|
||||
view_colors::singleton().
|
||||
next_highlight());
|
||||
|
@ -1682,8 +1682,9 @@ static void rl_callback(void *dummy, readline_curses *rc)
|
|||
|
||||
hs.analyze();
|
||||
lnav_data.ld_views[LNV_DB].reload_data();
|
||||
|
||||
toggle_view(&lnav_data.ld_views[LNV_DB]);
|
||||
|
||||
if (row_number > 0)
|
||||
toggle_view(&lnav_data.ld_views[LNV_DB]);
|
||||
}
|
||||
catch (soci::soci_error &e) {
|
||||
rc->set_value(e.what());
|
||||
|
@ -1778,6 +1779,7 @@ static void looper(void)
|
|||
struct timeval last_check = { 0, 0 };
|
||||
readline_context search_context;
|
||||
readline_context index_context;
|
||||
readline_context sql_context;
|
||||
textview_curses *tc;
|
||||
readline_curses rlc;
|
||||
int lpc;
|
||||
|
@ -1788,7 +1790,7 @@ static void looper(void)
|
|||
rlc.add_context(LNM_COMMAND, command_context);
|
||||
rlc.add_context(LNM_SEARCH, search_context);
|
||||
rlc.add_context(LNM_CAPTURE, index_context);
|
||||
rlc.add_context(LNM_SQL, index_context);
|
||||
rlc.add_context(LNM_SQL, sql_context);
|
||||
rlc.start();
|
||||
|
||||
lnav_data.ld_rl_view = &rlc;
|
||||
|
@ -1798,6 +1800,110 @@ static void looper(void)
|
|||
lnav_data.ld_rl_view->
|
||||
add_possibility(LNM_COMMAND, "graph", "([:= \\t]\\d+(?:\\.\\d+)?)");
|
||||
|
||||
{
|
||||
const char *sql_commands[] = {
|
||||
"add",
|
||||
"all",
|
||||
"alter",
|
||||
"analyze",
|
||||
"asc",
|
||||
"attach",
|
||||
"begin",
|
||||
"collate",
|
||||
"column",
|
||||
"commit",
|
||||
"conflict",
|
||||
"create",
|
||||
"cross",
|
||||
"database",
|
||||
"delete",
|
||||
"desc",
|
||||
"detach",
|
||||
"distinct",
|
||||
"drop",
|
||||
"end",
|
||||
"except",
|
||||
"explain",
|
||||
"from",
|
||||
"group",
|
||||
"having",
|
||||
"index",
|
||||
"indexed",
|
||||
"inner",
|
||||
"insert",
|
||||
"intersect",
|
||||
"join",
|
||||
"left",
|
||||
"limit",
|
||||
"natural",
|
||||
"offset",
|
||||
"order",
|
||||
"outer",
|
||||
"pragma",
|
||||
"reindex",
|
||||
"rename",
|
||||
"replace",
|
||||
"rollback",
|
||||
"select",
|
||||
"table",
|
||||
"transaction",
|
||||
"trigger",
|
||||
"union",
|
||||
"unique",
|
||||
"update",
|
||||
"using",
|
||||
"vacuum",
|
||||
"view",
|
||||
"where",
|
||||
"when",
|
||||
|
||||
// XXX do the following dynamically by reading sqlite_master
|
||||
|
||||
"access_log",
|
||||
"syslog_log",
|
||||
"generic_log",
|
||||
"strace_log",
|
||||
|
||||
"line_number",
|
||||
"path",
|
||||
"log_time",
|
||||
"level",
|
||||
"raw_line",
|
||||
|
||||
"c_ip",
|
||||
"cs_username",
|
||||
"cs_method",
|
||||
"cs_uri_stem",
|
||||
"cs_uri_query",
|
||||
"cs_version",
|
||||
"sc_status",
|
||||
"sc_bytes",
|
||||
"cs_referer",
|
||||
"cs_user_agent",
|
||||
|
||||
"funcname",
|
||||
"result",
|
||||
"duration",
|
||||
"arg0",
|
||||
"arg1",
|
||||
"arg2",
|
||||
"arg3",
|
||||
"arg4",
|
||||
"arg5",
|
||||
"arg6",
|
||||
"arg7",
|
||||
"arg8",
|
||||
"arg9",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int lpc = 0; sql_commands[lpc]; lpc++) {
|
||||
lnav_data.ld_rl_view->
|
||||
add_possibility(LNM_SQL, "*", sql_commands[lpc]);
|
||||
}
|
||||
}
|
||||
|
||||
(void)signal(SIGINT, sigint);
|
||||
(void)signal(SIGTERM, sigint);
|
||||
(void)signal(SIGWINCH, sigwinch);
|
||||
|
@ -2033,7 +2139,7 @@ public:
|
|||
using namespace sqlite_api;
|
||||
string c_ip, cs_username, cs_method, cs_uri_stem, cs_uri_query;
|
||||
string cs_version, sc_status, cs_referer, cs_user_agent;
|
||||
int sc_bytes = 0;
|
||||
string sc_bytes;
|
||||
|
||||
if (!this->alt_regex.FullMatch(line,
|
||||
&c_ip,
|
||||
|
@ -2046,7 +2152,7 @@ public:
|
|||
&sc_bytes,
|
||||
&cs_referer,
|
||||
&cs_user_agent)) {
|
||||
fprintf(stderr, "bad match! %s\n", line.c_str());
|
||||
fprintf(stderr, "bad match! %d %s\n", column, line.c_str());
|
||||
}
|
||||
switch (column) {
|
||||
case 0:
|
||||
|
@ -2092,7 +2198,12 @@ public:
|
|||
SQLITE_TRANSIENT);
|
||||
break;
|
||||
case 7:
|
||||
sqlite3_result_int64(ctx, sc_bytes);
|
||||
{
|
||||
int sc_bytes_int = 0;
|
||||
|
||||
sscanf(sc_bytes.c_str(), "%d", &sc_bytes_int);
|
||||
sqlite3_result_int64(ctx, sc_bytes_int);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
sqlite3_result_text(ctx,
|
||||
|
@ -2185,6 +2296,18 @@ public:
|
|||
if (!in_quote)
|
||||
in_struct += 1;
|
||||
break;
|
||||
case '}':
|
||||
if (!in_quote)
|
||||
in_struct -= 1;
|
||||
break;
|
||||
case '[':
|
||||
if (!in_quote)
|
||||
in_list += 1;
|
||||
break;
|
||||
case ']':
|
||||
if (!in_quote)
|
||||
in_list -= 1;
|
||||
break;
|
||||
case '"':
|
||||
if (!in_quote)
|
||||
in_quote = true;
|
||||
|
@ -2192,7 +2315,7 @@ public:
|
|||
in_quote = false;
|
||||
break;
|
||||
case ',':
|
||||
if (!in_quote) {
|
||||
if (!in_quote && !in_struct && !in_list) {
|
||||
if (curarg == argnum) {
|
||||
sqlite3_result_text(ctx,
|
||||
arg_start,
|
||||
|
@ -2296,7 +2419,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
lnav_data.ld_looping = true;
|
||||
lnav_data.ld_mode = LNM_PAGING;
|
||||
lnav_data.ld_debug_log_name = "/tmp/lnav.err"; // XXX change to /dev/null
|
||||
lnav_data.ld_debug_log_name = "/dev/null"; // XXX change to /dev/null
|
||||
while ((c = getopt(argc, argv, "harsd:")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
|
@ -2392,7 +2515,6 @@ int main(int argc, char *argv[])
|
|||
lnav_data.ld_log_source.insert_file(lf);
|
||||
}
|
||||
|
||||
lnav_data.ld_db_file = "/tmp/lnav-db.XXXXXX";
|
||||
looper();
|
||||
}
|
||||
catch (line_buffer::error & e) {
|
||||
|
|
|
@ -136,6 +136,8 @@ int log_format::log_scanf(const char *line,
|
|||
"%Y/%m/%d %H:%M:%S",
|
||||
"%Y/%m/%d %H:%M",
|
||||
|
||||
"%a %b %d %H:%M:%S %Y",
|
||||
|
||||
"%d/%b/%Y:%H:%M:%S %z",
|
||||
|
||||
"%b %d %H:%M:%S",
|
||||
|
|
|
@ -174,10 +174,11 @@ class generic_log_format : public log_format {
|
|||
char *prefix,
|
||||
int len) {
|
||||
static const char *log_fmt[] = {
|
||||
"%63[0-9: ,-] %15s",
|
||||
"[%63[0-9: -]] %15s",
|
||||
"[%63[0-9: .-] %*s %15s",
|
||||
"[%63[0-9: -]] (%*d) %15s",
|
||||
"%63[a-zA-Z0-90-9: ,-] %15s",
|
||||
"[%63[a-zA-Z0-9: -]] %15s",
|
||||
"[%63[a-zA-Z0-9: -]] [%15[a-zA-Z]]",
|
||||
"[%63[a-zA-Z0-90-9: .-] %*s %15s",
|
||||
"[%63[a-zA-Z0-90-9: -]] (%*d) %15s",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ public:
|
|||
int length() { return this->m_end - this->m_begin; };
|
||||
} match_t;
|
||||
typedef match_t *iterator;
|
||||
|
||||
|
||||
int get_max_count() {
|
||||
return this->pc_max_count;
|
||||
};
|
||||
|
||||
void set_count(int count) {
|
||||
this->pc_count = count;
|
||||
|
@ -37,9 +40,11 @@ public:
|
|||
iterator end() { return pc_matches + pc_count; };
|
||||
|
||||
protected:
|
||||
pcre_context(match_t *matches) : pc_matches(matches) { };
|
||||
|
||||
pcre_context(match_t *matches, int max_count)
|
||||
: pc_matches(matches), pc_max_count(max_count) { };
|
||||
|
||||
match_t *pc_matches;
|
||||
int pc_max_count;
|
||||
int pc_count;
|
||||
};
|
||||
|
||||
|
@ -47,10 +52,10 @@ template<size_t MAX_COUNT>
|
|||
class pcre_context_static : public pcre_context {
|
||||
public:
|
||||
pcre_context_static()
|
||||
: pcre_context(this->pc_match_buffer) { };
|
||||
: pcre_context(this->pc_match_buffer, MAX_COUNT + 1) { };
|
||||
|
||||
private:
|
||||
match_t pc_match_buffer[MAX_COUNT * 3 + 1];
|
||||
match_t pc_match_buffer[MAX_COUNT + 1];
|
||||
};
|
||||
|
||||
class pcre_input {
|
||||
|
@ -119,7 +124,7 @@ public:
|
|||
virtual ~pcrepp() { };
|
||||
|
||||
bool match(pcre_context &pc, pcre_input &pi, int options = 0) {
|
||||
int count = 30;
|
||||
int count = pc.get_max_count();
|
||||
int rc;
|
||||
|
||||
pi.pi_offset = pi.pi_next_offset;
|
||||
|
@ -130,9 +135,13 @@ public:
|
|||
pi.pi_offset,
|
||||
options,
|
||||
(int *)pc.all(),
|
||||
count);
|
||||
count * 2);
|
||||
|
||||
if (rc <= 0) { }
|
||||
if (rc < 0) {
|
||||
}
|
||||
else if (rc == 0) {
|
||||
rc = 0;
|
||||
}
|
||||
else if (pc.all()->m_begin == pc.all()->m_end)
|
||||
rc = 0;
|
||||
else
|
||||
|
|
|
@ -93,7 +93,12 @@ char **readline_context::attempted_completion(const char *text,
|
|||
{
|
||||
char **retval = NULL;
|
||||
|
||||
if (start == 0) {
|
||||
if (loaded_context->rc_possibilities.find("*") != loaded_context->rc_possibilities.end()) {
|
||||
fprintf(stderr, "all poss\n");
|
||||
arg_possibilities = &loaded_context->rc_possibilities["*"];
|
||||
rl_completion_append_character = ' ';
|
||||
}
|
||||
else if (start == 0) {
|
||||
arg_possibilities = &loaded_context->rc_possibilities["__command"];
|
||||
rl_completion_append_character = ' ';
|
||||
}
|
||||
|
|
|
@ -204,7 +204,7 @@ void textview_curses::listview_value_for_row(const listview_curses &lv,
|
|||
int off, hcount = 0;
|
||||
|
||||
for (off = 0; off < str.size(); ) {
|
||||
int rc, matches[30];
|
||||
int rc, matches[60];
|
||||
|
||||
rc = pcre_exec(iter->second.h_code,
|
||||
NULL,
|
||||
|
@ -213,7 +213,7 @@ void textview_curses::listview_value_for_row(const listview_curses &lv,
|
|||
off,
|
||||
0,
|
||||
matches,
|
||||
30);
|
||||
60);
|
||||
if (rc > 0) {
|
||||
struct line_range lr;
|
||||
|
||||
|
@ -242,9 +242,10 @@ void textview_curses::listview_value_for_row(const listview_curses &lv,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (binary_search(bv.begin(), bv.end(), row)) {
|
||||
string_attrs_t::iterator iter;
|
||||
bool added = false;
|
||||
|
||||
for (iter = sa.begin(); iter != sa.end(); iter++) {
|
||||
attrs_map_t &am = iter->second;
|
||||
|
@ -253,8 +254,15 @@ void textview_curses::listview_value_for_row(const listview_curses &lv,
|
|||
for (am_iter = am.begin(); am_iter != am.end(); am_iter++) {
|
||||
if (am_iter->first == "style") {
|
||||
am_iter->second.sa_int ^= A_REVERSE;
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!added) {
|
||||
struct line_range lr = { 0, -1 };
|
||||
|
||||
sa[lr].insert(make_string_attr("style", A_REVERSE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ void view_colors::init(void)
|
|||
init_pair(VC_CYAN, COLOR_CYAN, COLOR_BLACK);
|
||||
init_pair(VC_GREEN, COLOR_GREEN, COLOR_BLACK);
|
||||
init_pair(VC_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
|
||||
|
||||
|
||||
init_pair(VC_BLUE_ON_WHITE, COLOR_BLUE, COLOR_WHITE);
|
||||
init_pair(VC_CYAN_ON_BLACK, COLOR_CYAN, COLOR_BLACK);
|
||||
init_pair(VC_GREEN_ON_WHITE, COLOR_GREEN, COLOR_WHITE);
|
||||
|
|
Loading…
Reference in New Issue