mirror of
https://github.com/tstack/lnav.git
synced 2024-08-17 00:40:30 +03:00
parent
ef686b6932
commit
44d2e12403
1
NEWS
1
NEWS
@ -11,6 +11,7 @@ lnav v0.7.3:
|
|||||||
* Added a 'relative-goto' command to move the current view relative
|
* Added a 'relative-goto' command to move the current view relative
|
||||||
to its current position.
|
to its current position.
|
||||||
* Experimental support for linking with jemalloc.
|
* Experimental support for linking with jemalloc.
|
||||||
|
* The plain text view now supports filtering.
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
* Autotools scripts overhaul.
|
* Autotools scripts overhaul.
|
||||||
|
@ -73,6 +73,7 @@ set(diag_STAT_SRCS
|
|||||||
chunky_index.hh
|
chunky_index.hh
|
||||||
concise_index.hh
|
concise_index.hh
|
||||||
column_namer.hh
|
column_namer.hh
|
||||||
|
filter_observer.hh
|
||||||
format-text-files.hh
|
format-text-files.hh
|
||||||
grapher.hh
|
grapher.hh
|
||||||
grep_highlighter.hh
|
grep_highlighter.hh
|
||||||
|
@ -90,6 +90,7 @@ noinst_HEADERS = \
|
|||||||
default-log-formats-json.hh \
|
default-log-formats-json.hh \
|
||||||
db_sub_source.hh \
|
db_sub_source.hh \
|
||||||
environ_vtab.hh \
|
environ_vtab.hh \
|
||||||
|
filter_observer.hh \
|
||||||
format-text-files.hh \
|
format-text-files.hh \
|
||||||
grapher.hh \
|
grapher.hh \
|
||||||
grep_highlighter.hh \
|
grep_highlighter.hh \
|
||||||
@ -119,6 +120,7 @@ noinst_HEADERS = \
|
|||||||
logfile_sub_source.hh \
|
logfile_sub_source.hh \
|
||||||
pcrepp.hh \
|
pcrepp.hh \
|
||||||
piper_proc.hh \
|
piper_proc.hh \
|
||||||
|
pretty_printer.hh \
|
||||||
ptimec.hh \
|
ptimec.hh \
|
||||||
readline_curses.hh \
|
readline_curses.hh \
|
||||||
readline_highlighters.hh \
|
readline_highlighters.hh \
|
||||||
|
@ -281,22 +281,24 @@ am__noinst_HEADERS_DIST = ansi_scrubber.hh auto_fd.hh auto_mem.hh \
|
|||||||
auto_pid.hh bookmarks.hh bottom_status_source.hh byte_array.hh \
|
auto_pid.hh bookmarks.hh bottom_status_source.hh byte_array.hh \
|
||||||
chunky_index.hh column_namer.hh concise_index.hh \
|
chunky_index.hh column_namer.hh concise_index.hh \
|
||||||
data_scanner.hh data_parser.hh default-log-formats-json.hh \
|
data_scanner.hh data_parser.hh default-log-formats-json.hh \
|
||||||
db_sub_source.hh environ_vtab.hh format-text-files.hh \
|
db_sub_source.hh environ_vtab.hh filter_observer.hh \
|
||||||
grapher.hh grep_highlighter.hh grep_proc.hh help.hh help.txt \
|
format-text-files.hh grapher.hh grep_highlighter.hh \
|
||||||
hist_source.hh init.sql init-sql.hh intern_string.hh \
|
grep_proc.hh help.hh help.txt hist_source.hh init.sql \
|
||||||
json_op.hh json_ptr.hh k_merge_tree.h line_buffer.hh \
|
init-sql.hh intern_string.hh json_op.hh json_ptr.hh \
|
||||||
listview_curses.hh lnav.hh lnav_commands.hh lnav_config.hh \
|
k_merge_tree.h line_buffer.hh listview_curses.hh lnav.hh \
|
||||||
lnav_log.hh lnav_util.hh log_accel.hh log_data_helper.hh \
|
lnav_commands.hh lnav_config.hh lnav_log.hh lnav_util.hh \
|
||||||
log_data_table.hh log_format.hh log_format_loader.hh \
|
log_accel.hh log_data_helper.hh log_data_table.hh \
|
||||||
logfile.hh logfile_sub_source.hh pcrepp.hh piper_proc.hh \
|
log_format.hh log_format_loader.hh logfile.hh \
|
||||||
ptimec.hh readline_curses.hh readline_highlighters.hh \
|
logfile_sub_source.hh pcrepp.hh piper_proc.hh \
|
||||||
sequence_matcher.hh sequence_sink.hh session_data.hh \
|
pretty_printer.hh ptimec.hh readline_curses.hh \
|
||||||
shared_buffer.hh sql_util.hh sqlite-extension-func.h \
|
readline_highlighters.hh sequence_matcher.hh sequence_sink.hh \
|
||||||
status_controllers.hh statusview_curses.hh strnatcmp.h \
|
session_data.hh shared_buffer.hh sql_util.hh \
|
||||||
strong_int.hh sysclip.hh termios_guard.hh term_extra.hh \
|
sqlite-extension-func.h status_controllers.hh \
|
||||||
textfile_sub_source.hh textview_curses.hh time_T.hh \
|
statusview_curses.hh strnatcmp.h strong_int.hh sysclip.hh \
|
||||||
top_status_source.hh view_curses.hh vt52_curses.hh \
|
termios_guard.hh term_extra.hh textfile_sub_source.hh \
|
||||||
log_vtab_impl.hh log_format_impls.cc xterm_mouse.hh yajlpp.hh \
|
textview_curses.hh time_T.hh top_status_source.hh \
|
||||||
|
view_curses.hh vt52_curses.hh log_vtab_impl.hh \
|
||||||
|
log_format_impls.cc xterm_mouse.hh yajlpp.hh \
|
||||||
spookyhash/SpookyV2.h yajl/api/yajl_common.h \
|
spookyhash/SpookyV2.h yajl/api/yajl_common.h \
|
||||||
yajl/api/yajl_gen.h yajl/api/yajl_parse.h yajl/api/yajl_tree.h \
|
yajl/api/yajl_gen.h yajl/api/yajl_parse.h yajl/api/yajl_tree.h \
|
||||||
yajl/yajl_alloc.h yajl/yajl_buf.h yajl/yajl_bytestack.h \
|
yajl/yajl_alloc.h yajl/yajl_buf.h yajl/yajl_bytestack.h \
|
||||||
@ -505,22 +507,24 @@ noinst_HEADERS = ansi_scrubber.hh auto_fd.hh auto_mem.hh auto_pid.hh \
|
|||||||
bookmarks.hh bottom_status_source.hh byte_array.hh \
|
bookmarks.hh bottom_status_source.hh byte_array.hh \
|
||||||
chunky_index.hh column_namer.hh concise_index.hh \
|
chunky_index.hh column_namer.hh concise_index.hh \
|
||||||
data_scanner.hh data_parser.hh default-log-formats-json.hh \
|
data_scanner.hh data_parser.hh default-log-formats-json.hh \
|
||||||
db_sub_source.hh environ_vtab.hh format-text-files.hh \
|
db_sub_source.hh environ_vtab.hh filter_observer.hh \
|
||||||
grapher.hh grep_highlighter.hh grep_proc.hh help.hh help.txt \
|
format-text-files.hh grapher.hh grep_highlighter.hh \
|
||||||
hist_source.hh init.sql init-sql.hh intern_string.hh \
|
grep_proc.hh help.hh help.txt hist_source.hh init.sql \
|
||||||
json_op.hh json_ptr.hh k_merge_tree.h line_buffer.hh \
|
init-sql.hh intern_string.hh json_op.hh json_ptr.hh \
|
||||||
listview_curses.hh lnav.hh lnav_commands.hh lnav_config.hh \
|
k_merge_tree.h line_buffer.hh listview_curses.hh lnav.hh \
|
||||||
lnav_log.hh lnav_util.hh log_accel.hh log_data_helper.hh \
|
lnav_commands.hh lnav_config.hh lnav_log.hh lnav_util.hh \
|
||||||
log_data_table.hh log_format.hh log_format_loader.hh \
|
log_accel.hh log_data_helper.hh log_data_table.hh \
|
||||||
logfile.hh logfile_sub_source.hh pcrepp.hh piper_proc.hh \
|
log_format.hh log_format_loader.hh logfile.hh \
|
||||||
ptimec.hh readline_curses.hh readline_highlighters.hh \
|
logfile_sub_source.hh pcrepp.hh piper_proc.hh \
|
||||||
sequence_matcher.hh sequence_sink.hh session_data.hh \
|
pretty_printer.hh ptimec.hh readline_curses.hh \
|
||||||
shared_buffer.hh sql_util.hh sqlite-extension-func.h \
|
readline_highlighters.hh sequence_matcher.hh sequence_sink.hh \
|
||||||
status_controllers.hh statusview_curses.hh strnatcmp.h \
|
session_data.hh shared_buffer.hh sql_util.hh \
|
||||||
strong_int.hh sysclip.hh termios_guard.hh term_extra.hh \
|
sqlite-extension-func.h status_controllers.hh \
|
||||||
textfile_sub_source.hh textview_curses.hh time_T.hh \
|
statusview_curses.hh strnatcmp.h strong_int.hh sysclip.hh \
|
||||||
top_status_source.hh view_curses.hh vt52_curses.hh \
|
termios_guard.hh term_extra.hh textfile_sub_source.hh \
|
||||||
log_vtab_impl.hh log_format_impls.cc xterm_mouse.hh yajlpp.hh \
|
textview_curses.hh time_T.hh top_status_source.hh \
|
||||||
|
view_curses.hh vt52_curses.hh log_vtab_impl.hh \
|
||||||
|
log_format_impls.cc xterm_mouse.hh yajlpp.hh \
|
||||||
spookyhash/SpookyV2.h $(am__append_1)
|
spookyhash/SpookyV2.h $(am__append_1)
|
||||||
libdiag_a_SOURCES = ansi_scrubber.cc bookmarks.cc \
|
libdiag_a_SOURCES = ansi_scrubber.cc bookmarks.cc \
|
||||||
collation-functions.cc db_sub_source.cc environ_vtab.cc \
|
collation-functions.cc db_sub_source.cc environ_vtab.cc \
|
||||||
|
@ -227,17 +227,17 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void update_filtered(logfile_sub_source &lss)
|
void update_filtered(text_sub_source *tss)
|
||||||
{
|
{
|
||||||
status_field &sf = this->bss_fields[BSF_FILTERED];
|
status_field &sf = this->bss_fields[BSF_FILTERED];
|
||||||
|
|
||||||
if (lss.get_filtered_count() == 0) {
|
if (tss == NULL || tss->get_filtered_count() == 0) {
|
||||||
sf.clear();
|
sf.clear();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui_periodic_timer &timer = ui_periodic_timer::singleton();
|
ui_periodic_timer &timer = ui_periodic_timer::singleton();
|
||||||
|
|
||||||
if (lss.get_filtered_count() == this->bss_last_filtered_count) {
|
if (tss->get_filtered_count() == this->bss_last_filtered_count) {
|
||||||
|
|
||||||
if (timer.fade_diff(this->bss_filter_counter) == 0) {
|
if (timer.fade_diff(this->bss_filter_counter) == 0) {
|
||||||
this->bss_fields[BSF_FILTERED].set_role(
|
this->bss_fields[BSF_FILTERED].set_role(
|
||||||
@ -247,10 +247,10 @@ public:
|
|||||||
else {
|
else {
|
||||||
this->bss_fields[BSF_FILTERED].set_role(
|
this->bss_fields[BSF_FILTERED].set_role(
|
||||||
view_colors::VCR_ALERT_STATUS);
|
view_colors::VCR_ALERT_STATUS);
|
||||||
this->bss_last_filtered_count = lss.get_filtered_count();
|
this->bss_last_filtered_count = tss->get_filtered_count();
|
||||||
timer.start_fade(this->bss_filter_counter, 3);
|
timer.start_fade(this->bss_filter_counter, 3);
|
||||||
}
|
}
|
||||||
sf.set_value("%'9d Not Shown", lss.get_filtered_count());
|
sf.set_value("%'9d Not Shown", tss->get_filtered_count());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
106
src/filter_observer.hh
Normal file
106
src/filter_observer.hh
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015, Timothy Stack
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __filter_observer_hh
|
||||||
|
#define __filter_observer_hh
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "logfile.hh"
|
||||||
|
#include "textview_curses.hh"
|
||||||
|
|
||||||
|
class line_filter_observer : public logline_observer {
|
||||||
|
public:
|
||||||
|
line_filter_observer(filter_stack &fs, logfile *lf)
|
||||||
|
: lfo_filter_stack(fs), lfo_filter_state(lf) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void logline_new_line(const logfile &lf, logfile::const_iterator ll, shared_buffer_ref &sbr) {
|
||||||
|
long offset = std::distance(lf.begin(), ll);
|
||||||
|
|
||||||
|
require(&lf == this->lfo_filter_state.tfs_logfile);
|
||||||
|
|
||||||
|
this->lfo_filter_state.resize(lf.size());
|
||||||
|
if (!this->lfo_filter_stack.empty()) {
|
||||||
|
if (lf.get_format() != NULL) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool excluded(uint32_t filter_in_mask, uint32_t filter_out_mask,
|
||||||
|
size_t offset) const {
|
||||||
|
bool filtered_in = (filter_in_mask == 0) || (
|
||||||
|
this->lfo_filter_state.tfs_mask[offset] & filter_in_mask) != 0;
|
||||||
|
bool filtered_out = (
|
||||||
|
this->lfo_filter_state.tfs_mask[offset] & filter_out_mask) != 0;
|
||||||
|
return !filtered_in || filtered_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
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()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
};
|
||||||
|
|
||||||
|
filter_stack &lfo_filter_stack;
|
||||||
|
logfile_filter_state lfo_filter_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -386,7 +386,8 @@ COMMANDS
|
|||||||
expression. This command can be used multiple
|
expression. This command can be used multiple
|
||||||
times to add more lines to the display. The number
|
times to add more lines to the display. The number
|
||||||
of lines that are filtered out will be shown in the
|
of lines that are filtered out will be shown in the
|
||||||
bottom status bar as 'Not Shown'.
|
bottom status bar as 'Not Shown'. Note that filtering
|
||||||
|
only works in the log and plain text views.
|
||||||
|
|
||||||
filter-out <regex>
|
filter-out <regex>
|
||||||
Do not display lines that match the given regular
|
Do not display lines that match the given regular
|
||||||
@ -396,7 +397,8 @@ COMMANDS
|
|||||||
priority and the filter-out will remove lines that
|
priority and the filter-out will remove lines that
|
||||||
were matched by the 'filter-in'. The number
|
were matched by the 'filter-in'. The number
|
||||||
of lines that are filtered out will be shown in the
|
of lines that are filtered out will be shown in the
|
||||||
bottom status bar as 'Not Shown'.
|
bottom status bar as 'Not Shown'. Note that filtering
|
||||||
|
only works in the log and plain text views.
|
||||||
|
|
||||||
disable-filter <regex>
|
disable-filter <regex>
|
||||||
Disable an active 'filter-in' or 'filter-out'
|
Disable an active 'filter-in' or 'filter-out'
|
||||||
|
169
src/lnav.cc
169
src/lnav.cc
@ -576,6 +576,28 @@ static void add_env_possibilities(int context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_filter_possibilities(textview_curses *tc)
|
||||||
|
{
|
||||||
|
readline_curses *rc = lnav_data.ld_rl_view;
|
||||||
|
text_sub_source *tss = tc->get_sub_source();
|
||||||
|
filter_stack &fs = tss->get_filters();
|
||||||
|
|
||||||
|
rc->clear_possibilities(LNM_COMMAND, "disabled-filter");
|
||||||
|
rc->clear_possibilities(LNM_COMMAND, "enabled-filter");
|
||||||
|
for (filter_stack::iterator iter = fs.begin();
|
||||||
|
iter != fs.end();
|
||||||
|
++iter) {
|
||||||
|
text_filter *tf = *iter;
|
||||||
|
|
||||||
|
if (tf->is_enabled()) {
|
||||||
|
rc->add_possibility(LNM_COMMAND, "enabled-filter", tf->get_id());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rc->add_possibility(LNM_COMMAND, "disabled-filter", tf->get_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool setup_logline_table()
|
bool setup_logline_table()
|
||||||
{
|
{
|
||||||
// Hidden columns don't show up in the table_info pragma.
|
// Hidden columns don't show up in the table_info pragma.
|
||||||
@ -751,6 +773,41 @@ static void rebuild_hist(size_t old_count, bool force)
|
|||||||
hist_view.set_top(hs.row_for_value(old_time));
|
hist_view.set_top(hs.row_for_value(old_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class textfile_callback {
|
||||||
|
public:
|
||||||
|
textfile_callback() : force(false), front_file(NULL), front_top(-1) { };
|
||||||
|
|
||||||
|
void closed_file(logfile *lf) {
|
||||||
|
lnav_data.ld_file_names.erase(make_pair(lf->get_filename(), lf->get_fd()));
|
||||||
|
lnav_data.ld_files.remove(lf);
|
||||||
|
delete lf;
|
||||||
|
};
|
||||||
|
|
||||||
|
void promote_file(logfile *lf) {
|
||||||
|
if (lnav_data.ld_log_source.insert_file(lf)) {
|
||||||
|
force = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->closed_file(lf);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void scanned_file(logfile *lf) {
|
||||||
|
if (!lnav_data.ld_files_to_front.empty() &&
|
||||||
|
lnav_data.ld_files_to_front.front().first ==
|
||||||
|
lf->get_filename()) {
|
||||||
|
front_file = lf;
|
||||||
|
front_top = lnav_data.ld_files_to_front.front().second;
|
||||||
|
|
||||||
|
lnav_data.ld_files_to_front.pop_front();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool force;
|
||||||
|
logfile *front_file;
|
||||||
|
int front_top;
|
||||||
|
};
|
||||||
|
|
||||||
void rebuild_indexes(bool force)
|
void rebuild_indexes(bool force)
|
||||||
{
|
{
|
||||||
logfile_sub_source &lss = lnav_data.ld_log_source;
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
||||||
@ -772,63 +829,22 @@ void rebuild_indexes(bool force)
|
|||||||
{
|
{
|
||||||
textfile_sub_source * tss = &lnav_data.ld_text_source;
|
textfile_sub_source * tss = &lnav_data.ld_text_source;
|
||||||
std::list<logfile *>::iterator iter;
|
std::list<logfile *>::iterator iter;
|
||||||
logfile *front_file = NULL;
|
bool new_data;
|
||||||
int front_top = -1;
|
|
||||||
bool new_data = false;
|
|
||||||
|
|
||||||
old_bottom = text_view.get_top_for_last_row();
|
old_bottom = text_view.get_top_for_last_row();
|
||||||
scroll_down = (text_view.get_top() >= old_bottom &&
|
scroll_down = (text_view.get_top() >= old_bottom &&
|
||||||
!(lnav_data.ld_flags & LNF_HEADLESS));
|
!(lnav_data.ld_flags & LNF_HEADLESS));
|
||||||
|
|
||||||
for (iter = tss->tss_files.begin();
|
textfile_callback cb;
|
||||||
iter != tss->tss_files.end(); ) {
|
|
||||||
logfile *lf = (*iter);
|
|
||||||
|
|
||||||
if (!lf->exists() || lf->is_closed()) {
|
new_data = tss->rescan_files(cb);
|
||||||
lnav_data.ld_file_names.erase(make_pair(lf->get_filename(), lf->get_fd()));
|
force = force || cb.force;
|
||||||
iter = tss->tss_files.erase(iter);
|
|
||||||
lnav_data.ld_files.remove(lf);
|
|
||||||
delete lf;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
if (cb.front_file != NULL) {
|
||||||
bool new_text_data = (*iter)->rebuild_index();
|
|
||||||
|
|
||||||
if ((*iter)->get_format() != NULL) {
|
|
||||||
if (lnav_data.ld_log_source.insert_file(lf)) {
|
|
||||||
iter = tss->tss_files.erase(iter);
|
|
||||||
force = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
new_data = new_data || new_text_data;
|
|
||||||
if (!lnav_data.ld_files_to_front.empty() &&
|
|
||||||
lnav_data.ld_files_to_front.front().first ==
|
|
||||||
(*iter)->get_filename()) {
|
|
||||||
front_file = *iter;
|
|
||||||
front_top = lnav_data.ld_files_to_front.front().second;
|
|
||||||
|
|
||||||
lnav_data.ld_files_to_front.pop_front();
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const line_buffer::error &e) {
|
|
||||||
// TODO: log that we dropped this file.
|
|
||||||
iter = tss->tss_files.erase(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (front_file != NULL) {
|
|
||||||
ensure_view(&text_view);
|
ensure_view(&text_view);
|
||||||
|
|
||||||
if (tss->current_file() != front_file) {
|
if (tss->current_file() != cb.front_file) {
|
||||||
tss->tss_files.remove(front_file);
|
tss->to_front(cb.front_file);
|
||||||
tss->tss_files.push_front(front_file);
|
|
||||||
redo_search(LNV_TEXT);
|
redo_search(LNV_TEXT);
|
||||||
text_view.reload_data();
|
text_view.reload_data();
|
||||||
old_bottom = vis_line_t(-1);
|
old_bottom = vis_line_t(-1);
|
||||||
@ -836,11 +852,11 @@ void rebuild_indexes(bool force)
|
|||||||
new_data = false;
|
new_data = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (front_top < 0) {
|
if (cb.front_top < 0) {
|
||||||
front_top += text_view.get_inner_height();
|
cb.front_top += text_view.get_inner_height();
|
||||||
}
|
}
|
||||||
if (front_top < text_view.get_inner_height()) {
|
if (cb.front_top < text_view.get_inner_height()) {
|
||||||
text_view.set_top(vis_line_t(front_top));
|
text_view.set_top(vis_line_t(cb.front_top));
|
||||||
scroll_down = false;
|
scroll_down = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -873,7 +889,7 @@ void rebuild_indexes(bool force)
|
|||||||
|
|
||||||
if (!lf->exists() || lf->is_closed()) {
|
if (!lf->exists() || lf->is_closed()) {
|
||||||
lnav_data.ld_file_names.erase(make_pair(lf->get_filename(), lf->get_fd()));
|
lnav_data.ld_file_names.erase(make_pair(lf->get_filename(), lf->get_fd()));
|
||||||
lnav_data.ld_text_source.tss_files.remove(lf);
|
lnav_data.ld_text_source.remove(lf);
|
||||||
lnav_data.ld_log_source.remove_file(lf);
|
lnav_data.ld_log_source.remove_file(lf);
|
||||||
file_iter = lnav_data.ld_files.erase(file_iter);
|
file_iter = lnav_data.ld_files.erase(file_iter);
|
||||||
force = true;
|
force = true;
|
||||||
@ -933,8 +949,9 @@ void rebuild_indexes(bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lnav_data.ld_bottom_source.update_filtered(lss);
|
textview_curses *tc = lnav_data.ld_view_stack.top();
|
||||||
lnav_data.ld_scroll_broadcaster.invoke(lnav_data.ld_view_stack.top());
|
lnav_data.ld_bottom_source.update_filtered(tc->get_sub_source());
|
||||||
|
lnav_data.ld_scroll_broadcaster.invoke(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
class plain_text_source
|
class plain_text_source
|
||||||
@ -1177,9 +1194,13 @@ static void open_pretty_view(void)
|
|||||||
|
|
||||||
bool toggle_view(textview_curses *toggle_tc)
|
bool toggle_view(textview_curses *toggle_tc)
|
||||||
{
|
{
|
||||||
textview_curses *tc = lnav_data.ld_view_stack.top();
|
textview_curses *tc = lnav_data.ld_view_stack.empty() ? NULL : lnav_data.ld_view_stack.top();
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
|
require(toggle_tc != NULL);
|
||||||
|
require(toggle_tc >= &lnav_data.ld_views[0]);
|
||||||
|
require(toggle_tc < &lnav_data.ld_views[LNV__MAX]);
|
||||||
|
|
||||||
if (tc == toggle_tc) {
|
if (tc == toggle_tc) {
|
||||||
lnav_data.ld_view_stack.pop();
|
lnav_data.ld_view_stack.pop();
|
||||||
}
|
}
|
||||||
@ -1222,15 +1243,18 @@ void redo_search(lnav_view_t view_index)
|
|||||||
* Ensure that the view is on the top of the view stack.
|
* Ensure that the view is on the top of the view stack.
|
||||||
*
|
*
|
||||||
* @param expected_tc The text view that should be on top.
|
* @param expected_tc The text view that should be on top.
|
||||||
|
* @return True if the view was already on the top of the stack.
|
||||||
*/
|
*/
|
||||||
void ensure_view(textview_curses *expected_tc)
|
bool ensure_view(textview_curses *expected_tc)
|
||||||
{
|
{
|
||||||
textview_curses *tc = lnav_data.ld_view_stack.top();
|
textview_curses *tc = lnav_data.ld_view_stack.empty() ? NULL : lnav_data.ld_view_stack.top();
|
||||||
|
bool retval = true;
|
||||||
|
|
||||||
if (tc != expected_tc) {
|
if (tc != expected_tc) {
|
||||||
|
|
||||||
toggle_view(expected_tc);
|
toggle_view(expected_tc);
|
||||||
|
retval = false;
|
||||||
}
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vis_line_t next_cluster(
|
static vis_line_t next_cluster(
|
||||||
@ -1509,9 +1533,8 @@ static void handle_paging_key(int ch)
|
|||||||
else if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
else if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
||||||
textfile_sub_source &tss = lnav_data.ld_text_source;
|
textfile_sub_source &tss = lnav_data.ld_text_source;
|
||||||
|
|
||||||
if (!tss.tss_files.empty()) {
|
if (!tss.empty()) {
|
||||||
tss.tss_files.push_front(tss.tss_files.back());
|
tss.rotate_right();
|
||||||
tss.tss_files.pop_back();
|
|
||||||
redo_search(LNV_TEXT);
|
redo_search(LNV_TEXT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1524,9 +1547,8 @@ static void handle_paging_key(int ch)
|
|||||||
else if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
else if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
||||||
textfile_sub_source &tss = lnav_data.ld_text_source;
|
textfile_sub_source &tss = lnav_data.ld_text_source;
|
||||||
|
|
||||||
if (!tss.tss_files.empty()) {
|
if (!tss.empty()) {
|
||||||
tss.tss_files.push_back(tss.tss_files.front());
|
tss.rotate_left();
|
||||||
tss.tss_files.pop_front();
|
|
||||||
redo_search(LNV_TEXT);
|
redo_search(LNV_TEXT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1956,15 +1978,13 @@ static void handle_paging_key(int ch)
|
|||||||
"line-time",
|
"line-time",
|
||||||
buffer);
|
buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_view_text_possibilities(LNM_COMMAND, "filter", tc);
|
add_view_text_possibilities(LNM_COMMAND, "filter", tc);
|
||||||
lnav_data.ld_rl_view->
|
lnav_data.ld_rl_view->
|
||||||
add_possibility(LNM_COMMAND, "filter",
|
add_possibility(LNM_COMMAND, "filter",
|
||||||
lnav_data.ld_last_search[tc - lnav_data.ld_views]);
|
lnav_data.ld_last_search[tc - lnav_data.ld_views]);
|
||||||
lnav_data.ld_rl_view->add_possibility(
|
add_filter_possibilities(tc);
|
||||||
LNM_COMMAND, "levelname", logline::level_names);
|
|
||||||
lnav_data.ld_mode = LNM_COMMAND;
|
lnav_data.ld_mode = LNM_COMMAND;
|
||||||
lnav_data.ld_rl_view->focus(LNM_COMMAND, ":");
|
lnav_data.ld_rl_view->focus(LNM_COMMAND, ":");
|
||||||
lnav_data.ld_bottom_source.set_prompt("Enter an lnav command: "
|
lnav_data.ld_bottom_source.set_prompt("Enter an lnav command: "
|
||||||
@ -3133,7 +3153,7 @@ static void watch_logfile(string filename, int fd, bool required)
|
|||||||
log_info("loading new file: %s", filename.c_str());
|
log_info("loading new file: %s", filename.c_str());
|
||||||
lf->set_logfile_observer(&obs);
|
lf->set_logfile_observer(&obs);
|
||||||
lnav_data.ld_files.push_back(lf);
|
lnav_data.ld_files.push_back(lf);
|
||||||
lnav_data.ld_text_source.tss_files.push_back(lf);
|
lnav_data.ld_text_source.push_back(lf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3565,6 +3585,9 @@ static void looper(void)
|
|||||||
lnav_data.ld_rl_view->add_possibility(
|
lnav_data.ld_rl_view->add_possibility(
|
||||||
LNM_COMMAND, "viewname", lnav_view_strings);
|
LNM_COMMAND, "viewname", lnav_view_strings);
|
||||||
|
|
||||||
|
lnav_data.ld_rl_view->add_possibility(
|
||||||
|
LNM_COMMAND, "levelname", logline::level_names);
|
||||||
|
|
||||||
(void)signal(SIGINT, sigint);
|
(void)signal(SIGINT, sigint);
|
||||||
(void)signal(SIGTERM, sigint);
|
(void)signal(SIGTERM, sigint);
|
||||||
(void)signal(SIGWINCH, sigwinch);
|
(void)signal(SIGWINCH, sigwinch);
|
||||||
|
@ -222,7 +222,7 @@ extern struct _lnav_data lnav_data;
|
|||||||
|
|
||||||
void rebuild_indexes(bool force);
|
void rebuild_indexes(bool force);
|
||||||
|
|
||||||
void ensure_view(textview_curses *expected_tc);
|
bool ensure_view(textview_curses *expected_tc);
|
||||||
bool toggle_view(textview_curses *toggle_tc);
|
bool toggle_view(textview_curses *toggle_tc);
|
||||||
|
|
||||||
std::string execute_command(std::string cmdline);
|
std::string execute_command(std::string cmdline);
|
||||||
|
@ -871,12 +871,6 @@ static string com_enable_filter(string cmdline, vector<string> &args)
|
|||||||
fs.set_filter_enabled(lf, true);
|
fs.set_filter_enabled(lf, true);
|
||||||
tss->text_filters_changed();
|
tss->text_filters_changed();
|
||||||
tc->reload_data();
|
tc->reload_data();
|
||||||
if (lnav_data.ld_rl_view != NULL) {
|
|
||||||
lnav_data.ld_rl_view->rem_possibility(
|
|
||||||
LNM_COMMAND, "disabled-filter", args[1]);
|
|
||||||
lnav_data.ld_rl_view->add_possibility(
|
|
||||||
LNM_COMMAND, "enabled-filter", args[1]);
|
|
||||||
}
|
|
||||||
retval = "info: filter enabled";
|
retval = "info: filter enabled";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -909,12 +903,6 @@ static string com_disable_filter(string cmdline, vector<string> &args)
|
|||||||
fs.set_filter_enabled(lf, false);
|
fs.set_filter_enabled(lf, false);
|
||||||
tss->text_filters_changed();
|
tss->text_filters_changed();
|
||||||
tc->reload_data();
|
tc->reload_data();
|
||||||
if (lnav_data.ld_rl_view != NULL) {
|
|
||||||
lnav_data.ld_rl_view->rem_possibility(
|
|
||||||
LNM_COMMAND, "enabled-filter", args[1]);
|
|
||||||
lnav_data.ld_rl_view->add_possibility(
|
|
||||||
LNM_COMMAND, "disabled-filter", args[1]);
|
|
||||||
}
|
|
||||||
retval = "info: filter disabled";
|
retval = "info: filter disabled";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1205,14 +1193,14 @@ static string com_close(string cmdline, vector<string> &args)
|
|||||||
if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
||||||
textfile_sub_source &tss = lnav_data.ld_text_source;
|
textfile_sub_source &tss = lnav_data.ld_text_source;
|
||||||
|
|
||||||
if (tss.tss_files.empty()) {
|
if (tss.empty()) {
|
||||||
retval = "error: no text files are opened";
|
retval = "error: no text files are opened";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fn = tss.current_file()->get_filename();
|
fn = tss.current_file()->get_filename();
|
||||||
tss.current_file()->close();
|
tss.current_file()->close();
|
||||||
|
|
||||||
if (tss.tss_files.size() == 1) {
|
if (tss.size() == 1) {
|
||||||
lnav_data.ld_view_stack.pop();
|
lnav_data.ld_view_stack.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,9 @@ void logfile::read_full_message(logfile::iterator ll,
|
|||||||
void logfile::set_logline_observer(logline_observer *llo)
|
void logfile::set_logline_observer(logline_observer *llo)
|
||||||
{
|
{
|
||||||
this->lf_logline_observer = llo;
|
this->lf_logline_observer = llo;
|
||||||
this->reobserve_from(this->begin());
|
if (llo != NULL) {
|
||||||
|
this->reobserve_from(this->begin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void logfile::reobserve_from(iterator iter)
|
void logfile::reobserve_from(iterator iter)
|
||||||
|
@ -304,6 +304,10 @@ public:
|
|||||||
|
|
||||||
void set_logline_observer(logline_observer *llo);
|
void set_logline_observer(logline_observer *llo);
|
||||||
|
|
||||||
|
logline_observer *get_logline_observer() const {
|
||||||
|
return this->lf_logline_observer;
|
||||||
|
};
|
||||||
|
|
||||||
bool operator<(const logfile &rhs) const
|
bool operator<(const logfile &rhs) const
|
||||||
{
|
{
|
||||||
bool retval;
|
bool retval;
|
||||||
|
@ -47,77 +47,10 @@
|
|||||||
#include "bookmarks.hh"
|
#include "bookmarks.hh"
|
||||||
#include "chunky_index.hh"
|
#include "chunky_index.hh"
|
||||||
#include "textview_curses.hh"
|
#include "textview_curses.hh"
|
||||||
|
#include "filter_observer.hh"
|
||||||
|
|
||||||
STRONG_INT_TYPE(uint64_t, content_line);
|
STRONG_INT_TYPE(uint64_t, content_line);
|
||||||
|
|
||||||
class line_filter_observer : public logline_observer {
|
|
||||||
public:
|
|
||||||
line_filter_observer(filter_stack &fs, logfile *lf)
|
|
||||||
: lfo_filter_stack(fs), lfo_filter_state(lf) {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void logline_new_line(const logfile &lf, logfile::const_iterator ll, shared_buffer_ref &sbr) {
|
|
||||||
long offset = std::distance(lf.begin(), ll);
|
|
||||||
|
|
||||||
require(&lf == this->lfo_filter_state.tfs_logfile);
|
|
||||||
|
|
||||||
this->lfo_filter_state.resize(lf.size());
|
|
||||||
if (!this->lfo_filter_stack.empty()) {
|
|
||||||
if (lf.get_format() != NULL) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool excluded(uint32_t filter_in_mask, uint32_t filter_out_mask,
|
|
||||||
size_t offset) const {
|
|
||||||
bool filtered_in = (filter_in_mask == 0) || (
|
|
||||||
this->lfo_filter_state.tfs_mask[offset] & filter_in_mask) != 0;
|
|
||||||
bool filtered_out = (
|
|
||||||
this->lfo_filter_state.tfs_mask[offset] & filter_out_mask) != 0;
|
|
||||||
return !filtered_in || filtered_out;
|
|
||||||
};
|
|
||||||
|
|
||||||
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()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
};
|
|
||||||
|
|
||||||
filter_stack &lfo_filter_stack;
|
|
||||||
logfile_filter_state lfo_filter_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate class that merges the contents of multiple log files into a single
|
* Delegate class that merges the contents of multiple log files into a single
|
||||||
* source of data for a text view.
|
* source of data for a text view.
|
||||||
|
@ -753,20 +753,30 @@ static int read_word_wrap(yajlpp_parse_context *ypc, int value)
|
|||||||
static int read_commands(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
|
static int read_commands(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
|
||||||
{
|
{
|
||||||
std::string cmdline = std::string((const char *)str, len);
|
std::string cmdline = std::string((const char *)str, len);
|
||||||
|
const char ** view_name;
|
||||||
|
int view_index;
|
||||||
|
|
||||||
|
view_name = find(lnav_view_strings,
|
||||||
|
lnav_view_strings + LNV__MAX,
|
||||||
|
ypc->get_path_fragment(-3));
|
||||||
|
view_index = view_name - lnav_view_strings;
|
||||||
|
bool active = ensure_view(&lnav_data.ld_views[view_index]);
|
||||||
execute_command(cmdline);
|
execute_command(cmdline);
|
||||||
|
if (!active) {
|
||||||
|
lnav_data.ld_view_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct json_path_handler view_info_handlers[] = {
|
static struct json_path_handler view_info_handlers[] = {
|
||||||
json_path_handler("/save-time", read_save_time),
|
json_path_handler("^/save-time", read_save_time),
|
||||||
json_path_handler("/time-offset", read_time_offset),
|
json_path_handler("^/time-offset", read_time_offset),
|
||||||
json_path_handler("/files#", read_files),
|
json_path_handler("^/files#", read_files),
|
||||||
json_path_handler("/views/([^/]+)/top_line", read_top_line),
|
json_path_handler("^/views/([^/]+)/top_line", read_top_line),
|
||||||
json_path_handler("/views/([^/]+)/search", read_last_search),
|
json_path_handler("^/views/([^/]+)/search", read_last_search),
|
||||||
json_path_handler("/views/([^/]+)/word_wrap", read_word_wrap),
|
json_path_handler("^/views/([^/]+)/word_wrap", read_word_wrap),
|
||||||
json_path_handler("/commands#", read_commands),
|
json_path_handler("^/views/([^/]+)/commands#", read_commands),
|
||||||
|
|
||||||
json_path_handler()
|
json_path_handler()
|
||||||
};
|
};
|
||||||
@ -1257,22 +1267,22 @@ void save_session(void)
|
|||||||
cmd_array.gen((*filter_iter)->to_command());
|
cmd_array.gen((*filter_iter)->to_command());
|
||||||
}
|
}
|
||||||
|
|
||||||
textview_curses::highlight_map_t &hmap =
|
if (lpc == LNV_LOG) {
|
||||||
lnav_data.ld_views[LNV_LOG].get_highlights();
|
textview_curses::highlight_map_t &hmap =
|
||||||
textview_curses::highlight_map_t::iterator hl_iter;
|
lnav_data.ld_views[LNV_LOG].get_highlights();
|
||||||
|
textview_curses::highlight_map_t::iterator hl_iter;
|
||||||
|
|
||||||
for (hl_iter = hmap.begin();
|
for (hl_iter = hmap.begin();
|
||||||
hl_iter != hmap.end();
|
hl_iter != hmap.end();
|
||||||
++hl_iter) {
|
++hl_iter) {
|
||||||
if (hl_iter->first[0] == '$') {
|
if (hl_iter->first[0] == '$') {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
cmd_array.gen("highlight " + hl_iter->first);
|
||||||
}
|
}
|
||||||
cmd_array.gen("highlight " + hl_iter->first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root_map.gen("commands");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yajl_gen_clear(handle);
|
yajl_gen_clear(handle);
|
||||||
@ -1281,6 +1291,8 @@ void save_session(void)
|
|||||||
fclose(file.release());
|
fclose(file.release());
|
||||||
|
|
||||||
rename(view_file_tmp_name.c_str(), view_file_name.c_str());
|
rename(view_file_tmp_name.c_str(), view_file_name.c_str());
|
||||||
|
|
||||||
|
log_debug("Saved session: %s", view_file_name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "logfile.hh"
|
#include "logfile.hh"
|
||||||
#include "textview_curses.hh"
|
#include "textview_curses.hh"
|
||||||
|
#include "filter_observer.hh"
|
||||||
|
|
||||||
class textfile_sub_source : public text_sub_source {
|
class textfile_sub_source : public text_sub_source {
|
||||||
public:
|
public:
|
||||||
@ -41,12 +42,22 @@ public:
|
|||||||
|
|
||||||
textfile_sub_source() { };
|
textfile_sub_source() { };
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return this->tss_files.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return this->tss_files.size();
|
||||||
|
}
|
||||||
|
|
||||||
size_t text_line_count()
|
size_t text_line_count()
|
||||||
{
|
{
|
||||||
size_t retval = 0;
|
size_t retval = 0;
|
||||||
|
|
||||||
if (!this->tss_files.empty()) {
|
if (!this->tss_files.empty()) {
|
||||||
retval = this->current_file()->size();
|
logfile *lf = this->current_file();
|
||||||
|
line_filter_observer *lfo = (line_filter_observer *) lf->get_logline_observer();
|
||||||
|
retval = lfo->lfo_filter_state.tfs_index.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@ -58,8 +69,9 @@ public:
|
|||||||
bool raw = false)
|
bool raw = false)
|
||||||
{
|
{
|
||||||
if (!this->tss_files.empty()) {
|
if (!this->tss_files.empty()) {
|
||||||
this->current_file()->
|
logfile *lf = this->current_file();
|
||||||
read_line(this->current_file()->begin() + line, value_out);
|
line_filter_observer *lfo = (line_filter_observer *) lf->get_logline_observer();
|
||||||
|
lf->read_line(lf->begin() + lfo->lfo_filter_state.tfs_index[line], value_out);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
value_out.clear();
|
value_out.clear();
|
||||||
@ -85,7 +97,9 @@ public:
|
|||||||
size_t retval = 0;
|
size_t retval = 0;
|
||||||
|
|
||||||
if (!this->tss_files.empty()) {
|
if (!this->tss_files.empty()) {
|
||||||
retval = this->current_file()->line_length(this->current_file()->begin() + line);
|
logfile *lf = this->current_file();
|
||||||
|
line_filter_observer *lfo = (line_filter_observer *) lf->get_logline_observer();
|
||||||
|
retval = lf->line_length(lf->begin() + lfo->lfo_filter_state.tfs_index[line]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@ -106,8 +120,135 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this->tss_files.front()->get_filename();
|
return this->tss_files.front()->get_filename();
|
||||||
|
};
|
||||||
|
|
||||||
|
void to_front(logfile *lf) {
|
||||||
|
this->tss_files.remove(lf);
|
||||||
|
this->tss_files.push_front(lf);
|
||||||
|
};
|
||||||
|
|
||||||
|
void rotate_left() {
|
||||||
|
this->tss_files.push_back(this->tss_files.front());
|
||||||
|
this->tss_files.pop_front();
|
||||||
|
};
|
||||||
|
|
||||||
|
void rotate_right() {
|
||||||
|
this->tss_files.push_front(this->tss_files.back());
|
||||||
|
this->tss_files.pop_back();
|
||||||
|
};
|
||||||
|
|
||||||
|
void remove(logfile *lf) {
|
||||||
|
file_iterator iter = std::find(this->tss_files.begin(),
|
||||||
|
this->tss_files.end(), lf);
|
||||||
|
if (iter != this->tss_files.end()) {
|
||||||
|
detach_observer(lf);
|
||||||
|
this->tss_files.erase(iter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void push_back(logfile *lf) {
|
||||||
|
line_filter_observer *lfo = new line_filter_observer(
|
||||||
|
this->get_filters(), lf);
|
||||||
|
lf->set_logline_observer(lfo);
|
||||||
|
this->tss_files.push_back(lf);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T> bool rescan_files(T &callback) {
|
||||||
|
file_iterator iter;
|
||||||
|
bool retval = false;
|
||||||
|
|
||||||
|
for (iter = this->tss_files.begin(); iter != this->tss_files.end();) {
|
||||||
|
logfile *lf = (*iter);
|
||||||
|
|
||||||
|
if (!lf->exists() || lf->is_closed()) {
|
||||||
|
iter = this->tss_files.erase(iter);
|
||||||
|
this->detach_observer(lf);
|
||||||
|
callback.closed_file(lf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uint32_t old_size = lf->size();
|
||||||
|
bool new_text_data = lf->rebuild_index();
|
||||||
|
|
||||||
|
if (lf->get_format() != NULL) {
|
||||||
|
iter = this->tss_files.erase(iter);
|
||||||
|
this->detach_observer(lf);
|
||||||
|
callback.promote_file(lf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = retval || new_text_data;
|
||||||
|
callback.scanned_file(lf);
|
||||||
|
|
||||||
|
uint32_t filter_in_mask, filter_out_mask;
|
||||||
|
|
||||||
|
this->get_filters().get_enabled_mask(filter_in_mask, filter_out_mask);
|
||||||
|
line_filter_observer *lfo = (line_filter_observer *) lf->get_logline_observer();
|
||||||
|
for (uint32_t lpc = old_size; lpc < lf->size(); lpc++) {
|
||||||
|
if (lfo->excluded(filter_in_mask, filter_out_mask, lpc)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lfo->lfo_filter_state.tfs_index.push_back(lpc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const line_buffer::error &e) {
|
||||||
|
iter = this->tss_files.erase(iter);
|
||||||
|
lf->close();
|
||||||
|
this->detach_observer(lf);
|
||||||
|
callback.closed_file(lf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void text_filters_changed() {
|
||||||
|
logfile *lf = this->current_file();
|
||||||
|
|
||||||
|
if (lf == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_filter_observer *lfo = (line_filter_observer *) lf->get_logline_observer();
|
||||||
|
uint32_t filter_in_mask, filter_out_mask;
|
||||||
|
|
||||||
|
lf->reobserve_from(lf->begin() + lfo->get_min_count(lf->size()));
|
||||||
|
|
||||||
|
this->get_filters().get_enabled_mask(filter_in_mask, filter_out_mask);
|
||||||
|
lfo->lfo_filter_state.tfs_index.clear();
|
||||||
|
for (uint32_t lpc = 0; lpc < lf->size(); lpc++) {
|
||||||
|
if (lfo->excluded(filter_in_mask, filter_out_mask, lpc)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lfo->lfo_filter_state.tfs_index.push_back(lpc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int get_filtered_count() const {
|
||||||
|
logfile *lf = this->current_file();
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (lf != NULL) {
|
||||||
|
line_filter_observer *lfo = (line_filter_observer *) lf->get_logline_observer();
|
||||||
|
retval = lf->size() - lfo->lfo_filter_state.tfs_index.size();
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void detach_observer(logfile *lf) {
|
||||||
|
line_filter_observer *lfo = (line_filter_observer *) lf->get_logline_observer();
|
||||||
|
lf->set_logline_observer(NULL);
|
||||||
|
if (lfo != NULL) {
|
||||||
|
delete lfo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::list<logfile *> tss_files;
|
std::list<logfile *> tss_files;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,6 +74,7 @@ public:
|
|||||||
logfile *tfs_logfile;
|
logfile *tfs_logfile;
|
||||||
size_t tfs_filter_count[MAX_FILTERS];
|
size_t tfs_filter_count[MAX_FILTERS];
|
||||||
std::vector<uint32_t> tfs_mask;
|
std::vector<uint32_t> tfs_mask;
|
||||||
|
std::vector<uint32_t> tfs_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
class text_filter {
|
class text_filter {
|
||||||
@ -345,6 +346,10 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual int get_filtered_count() const {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
filter_stack tss_filters;
|
filter_stack tss_filters;
|
||||||
};
|
};
|
||||||
@ -356,7 +361,7 @@ public:
|
|||||||
virtual void text_overlay(textview_curses &tc) { };
|
virtual void text_overlay(textview_curses &tc) { };
|
||||||
|
|
||||||
virtual bool text_handle_mouse(textview_curses &tc, mouse_event &me) {
|
virtual bool text_handle_mouse(textview_curses &tc, mouse_event &me) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,7 +145,9 @@ public:
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sf_format.clear();
|
sf_format.clear();
|
||||||
sf_filename.set_value(lc->get_data_source()->listview_source_name(*lc));
|
if (lc->get_data_source() != NULL) {
|
||||||
|
sf_filename.set_value(lc->get_data_source()->listview_source_name(*lc));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sf_format.get_value().get_attrs().push_back(
|
sf_format.get_value().get_attrs().push_back(
|
||||||
string_attr(lr, &view_curses::VC_STYLE,
|
string_attr(lr, &view_curses::VC_STYLE,
|
||||||
|
@ -226,6 +226,7 @@ dist_noinst_DATA = \
|
|||||||
logfile_json.json \
|
logfile_json.json \
|
||||||
logfile_multiline.0 \
|
logfile_multiline.0 \
|
||||||
logfile_openam.0 \
|
logfile_openam.0 \
|
||||||
|
logfile_plain.0 \
|
||||||
logfile_strace_log.0 \
|
logfile_strace_log.0 \
|
||||||
logfile_syslog.0 \
|
logfile_syslog.0 \
|
||||||
logfile_syslog.1 \
|
logfile_syslog.1 \
|
||||||
|
@ -821,6 +821,7 @@ dist_noinst_DATA = \
|
|||||||
logfile_json.json \
|
logfile_json.json \
|
||||||
logfile_multiline.0 \
|
logfile_multiline.0 \
|
||||||
logfile_openam.0 \
|
logfile_openam.0 \
|
||||||
|
logfile_plain.0 \
|
||||||
logfile_strace_log.0 \
|
logfile_strace_log.0 \
|
||||||
logfile_syslog.0 \
|
logfile_syslog.0 \
|
||||||
logfile_syslog.1 \
|
logfile_syslog.1 \
|
||||||
|
3
test/logfile_plain.0
Normal file
3
test/logfile_plain.0
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Hello, World!
|
||||||
|
How are you?
|
||||||
|
Goodbye, World!
|
@ -142,6 +142,24 @@ Dec 6 13:01:34 ubu-mac dnsmasq-dhcp[1840]: read /var/lib/libvirt/dnsmasq/defaul
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
run_test ${lnav_test} -n \
|
||||||
|
-c ":switch-to-view text" \
|
||||||
|
-c ":filter-in World" \
|
||||||
|
${test_dir}/logfile_plain.0
|
||||||
|
check_output "plain text filter-in is not working" <<EOF
|
||||||
|
Hello, World!
|
||||||
|
Goodbye, World!
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run_test ${lnav_test} -n \
|
||||||
|
-c ":switch-to-view text" \
|
||||||
|
-c ":filter-out World" \
|
||||||
|
${test_dir}/logfile_plain.0
|
||||||
|
check_output "plain text filter-out is not working" <<EOF
|
||||||
|
How are you?
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
run_test ${lnav_test} -n \
|
run_test ${lnav_test} -n \
|
||||||
-c ":switch-to-view help" \
|
-c ":switch-to-view help" \
|
||||||
${test_dir}/logfile_access_log.0
|
${test_dir}/logfile_access_log.0
|
||||||
|
Loading…
Reference in New Issue
Block a user