1
1
mirror of https://github.com/tstack/lnav.git synced 2024-09-11 13:05:51 +03:00

[pretty] highlight log messages in the pretty view as in the normal log view

This commit is contained in:
Timothy Stack 2018-05-10 06:44:03 -07:00
parent 697d22705d
commit 7fb881222d
36 changed files with 75544 additions and 28713 deletions

2
NEWS
View File

@ -8,6 +8,8 @@ lnav v0.8.4:
* When typing in a search, instead of moving the view to the first match
that was found, the first ten matches will be displayed in the preview
window.
* The pretty-print view maintains highlighting from the log view.
* The pretty-print view no longer tries to reverse lookup IP addresses.
Fixes:
* The HOME key should now work in the command-prompt and move the cursor

View File

@ -41,8 +41,15 @@ AC_PROG_CXX
CPPFLAGS="$CPPFLAGS -D_ISOC99_SOURCE -D__STDC_LIMIT_MACROS -D_GNU_SOURCE"
# CFLAGS=`echo $CFLAGS | sed 's/-O2//g'`
# CXXFLAGS=`echo $CXXFLAGS | sed 's/-O2//g'`
AC_ARG_ENABLE([debug],
AS_HELP_STRING([--enable-debug],
[Compile with symbols]))
AS_VAR_IF([enable_profiling], [yes],
[CFLAGS=`echo $CFLAGS | sed 's/-O2//g'`
CXXFLAGS=`echo $CXXFLAGS | sed 's/-O2//g'`],
[enable_debug=no]dnl
)
AC_ARG_VAR(SFTP_TEST_URL)

View File

@ -93,7 +93,7 @@ time_fmts.cc: ptimec
if HAVE_RE2C
%.cc: %.re
$(RE2C_V)$(RE2C_CMD) -o $@ $<
$(RE2C_V)$(RE2C_CMD) -8 -o $@ $<
$(REC2_V)test $@ -ef $(srcdir)/$*.cc || cp $@ $(srcdir)/$*.cc
endif

View File

@ -418,7 +418,11 @@ public:
return *this;
};
attr_line_t &append(const attr_line_t &al, text_wrap_settings *tws = nullptr);
attr_line_t &insert(size_t index, const attr_line_t &al, text_wrap_settings *tws = nullptr);
attr_line_t &append(const attr_line_t &al, text_wrap_settings *tws = nullptr) {
return this->insert(this->al_string.length(), al, tws);
};
attr_line_t &append(size_t len, char c) {
this->al_string.append(len, c);

View File

@ -45,6 +45,8 @@ using namespace std;
exec_context INIT_EXEC_CONTEXT;
bookmark_type_t BM_QUERY("query");
static const string MSG_FORMAT_STMT =
"SELECT count(*) as total, min(log_line) as log_line, log_msg_format "
"FROM all_logs GROUP BY log_msg_format ORDER BY total desc";
@ -742,3 +744,19 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
return task.get_future();
}
void add_global_vars(exec_context &ec)
{
for (const auto &iter : lnav_config.lc_global_vars) {
shlex subber(iter.second);
string str;
if (!subber.eval(str, ec.ec_global_vars)) {
log_error("Unable to evaluate global variable value: %s",
iter.second.c_str());
continue;
}
ec.ec_global_vars[iter.first] = str;
}
}

View File

@ -85,4 +85,8 @@ std::future<std::string> pipe_callback(
int sql_progress(const struct log_cursor &lc);
void add_global_vars(exec_context &ec);
extern bookmark_type_t BM_QUERY;
#endif //LNAV_COMMAND_EXECUTOR_H

View File

@ -136,11 +136,7 @@ public:
void reset() {
this->ds_pcre_input.reset_next_offset();
if (!this->ds_line.empty() &&
this->ds_line[this->ds_line.length() - 1] == '.') {
this->ds_pcre_input.pi_length -= 1;
}
}
};
private:
std::string ds_line;

File diff suppressed because it is too large Load Diff

View File

@ -37,9 +37,9 @@
bool data_scanner::tokenize2(pcre_context &pc, data_token_t &token_out)
{
# define YYCTYPE char
# define YYCTYPE unsigned char
# define CAPTURE(tok) { \
pi.pi_next_offset = YYCURSOR.val - pi.get_string(); \
pi.pi_next_offset = YYCURSOR.val - (const unsigned char *) pi.get_string(); \
cap[0].c_end = pi.pi_next_offset; \
cap[1].c_end = pi.pi_next_offset; \
token_out = tok; \
@ -48,7 +48,7 @@ bool data_scanner::tokenize2(pcre_context &pc, data_token_t &token_out)
CAPTURE(tok); \
return true; \
}
static const char *EMPTY = "";
static const unsigned char *EMPTY = (const unsigned char *) "";
pcre_input &pi = this->ds_pcre_input;
struct _YYCURSOR {
const YYCTYPE operator*() const {
@ -87,10 +87,12 @@ bool data_scanner::tokenize2(pcre_context &pc, data_token_t &token_out)
const YYCTYPE *val;
const YYCTYPE *lim;
} YYCURSOR;
YYCURSOR = pi.get_string() + pi.pi_next_offset;
YYCURSOR = (const unsigned char *) pi.get_string() + pi.pi_next_offset;
_YYCURSOR yyt1;
_YYCURSOR yyt2;
const YYCTYPE *YYLIMIT = pi.get_string() + pi.pi_length;
_YYCURSOR yyt3;
_YYCURSOR yyt4;
const YYCTYPE *YYLIMIT = (const unsigned char *) pi.get_string() + pi.pi_length;
const YYCTYPE *YYMARKER = YYCURSOR;
pcre_context::capture_t *cap = pc.all();
@ -161,7 +163,7 @@ bool data_scanner::tokenize2(pcre_context &pc, data_token_t &token_out)
(SPACE|NUM)NUM":"NUM{2}/[^:] { RET(DT_TIME); }
(SPACE|NUM)NUM?":"NUM{2}":"NUM{2}("."NUM{3,6})?/[^:] { RET(DT_TIME); }
[0-9a-fA-F][0-9a-fA-F](":"[0-9a-fA-F][0-9a-fA-F])+ {
if ((YYCURSOR - pi.get_string()) == 17) {
if ((YYCURSOR - (const unsigned char *) pi.get_string()) == 17) {
RET(DT_MAC_ADDRESS);
} else {
RET(DT_HEX_DUMP);

View File

@ -56,7 +56,7 @@ public:
return this->dls_rows.size();
};
size_t text_size_for_line(textview_curses &tc, int line, bool raw) {
size_t text_size_for_line(textview_curses &tc, int line, line_flags_t flags) {
return this->text_line_width(tc);
};
@ -74,7 +74,7 @@ public:
void text_value_for_line(textview_curses &tc,
int row,
std::string &label_out,
bool raw)
line_flags_t flags)
{
/*
* start_value is the result rowid, each bucket type is a column value

View File

@ -49,7 +49,7 @@ hist_source::hist_source()
void hist_source::text_value_for_line(textview_curses &tc,
int row,
std::string &value_out,
bool no_scrub)
line_flags_t flags)
{
int grow = row / (this->buckets_per_group() + 1);
int brow = row % (this->buckets_per_group() + 1);

View File

@ -153,12 +153,12 @@ public:
void text_value_for_line(textview_curses &tc,
int row,
std::string &value_out,
bool no_scrub);
line_flags_t flags);
void text_attrs_for_line(textview_curses &tc,
int row,
string_attrs_t &value_out);
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
size_t text_size_for_line(textview_curses &tc, int row, line_flags_t flags) {
return 0;
};
@ -550,7 +550,7 @@ public:
void text_value_for_line(textview_curses &tc,
int row,
std::string &value_out,
bool no_scrub) {
line_flags_t flags) {
bucket_t &bucket = this->find_bucket(row);
struct tm bucket_tm;
char tm_buffer[128];
@ -591,7 +591,7 @@ public:
}
};
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
size_t text_size_for_line(textview_curses &tc, int row, line_flags_t flags) {
return 0;
};

View File

@ -166,8 +166,6 @@ const int ZOOM_LEVELS[] = {
const ssize_t ZOOM_COUNT = sizeof(ZOOM_LEVELS) / sizeof(int);
bookmark_type_t BM_QUERY("query");
const char *lnav_view_strings[LNV__MAX + 1] = {
"log",
"text",
@ -252,22 +250,6 @@ public:
};
};
static void add_global_vars(exec_context &ec)
{
for (const auto &iter : lnav_config.lc_global_vars) {
shlex subber(iter.second);
string str;
if (!subber.eval(str, ec.ec_global_vars)) {
log_error("Unable to evaluate global variable value: %s",
iter.second.c_str());
continue;
}
ec.ec_global_vars[iter.first] = str;
}
}
static void regenerate_unique_file_names()
{
unique_path_generator upg;
@ -770,49 +752,6 @@ static void open_schema_view(void)
schema_tc->set_sub_source(pts);
}
static int pretty_sql_callback(exec_context &ec, sqlite3_stmt *stmt)
{
if (!sqlite3_stmt_busy(stmt)) {
return 0;
}
int ncols = sqlite3_column_count(stmt);
for (int lpc = 0; lpc < ncols; lpc++) {
if (lpc > 0) {
ec.ec_accumulator.append(", ");
}
ec.ec_accumulator.append((const char *)sqlite3_column_text(stmt, lpc));
}
return 0;
}
static future<string> pretty_pipe_callback(exec_context &ec,
const string &cmdline,
auto_fd &fd)
{
auto retval = std::async(std::launch::async, [&]() {
char buffer[1024];
ostringstream ss;
ssize_t rc;
while ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
ss.write(buffer, rc);
}
string retval = ss.str();
if (endswith(retval.c_str(), "\n")) {
retval.resize(retval.length() - 1);
}
return retval;
});
return retval;
}
static void open_pretty_view(void)
{
static const char *NOTHING_MSG =
@ -822,7 +761,7 @@ static void open_pretty_view(void)
textview_curses *pretty_tc = &lnav_data.ld_views[LNV_PRETTY];
textview_curses *log_tc = &lnav_data.ld_views[LNV_LOG];
textview_curses *text_tc = &lnav_data.ld_views[LNV_TEXT];
ostringstream stream;
attr_line_t full_text;
delete pretty_tc->get_sub_source();
if (top_tc->get_inner_height() == 0) {
@ -837,35 +776,51 @@ static void open_pretty_view(void)
for (vis_line_t vl = log_tc->get_top(); vl <= log_tc->get_bottom(); ++vl) {
content_line_t cl = lss.at(vl);
shared_ptr<logfile> lf = lss.find(cl);
log_format *format = lf->get_format();
logfile::iterator ll = lf->begin() + cl;
auto ll = lf->begin() + cl;
shared_buffer_ref sbr;
if (!first_line && ll->is_continued()) {
continue;
}
ll = lf->message_start(ll);
lf->read_full_message(ll, sbr);
string_attrs_t sa;
auto ll_start = lf->message_start(ll);
vector<logline_value> values;
string rewritten_line;
attr_line_t al;
format->annotate(sbr, sa, values);
exec_context ec(&values, pretty_sql_callback, pretty_pipe_callback);
ec.ec_top_line = vl;
add_ansi_vars(ec.ec_global_vars);
add_global_vars(ec);
format->rewrite(ec, sbr, sa, rewritten_line);
vl -= vis_line_t(distance(ll_start, ll));
lss.text_value_for_line(*log_tc, vl, al.get_string(),
text_sub_source::RF_FULL|
text_sub_source::RF_REWRITE);
lss.text_attrs_for_line(*log_tc, vl, al.get_attrs());
data_scanner ds(rewritten_line);
pretty_printer pp(&ds);
line_range orig_lr = find_string_attr_range(
al.get_attrs(), &textview_curses::SA_ORIGINAL_LINE);
attr_line_t orig_al = al.subline(orig_lr.lr_start, orig_lr.length());
attr_line_t prefix_al = al.subline(0, orig_lr.lr_start);
data_scanner ds(orig_al.get_string());
pretty_printer pp(&ds, orig_al.get_attrs());
attr_line_t pretty_al;
vector<attr_line_t> pretty_lines;
// TODO: dump more details of the line in the output.
stream << trim(pp.print()) << endl;
pp.append_to(pretty_al);
pretty_al.split_lines(pretty_lines);
for (auto &pretty_line : pretty_lines) {
if (pretty_line.empty() && &pretty_line == &pretty_lines.back()) {
break;
}
pretty_line.insert(0, prefix_al);
pretty_line.append("\n");
full_text.append(pretty_line);
}
first_line = false;
}
if (!full_text.empty()) {
full_text.erase(full_text.length() - 1, 1);
}
}
else if (top_tc == text_tc) {
shared_ptr<logfile> lf = lnav_data.ld_text_source.current_file();
@ -876,12 +831,15 @@ static void open_pretty_view(void)
lf->read_full_message(ll, sbr);
data_scanner ds(sbr);
pretty_printer pp(&ds);
string_attrs_t sa;
pretty_printer pp(&ds, sa);
stream << pp.print() << endl;
pp.append_to(full_text);
}
}
pretty_tc->set_sub_source(new plain_text_source(stream.str()));
plain_text_source *pts = new plain_text_source();
pts->replace_with(full_text);
pretty_tc->set_sub_source(pts);
if (lnav_data.ld_last_pretty_print_top != log_tc->get_top()) {
pretty_tc->set_top(vis_line_t(0));
}

View File

@ -319,7 +319,6 @@ struct _lnav_data {
extern struct _lnav_data lnav_data;
extern readline_context::command_map_t lnav_commands;
extern bookmark_type_t BM_QUERY;
extern const int ZOOM_LEVELS[];
extern const ssize_t ZOOM_COUNT;

View File

@ -638,7 +638,8 @@ static string com_save_to(exec_context &ec, string cmdline, vector<string> &args
string line;
dls.text_value_for_line(lnav_data.ld_views[LNV_DB], lpc, line, true);
dls.text_value_for_line(lnav_data.ld_views[LNV_DB], lpc, line,
text_sub_source::RF_RAW);
fputs(line.c_str(), outfile);
fputc('\n', outfile);
}

View File

@ -47,6 +47,7 @@
#include "auto_pid.hh"
#include "lnav_config.hh"
#include "yajlpp.hh"
#include "shlex.hh"
using namespace std;
@ -493,4 +494,4 @@ void reload_config()
curr->reload_config();
curr = curr->lcl_next;
}
}
}

View File

@ -60,12 +60,12 @@ using namespace std;
* iostat
*/
string_attr_type logline::L_PREFIX;
string_attr_type logline::L_TIMESTAMP;
string_attr_type logline::L_FILE;
string_attr_type logline::L_PARTITION;
string_attr_type logline::L_MODULE;
string_attr_type logline::L_OPID;
string_attr_type logline::L_PREFIX("prefix");
string_attr_type logline::L_TIMESTAMP("timestamp");
string_attr_type logline::L_FILE("file");
string_attr_type logline::L_PARTITION("partition");
string_attr_type logline::L_MODULE("module");
string_attr_type logline::L_OPID("opid");
const char *logline::level_names[LEVEL__MAX + 1] = {
"unknown",
@ -201,6 +201,47 @@ logline_value::kind_t logline_value::string2kind(const char *kindstr)
return VALUE_UNKNOWN;
}
struct line_range logline_value::origin_in_full_msg(const char *msg, size_t len) const
{
if (this->lv_sub_offset == 0) {
return this->lv_origin;
}
if (len == -1) {
len = strlen(msg);
}
struct line_range retval = this->lv_origin;
const char *last = msg, *msg_end = msg + len;
for (int lpc = 0; lpc < this->lv_sub_offset; lpc++) {
const auto *next = (const char *) memchr(last, '\n', msg_end - last);
require(next != NULL);
next += 1;
int amount = (next - last);
retval.lr_start += amount;
if (retval.lr_end != -1) {
retval.lr_end += amount;
}
last = next + 1;
}
if (retval.lr_end == -1) {
const auto *eol = (const char *) memchr(last, '\n', msg_end - last);
if (eol == nullptr) {
retval.lr_end = len;
} else {
retval.lr_end = eol - msg;
}
}
return retval;
}
vector<log_format *> log_format::lf_root_formats;
vector<log_format *> &log_format::get_root_formats(void)
@ -960,27 +1001,23 @@ void external_log_format::rewrite(exec_context &ec,
value_def &vd = *vd_iter->second;
if (!vd.vd_rewriter.empty()) {
string field_value = iter->to_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());
value_out.erase(adj_origin.lr_start, adj_origin.length());
int32_t shift_amount = field_value.length() - adj_origin.length();
value_out.insert(adj_origin.lr_start, field_value);
for (shift_iter = values.begin();
shift_iter != values.end(); ++shift_iter) {
if (shift_iter->lv_name == iter->lv_name) {
continue;
}
shift_iter->lv_origin.shift(adj_origin.lr_start, shift_amount);
}
if (vd.vd_rewriter.empty()) {
continue;
}
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());
value_out.erase(adj_origin.lr_start, adj_origin.length());
int32_t shift_amount = field_value.length() - adj_origin.length();
value_out.insert(adj_origin.lr_start, field_value);
for (shift_iter = values.begin();
shift_iter != values.end(); ++shift_iter) {
shift_iter->lv_origin.shift(adj_origin.lr_start, shift_amount);
}
shift_string_attrs(sa, adj_origin.lr_start, shift_amount);
}
}

View File

@ -545,37 +545,7 @@ public:
return this->lv_sbr.length();
}
struct line_range origin_in_full_msg(const char *msg, size_t len) {
if (this->lv_sub_offset == 0) {
return this->lv_origin;
}
struct line_range retval = this->lv_origin;
const char *last = msg;
for (int lpc = 0; lpc < this->lv_sub_offset; lpc++) {
const char *next = strchr(last, '\n');
require(next != NULL);
next += 1;
int amount = (next - last);
retval.lr_start += amount;
if (retval.lr_end != -1) {
retval.lr_end += amount;
}
last = next + 1;
}
if (retval.lr_end == -1) {
const char *eol = strchr(last, '\n');
retval.lr_end = eol - msg;
}
return retval;
};
struct line_range origin_in_full_msg(const char *msg, size_t len) const;;
intern_string_t lv_name;
kind_t lv_kind;

View File

@ -29,13 +29,17 @@
#include "config.h"
#include <future>
#include <algorithm>
#include <sqlite3.h>
#include "k_merge_tree.h"
#include "lnav_util.hh"
#include "log_accel.hh"
#include "relative_time.hh"
#include "logfile_sub_source.hh"
#include "command_executor.hh"
#include "ansi_scrubber.hh"
using namespace std;
@ -43,6 +47,55 @@ bookmark_type_t logfile_sub_source::BM_ERRORS("error");
bookmark_type_t logfile_sub_source::BM_WARNINGS("warning");
bookmark_type_t logfile_sub_source::BM_FILES("");
static int pretty_sql_callback(exec_context &ec, sqlite3_stmt *stmt)
{
if (!sqlite3_stmt_busy(stmt)) {
return 0;
}
int ncols = sqlite3_column_count(stmt);
for (int lpc = 0; lpc < ncols; lpc++) {
if (!ec.ec_accumulator.empty()) {
ec.ec_accumulator.append(", ");
}
const char *res = (const char *)sqlite3_column_text(stmt, lpc);
if (res == nullptr) {
continue;
}
ec.ec_accumulator.append(res);
}
return 0;
}
static future<string> pretty_pipe_callback(exec_context &ec,
const string &cmdline,
auto_fd &fd)
{
auto retval = std::async(std::launch::async, [&]() {
char buffer[1024];
ostringstream ss;
ssize_t rc;
while ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
ss.write(buffer, rc);
}
string retval = ss.str();
if (endswith(retval.c_str(), "\n")) {
retval.resize(retval.length() - 1);
}
return retval;
});
return retval;
}
logfile_sub_source::logfile_sub_source()
: lss_flags(0),
lss_force_rebuild(false),
@ -102,7 +155,7 @@ vis_line_t logfile_sub_source::find_from_time(const struct timeval &start)
void logfile_sub_source::text_value_for_line(textview_curses &tc,
int row,
string &value_out,
bool raw)
line_flags_t flags)
{
content_line_t line(0);
@ -110,19 +163,27 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
require((size_t)row < this->lss_filtered_index.size());
line = this->at(vis_line_t(row));
this->lss_token_file = this->find(line);
this->lss_token_line = this->lss_token_file->begin() + line;
if (raw) {
this->lss_token_file->read_line(this->lss_token_line, value_out);
if (flags & RF_RAW) {
shared_ptr<logfile> lf = this->find(line);
lf->read_line(lf->begin() + line, value_out);
return;
}
this->lss_token_flags = flags;
this->lss_token_file = this->find(line);
this->lss_token_line = this->lss_token_file->begin() + line;
this->lss_token_attrs.clear();
this->lss_token_values.clear();
this->lss_share_manager.invalidate_refs();
this->lss_token_value =
this->lss_token_file->read_line(this->lss_token_line);
if (flags & text_sub_source::RF_FULL) {
this->lss_token_file->read_full_message(this->lss_token_line,
this->lss_token_value);
} else {
this->lss_token_value =
this->lss_token_file->read_line(this->lss_token_line);
}
this->lss_token_shift_start = 0;
this->lss_token_shift_size = 0;
@ -143,6 +204,17 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
if (this->lss_token_line->get_sub_offset() != 0) {
this->lss_token_attrs.clear();
}
if (flags & RF_REWRITE) {
exec_context ec(&this->lss_token_values, pretty_sql_callback, pretty_pipe_callback);
string rewritten_line;
ec.ec_top_line = vis_line_t(row);
add_ansi_vars(ec.ec_global_vars);
add_global_vars(ec);
format->rewrite(ec, sbr, this->lss_token_attrs, rewritten_line);
this->lss_token_value.assign(rewritten_line);
value_out = this->lss_token_value;
}
if ((this->lss_token_file->is_time_adjusted() ||
format->lf_timestamp_flags & ETF_MACHINE_ORIENTED) &&
@ -289,10 +361,11 @@ void logfile_sub_source::text_attrs_for_line(textview_curses &lv,
value_out.emplace_back(lr, &view_curses::VC_STYLE, attrs);
for (vector<logline_value>::const_iterator lv_iter = line_values.begin();
lv_iter != line_values.end();
for (auto lv_iter = line_values.cbegin();
lv_iter != line_values.cend();
++lv_iter) {
if (lv_iter->lv_sub_offset != this->lss_token_line->get_sub_offset() ||
if ((!(this->lss_token_flags & RF_FULL) &&
lv_iter->lv_sub_offset != this->lss_token_line->get_sub_offset()) ||
!lv_iter->lv_origin.is_valid()) {
continue;
}
@ -309,8 +382,13 @@ void logfile_sub_source::text_attrs_for_line(textview_curses &lv,
int id_attrs = vc.attrs_for_ident(lv_iter->text_value(),
lv_iter->text_length());
value_out.emplace_back(
lv_iter->lv_origin, &view_curses::VC_STYLE, id_attrs);
line_range ident_range = lv_iter->lv_origin;
if (this->lss_token_flags & RF_FULL) {
ident_range = lv_iter->origin_in_full_msg(
this->lss_token_value.c_str(), this->lss_token_value.length());
}
value_out.emplace_back(ident_range, &view_curses::VC_STYLE, id_attrs);
}
if (this->lss_token_shift_size) {
@ -344,12 +422,15 @@ void logfile_sub_source::text_attrs_for_line(textview_curses &lv,
value_out.push_back(
string_attr(lr, &view_curses::VC_GRAPHIC, graph));
bookmark_vector<vis_line_t> &bv_search = bm[&textview_curses::BM_SEARCH];
if (!(this->lss_token_flags & RF_FULL)) {
bookmark_vector<vis_line_t> &bv_search = bm[&textview_curses::BM_SEARCH];
if (binary_search(::begin(bv_search), ::end(bv_search), vis_line_t(row))) {
lr.lr_start = 0;
lr.lr_end = 1;
value_out.emplace_back(lr, &view_curses::VC_STYLE, A_REVERSE);
if (binary_search(::begin(bv_search), ::end(bv_search),
vis_line_t(row))) {
lr.lr_start = 0;
lr.lr_end = 1;
value_out.emplace_back(lr, &view_curses::VC_STYLE, A_REVERSE);
}
}
}

View File

@ -226,19 +226,19 @@ public:
void text_value_for_line(textview_curses &tc,
int row,
std::string &value_out,
bool raw);
line_flags_t flags);
void text_attrs_for_line(textview_curses &tc,
int row,
string_attrs_t &value_out);
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
size_t text_size_for_line(textview_curses &tc, int row, line_flags_t flags) {
size_t index = row % LINE_SIZE_CACHE_SIZE;
if (this->lss_line_size_cache[index].first != row) {
std::string value;
this->text_value_for_line(tc, row, value, raw);
this->text_value_for_line(tc, row, value, flags);
this->lss_line_size_cache[index].second = value.size();
this->lss_line_size_cache[index].first = row;
}
@ -680,6 +680,7 @@ private:
bookmarks<content_line_t>::type lss_user_marks;
std::map<content_line_t, bookmark_metadata> lss_user_mark_metadata;
line_flags_t lss_token_flags;
std::shared_ptr<logfile> lss_token_file;
std::string lss_token_value;
string_attrs_t lss_token_attrs;

View File

@ -110,7 +110,7 @@ public:
void text_value_for_line(textview_curses &tc,
int row,
std::string &value_out,
bool no_scrub) {
line_flags_t flags) {
value_out = this->tds_lines[row].get_string();
};
@ -119,7 +119,7 @@ public:
value_out = this->tds_lines[line].get_attrs();
};
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
size_t text_size_for_line(textview_curses &tc, int row, line_flags_t flags) {
return this->tds_lines[row].length();
};

View File

@ -41,7 +41,7 @@ void sigalrm_handler(int sig)
}
}
std::string pretty_printer::print() {
void pretty_printer::append_to(attr_line_t &al) {
pcre_context_static<30> pc;
data_token_t dt;
@ -51,16 +51,16 @@ std::string pretty_printer::print() {
switch (dt) {
case DT_XML_EMPTY_TAG:
if (is_xml) {
if (this->pp_is_xml && this->pp_line_length > 0) {
this->start_new_line();
}
this->pp_values.push_back(el);
if (is_xml) {
if (this->pp_is_xml) {
this->start_new_line();
}
continue;
case DT_XML_OPEN_TAG:
if (is_xml) {
if (this->pp_is_xml) {
this->start_new_line();
this->write_element(el);
this->descend();
@ -100,8 +100,9 @@ std::string pretty_printer::print() {
}
break;
case DT_WHITE:
if (this->pp_values.empty() && this->pp_depth == 0) {
// this->pp_leading_indent = el.e_capture.length();
if (this->pp_values.empty() && this->pp_depth == 0 &&
this->pp_line_length == 0) {
this->pp_leading_indent = el.e_capture.length();
continue;
}
break;
@ -115,7 +116,14 @@ std::string pretty_printer::print() {
}
this->flush_values();
return this->pp_stream.str();
attr_line_t combined;
combined.get_string() = this->pp_stream.str();
combined.get_attrs() = this->pp_attrs;
if (!al.empty()) {
al.append("\n");
}
al.append(combined);
}
void pretty_printer::convert_ip_address(const pretty_printer::element &el) {
@ -170,33 +178,41 @@ void pretty_printer::convert_ip_address(const pretty_printer::element &el) {
log_info("Reverse lookup in pretty-print view disabled");
}
}
this->pp_stream << " " << ANSI_UNDERLINE_START <<
"(" << result << ")" <<
ANSI_NORM;
ssize_t start_size = this->pp_stream.tellp();
this->pp_stream << " (" << result << ")";
struct line_range lr{(int) start_size + 1, (int) this->pp_stream.tellp()};
this->pp_attrs.emplace_back(lr, &view_curses::VC_STYLE, A_UNDERLINE);
}
void pretty_printer::write_element(const pretty_printer::element &el) {
if (this->pp_leading_indent == 0 &&
this->pp_line_length == 0 &&
el.e_token == DT_WHITE) {
if (this->pp_depth == 0) {
this->pp_soft_indent += el.e_capture.length();
}
return;
}
if (this->pp_line_length == 0 && el.e_token == DT_LINE) {
if (this->pp_line_length <= this->pp_leading_indent && el.e_token == DT_LINE) {
this->pp_soft_indent = 0;
return;
}
pcre_input &pi = this->pp_scanner->get_input();
if (this->pp_line_length == 0) {
this->append_indent();
}
ssize_t start_size = this->pp_stream.tellp();
if (el.e_token == DT_QUOTED_STRING) {
auto_mem<char> unquoted_str((char *)malloc(el.e_capture.length() + 1));
const char *start = pi.get_substr_start(&el.e_capture);
unquote(unquoted_str.in(), start, el.e_capture.length());
data_scanner ds(unquoted_str.in());
pretty_printer str_pp(&ds,
string_attrs_t sa;
pretty_printer str_pp(&ds, sa,
this->pp_leading_indent + this->pp_depth * 4);
std::string result = str_pp.print();
if (result.find('\n') != std::string::npos) {
attr_line_t result;
str_pp.append_to(result);
if (result.get_string().find('\n') != std::string::npos) {
switch (start[0]) {
case 'r':
case 'u':
@ -209,8 +225,8 @@ void pretty_printer::write_element(const pretty_printer::element &el) {
}
this->pp_stream
<< std::endl
<< result;
if (!endswith(result.c_str(), "\n")) {
<< result.get_string();
if (!endswith(result.get_string().c_str(), "\n")) {
this->pp_stream << std::endl;
}
this->pp_stream
@ -221,14 +237,9 @@ void pretty_printer::write_element(const pretty_printer::element &el) {
}
} else {
this->pp_stream << pi.get_substr(&el.e_capture);
switch (el.e_token) {
case DT_IPV4_ADDRESS:
case DT_IPV6_ADDRESS:
this->convert_ip_address(el);
break;
default:
break;
}
int shift_amount = start_size - el.e_capture.c_begin - this->pp_shift_accum;
shift_string_attrs(this->pp_attrs, el.e_capture.c_begin, shift_amount);
this->pp_shift_accum = start_size - el.e_capture.c_begin;
}
this->pp_line_length += el.e_capture.length();
if (el.e_token == DT_LINE) {
@ -238,7 +249,8 @@ void pretty_printer::write_element(const pretty_printer::element &el) {
}
void pretty_printer::append_indent() {
this->pp_stream << std::string(this->pp_leading_indent, ' ');
this->pp_stream << std::string(this->pp_leading_indent + this->pp_soft_indent, ' ');
this->pp_soft_indent = 0;
if (this->pp_stream.tellp() == this->pp_leading_indent) {
return;
}

View File

@ -42,7 +42,7 @@
#include <deque>
#include <sstream>
#include <iomanip>
#include <utility>
#include "timer.hh"
#include "ansi_scrubber.hh"
#include "data_scanner.hh"
@ -66,12 +66,10 @@ public:
pcre_context::capture_t e_capture;
};
pretty_printer(data_scanner *ds, int leading_indent=0)
pretty_printer(data_scanner *ds, string_attrs_t sa, int leading_indent=0)
: pp_leading_indent(leading_indent),
pp_depth(0),
pp_line_length(0),
pp_scanner(ds),
is_xml(false) {
pp_attrs(sa) {
this->pp_body_lines.push(0);
pcre_context_static<30> pc;
@ -80,12 +78,12 @@ public:
this->pp_scanner->reset();
while (this->pp_scanner->tokenize2(pc, dt)) {
if (dt == DT_XML_CLOSE_TAG) {
is_xml = true;
pp_is_xml = true;
}
}
};
std::string print();
void append_to(attr_line_t &al);
private:
@ -104,13 +102,16 @@ private:
void write_element(const element &el);
int pp_leading_indent;
int pp_depth;
int pp_line_length;
std::stack<int> pp_body_lines;
int pp_depth{0};
int pp_line_length{0};
int pp_soft_indent{0};
std::stack<int> pp_body_lines{};
data_scanner *pp_scanner;
string_attrs_t pp_attrs;
std::ostringstream pp_stream;
std::deque<element> pp_values;
bool is_xml;
std::deque<element> pp_values{};
int pp_shift_accum{0};
bool pp_is_xml{false};
};
#endif

View File

@ -209,7 +209,7 @@ void add_view_text_possibilities(int context, const string &type, textview_curse
++curr_line) {
string line;
tss->text_value_for_line(*tc, curr_line, line);
tss->text_value_for_line(*tc, curr_line, line, text_sub_source::RF_RAW);
add_text_possibilities(context, type, line);
}

View File

@ -309,7 +309,7 @@ public:
return width;
};
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
size_t text_size_for_line(textview_curses &tc, int row, line_flags_t flags) {
return 0;
};
@ -345,7 +345,7 @@ public:
void text_value_for_line(textview_curses &tc,
int row,
std::string &value_out,
bool no_scrub) {
line_flags_t flags) {
spectrogram_row &s_row = this->load_row(tc, row);
time_t row_time;

View File

@ -70,7 +70,7 @@ public:
void text_value_for_line(textview_curses &tc,
int line,
std::string &value_out,
bool raw = false)
line_flags_t flags)
{
if (!this->tss_files.empty()) {
std::shared_ptr<logfile> lf = this->current_file();
@ -97,7 +97,7 @@ public:
value_out.push_back(string_attr(lr, &logline::L_FILE, this->current_file().get()));
};
size_t text_size_for_line(textview_curses &tc, int line, bool raw) {
size_t text_size_for_line(textview_curses &tc, int line, line_flags_t flags) {
size_t retval = 0;
if (!this->tss_files.empty()) {

View File

@ -58,10 +58,10 @@ bookmark_type_t textview_curses::BM_USER("user");
bookmark_type_t textview_curses::BM_PARTITION("partition");
bookmark_type_t textview_curses::BM_SEARCH("search");
string_attr_type textview_curses::SA_ORIGINAL_LINE;
string_attr_type textview_curses::SA_BODY;
string_attr_type textview_curses::SA_HIDDEN;
string_attr_type textview_curses::SA_FORMAT;
string_attr_type textview_curses::SA_ORIGINAL_LINE("original_line");
string_attr_type textview_curses::SA_BODY("body");
string_attr_type textview_curses::SA_HIDDEN("hidden");
string_attr_type textview_curses::SA_FORMAT("format");
textview_curses::textview_curses()
: tc_sub_source(NULL),

View File

@ -313,6 +313,20 @@ class text_sub_source {
public:
virtual ~text_sub_source() { };
enum {
RB_RAW,
RB_FULL,
RB_REWRITE,
};
enum {
RF_RAW = (1L << RB_RAW),
RF_FULL = (1L << RB_FULL),
RF_REWRITE = (1L << RB_REWRITE),
};
typedef long line_flags_t;
virtual void toggle_scrub(void) { };
/**
@ -337,9 +351,9 @@ public:
virtual void text_value_for_line(textview_curses &tc,
int line,
std::string &value_out,
bool raw = false) = 0;
line_flags_t flags = 0) = 0;
virtual size_t text_size_for_line(textview_curses &tc, int line, bool raw = false) = 0;
virtual size_t text_size_for_line(textview_curses &tc, int line, line_flags_t raw = 0) = 0;
/**
* Inform the source that the given line has been marked/unmarked. This
@ -647,7 +661,7 @@ public:
this->tc_sub_source->text_value_for_line(*this,
line,
value_out,
true);
text_sub_source::RF_RAW);
retval = true;
}

View File

@ -224,25 +224,27 @@ attr_line_t &attr_line_t::with_ansi_string(const std::string &str)
return *this;
}
attr_line_t &attr_line_t::append(const attr_line_t &al, text_wrap_settings *tws)
attr_line_t &attr_line_t::insert(size_t index, const attr_line_t &al, text_wrap_settings *tws)
{
size_t start_len = this->al_string.length();
if (index < this->al_string.length()) {
shift_string_attrs(this->al_attrs, index, al.al_string.length());
}
this->al_string.append(al.al_string);
this->al_string.insert(index, al.al_string);
for (auto &sa : al.al_attrs) {
this->al_attrs.emplace_back(sa);
line_range &lr = this->al_attrs.back().sa_range;
lr.shift(0, start_len);
lr.shift(0, index);
if (lr.lr_end == -1) {
lr.lr_end = this->al_string.length();
lr.lr_end = index + al.al_string.length();
}
}
if (tws != nullptr && (int)this->al_string.length() > tws->tws_width) {
ssize_t start_pos = start_len;
ssize_t start_pos = index;
ssize_t line_start = this->al_string.rfind('\n', start_pos);
if (line_start == (ssize_t)string::npos) {
@ -251,7 +253,7 @@ attr_line_t &attr_line_t::append(const attr_line_t &al, text_wrap_settings *tws)
line_start += 1;
}
ssize_t line_len = start_len - line_start;
ssize_t line_len = index - line_start;
ssize_t usable_width = tws->tws_width - tws->tws_indent;
ssize_t avail = max((ssize_t) 0, (ssize_t) tws->tws_width - line_len);
@ -328,7 +330,7 @@ attr_line_t &attr_line_t::append(const attr_line_t &al, text_wrap_settings *tws)
attr_line_t attr_line_t::subline(size_t start, size_t len) const
{
if (len == std::string::npos) {
len = this->length();
len = this->al_string.length() - start;
}
line_range lr{(int) start, (int) (start + len)};
@ -342,8 +344,11 @@ attr_line_t attr_line_t::subline(size_t start, size_t len) const
retval.al_attrs.emplace_back(lr.intersection(sa.sa_range)
.shift(lr.lr_start, -lr.lr_start),
sa.sa_type,
sa.sa_value);
sa.sa_type, sa.sa_value);
line_range &last_lr = retval.al_attrs.back().sa_range;
ensure(last_lr.lr_end <= retval.al_string.length());
}
return retval;

View File

@ -56,6 +56,10 @@ string execute_any(exec_context &ec, const string &cmdline_with_mode)
return "";
}
void add_global_vars(exec_context &ec)
{
}
int main(int argc, char *argv[])
{
int c, retval = EXIT_SUCCESS;
@ -157,10 +161,10 @@ int main(int argc, char *argv[])
}
}
if (format.get() != NULL) {
vector<logline_value> ll_values;
string_attrs_t sa;
vector<logline_value> ll_values;
string_attrs_t sa;
if (format.get() != NULL) {
format->annotate(sbr, sa, ll_values);
body = find_string_attr_range(sa, &textview_curses::SA_BODY);
}
@ -179,10 +183,11 @@ int main(int argc, char *argv[])
if (pretty_print) {
data_scanner ds2(sub_line, body.lr_start, sub_line.length());
pretty_printer pp(&ds2);
pretty_printer pp(&ds2, sa);
attr_line_t pretty_out;
string pretty_out = pp.print();
fprintf(out, "\n--\n%s", pretty_out.c_str());
pp.append_to(pretty_out);
fprintf(out, "\n--\n%s", pretty_out.get_string().c_str());
}
auto_mem<yajl_gen_t> gen(yajl_gen_free);

View File

@ -62,6 +62,10 @@ string execute_any(exec_context &ec, const string &cmdline_with_mode)
return "";
}
void add_global_vars(exec_context &ec)
{
}
int main(int argc, char *argv[]) {
int c, retval = EXIT_SUCCESS;
dl_mode_t mode = MODE_NONE;

View File

@ -61,6 +61,10 @@ string execute_any(exec_context &ec, const string &cmdline_with_mode)
return "";
}
void add_global_vars(exec_context &ec)
{
}
struct exec_context {
};

View File

@ -38,6 +38,10 @@ std::string execute_any(exec_context &ec, const std::string &cmdline_with_mode)
return "";
}
void add_global_vars(exec_context &ec)
{
}
int main(int argc, char *argv[])
{
int retval = EXIT_SUCCESS;

View File

@ -614,21 +614,21 @@ check_output "pretty-printer is not working" <<EOF
<response>
<locale>en-US</locale>
<requestid>ipInfo</requestid>
<value id="ipv4Gateway" actions="enabled">198.51.100.253 (unknown)</value>
<value id="ipv4Gateway" actions="enabled">198.51.100.253</value>
<value id="ipv6Gateway" actions="enabled"/>
<value id="ipv6Enabled" actions="enabled">true</value>
<value id="ipv4Enabled" actions="enabled">true</value>
<value id="name" actions="enabled">nic1</value>
<value id="v4config" actions="enabled">
<value id="defaultGateway" actions="enabled">0.0.0.0 (unknown)</value>
<value id="defaultGateway" actions="enabled">0.0.0.0</value>
<value id="updateable" actions="enabled">True</value>
<value id="prefix" actions="enabled">22</value>
<value id="mode" actions="enabled">dhcp</value>
<value id="address" actions="enabled">198.51.100.110 (unknown)</value>
<value id="address" actions="enabled">198.51.100.110</value>
<value id="interface" actions="enabled">nic1</value>
</value>
<value id="v6config" actions="enabled">
<value id="defaultGateway" actions="enabled">fe80::214:f609:19f7:6bf1 (unknown)</value>
<value id="defaultGateway" actions="enabled">fe80::214:f609:19f7:6bf1</value>
<value id="updateable" actions="enabled">True</value>
<value id="interface" actions="enabled">nic1</value>
<value id="dhcp" actions="enabled">False</value>
@ -637,7 +637,7 @@ check_output "pretty-printer is not working" <<EOF
<value id="origin" actions="enabled">other</value>
<value id="status" actions="enabled">preferred</value>
<value id="prefix" actions="enabled">64</value>
<value id="address" actions="enabled">fe80::250:56ff:feaa:5abf (unknown)</value>
<value id="address" actions="enabled">fe80::250:56ff:feaa:5abf</value>
</value>
</value>
<value id="interfaceInfo" actions="enabled">

View File

@ -29,9 +29,9 @@ echo '2015-04-18T13:16:30.003 8.8.8.8 <foo>8.8.8.8</foo>9 8.8.8.8<1054 198.51.10
run_test ${lnav_test} -n -c ":switch-to-view pretty"
check_output "pretty print not able to properly grok ipv4?" <<EOF
2015-04-18T13:16:30.003 8.8.8.8 (google-public-dns-a.google.com)
<foo>8.8.8.8 (google-public-dns-a.google.com)</foo>
9 8.8.8.8 (google-public-dns-a.google.com)<1054 198.51.100.1546 544.9.8.7 98.542.241.99 19143.2.5.6
2015-04-18T13:16:30.003 8.8.8.8
<foo>8.8.8.8</foo>
9 8.8.8.8<1054 198.51.100.1546 544.9.8.7 98.542.241.99 19143.2.5.6
EOF
cat <<EOF

View File

@ -52,6 +52,10 @@ string execute_any(exec_context &ec, const string &cmdline_with_mode)
return "";
}
void add_global_vars(exec_context &ec)
{
}
int main(int argc, char *argv[])
{
int retval = EXIT_SUCCESS;