random fixes

This commit is contained in:
tstack 2009-09-19 15:36:27 -07:00
parent 815cd2adf2
commit 335dbadb22
13 changed files with 285 additions and 35 deletions

View File

@ -23,7 +23,9 @@ HELP_SRC = help.cc
endif
AM_LDFLAGS = \
$(SQLITE3_LDFLAGS)
$(SQLITE3_LDFLAGS) \
-pthread \
-static
AM_CPPFLAGS = \
$(SQLITE3_CFLAGS) \

View File

@ -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) \

View File

@ -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;
};

View File

@ -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,

View File

@ -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;

View File

@ -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 {

View File

@ -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) {

View File

@ -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",

View File

@ -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
};

View File

@ -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

View File

@ -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 = ' ';
}

View File

@ -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));
}
}
}

View File

@ -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);