[cmds] add :export-session command

This commit is contained in:
Timothy Stack 2022-07-20 22:01:17 -07:00
parent 1abc77e129
commit 6712a33163
24 changed files with 688 additions and 158 deletions

8
NEWS
View File

@ -60,6 +60,10 @@ lnav v0.11.0:
if none of the clipboard commands could be detected. Your if none of the clipboard commands could be detected. Your
terminal software will need to support the sequence and you may terminal software will need to support the sequence and you may
need to explicitly enable it in the terminal. need to explicitly enable it in the terminal.
* Added the ":export-session-to <path>" command that writes the
current session state to a file as a list of commands/SQL
statements. This script file can be executed to restore the
majority of the current state.
Breaking Changes: Breaking Changes:
* Added a 'language' column to the lnav_view_filters table that * Added a 'language' column to the lnav_view_filters table that
@ -84,6 +88,10 @@ lnav v0.11.0:
match log messages that are in that log format instead of all match log messages that are in that log format instead of all
log messages. As a benefit, the search table now includes log messages. As a benefit, the search table now includes
the columns that are defined as part of the format. the columns that are defined as part of the format.
* The lnav_view_filters table will treats the tuple of
(view_name, type, language, pattern) as a UNIQUE index and
will raise a conflict error on an INSERT. Use "REPLACE INTO"
instead of "INSERT INTO" to ignore conflict error.
Fixes: Fixes:
* Toggling enabled/disabled filters when there is a SQL expression * Toggling enabled/disabled filters when there is a SQL expression

View File

@ -334,6 +334,7 @@ add_library(
regex101.client.cc regex101.client.cc
regex101.import.cc regex101.import.cc
relative_time.cc relative_time.cc
session.export.cc
session_data.cc session_data.cc
sequence_matcher.cc sequence_matcher.cc
shlex.cc shlex.cc
@ -448,6 +449,7 @@ add_library(
safe/defaulttypes.h safe/defaulttypes.h
safe/mutableref.h safe/mutableref.h
safe/safe.h safe/safe.h
session.export.hh
sequence_sink.hh sequence_sink.hh
shlex.hh shlex.hh
shlex.resolver.hh shlex.resolver.hh

View File

@ -258,6 +258,7 @@ noinst_HEADERS = \
safe/mutableref.h \ safe/mutableref.h \
safe/safe.h \ safe/safe.h \
service_tags.hh \ service_tags.hh \
session.export.hh \
session_data.hh \ session_data.hh \
shared_buffer.hh \ shared_buffer.hh \
shlex.hh \ shlex.hh \
@ -418,6 +419,7 @@ libdiag_a_SOURCES = \
regex101.import.cc \ regex101.import.cc \
regexp_vtab.cc \ regexp_vtab.cc \
relative_time.cc \ relative_time.cc \
session.export.cc \
session_data.cc \ session_data.cc \
shared_buffer.cc \ shared_buffer.cc \
shlex.cc \ shlex.cc \

View File

@ -52,6 +52,17 @@ using free_func_t = void (*)(void*);
template<class T, free_func_t default_free = free> template<class T, free_func_t default_free = free>
class auto_mem { class auto_mem {
public: public:
static void noop_free(void*) {}
static auto_mem<T> leak(T* ptr)
{
auto_mem<T> retval(noop_free);
retval = ptr;
return retval;
}
explicit auto_mem(T* ptr = nullptr) explicit auto_mem(T* ptr = nullptr)
: am_ptr(ptr), am_free_func(default_free) : am_ptr(ptr), am_free_func(default_free)
{ {
@ -156,6 +167,8 @@ private:
class auto_buffer { class auto_buffer {
public: public:
using value_type = char;
static auto_buffer alloc(size_t capacity) static auto_buffer alloc(size_t capacity)
{ {
return auto_buffer{capacity == 0 ? nullptr : (char*) malloc(capacity), return auto_buffer{capacity == 0 ? nullptr : (char*) malloc(capacity),
@ -223,6 +236,14 @@ public:
const char* begin() const { return this->ab_buffer; } const char* begin() const { return this->ab_buffer; }
void push_back(char ch)
{
this->ab_buffer[this->ab_size] = ch;
this->ab_size += 1;
}
void pop_back() { this->ab_size -= 1; }
bool is_bit_set(size_t bit_offset) const bool is_bit_set(size_t bit_offset) const
{ {
size_t byte_offset = bit_offset / 8; size_t byte_offset = bit_offset / 8;

View File

@ -44,7 +44,7 @@
:alt-msg Press t to switch to the text view :alt-msg Press t to switch to the text view
**See Also** **See Also**
:ref:`echo`, :ref:`eval`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to` :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to`
---- ----
@ -67,7 +67,7 @@
:append-to /tmp/interesting-lines.txt :append-to /tmp/interesting-lines.txt
**See Also** **See Also**
:ref:`echo`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to` :ref:`echo`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to`
---- ----
@ -413,7 +413,7 @@
:echo Hello, World! :echo Hello, World!
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -472,7 +472,23 @@
:eval ;SELECT * FROM ${table} :eval ;SELECT * FROM ${table}
**See Also** **See Also**
:ref:`alt_msg`, :ref:`echo`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`echo`, :ref:`export_session_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to`
----
.. _export_session_to:
:export-session-to *path*
^^^^^^^^^^^^^^^^^^^^^^^^^
Export the current lnav state to an lnav script file
**Parameters**
* **path\*** --- The path to the file to write
**See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -884,7 +900,7 @@
:pipe-line-to sed -e 's/foo/bar/g' :pipe-line-to sed -e 's/foo/bar/g'
**See Also** **See Also**
:ref:`append_to`, :ref:`echo`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to` :ref:`append_to`, :ref:`echo`, :ref:`export_session_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to`
---- ----
@ -907,7 +923,7 @@
:pipe-to sed -e s/foo/bar/g :pipe-to sed -e s/foo/bar/g
**See Also** **See Also**
:ref:`append_to`, :ref:`echo`, :ref:`pipe_line_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to` :ref:`append_to`, :ref:`echo`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_view_to`
---- ----
@ -1029,7 +1045,7 @@
:redirect-to /tmp/script-output.txt :redirect-to /tmp/script-output.txt
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1417,7 +1433,7 @@
:write-table-to /tmp/table.txt :write-table-to /tmp/table.txt
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1440,7 +1456,7 @@
:write-csv-to /tmp/table.csv :write-csv-to /tmp/table.csv
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1463,7 +1479,7 @@
:write-json-to /tmp/table.json :write-json-to /tmp/table.json
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1486,7 +1502,7 @@
:write-jsonlines-to /tmp/table.json :write-jsonlines-to /tmp/table.json
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1510,7 +1526,7 @@
:write-raw-to /tmp/table.txt :write-raw-to /tmp/table.txt
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1533,7 +1549,7 @@
:write-screen-to /tmp/table.txt :write-screen-to /tmp/table.txt
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`, :ref:`write_view_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1556,7 +1572,7 @@
:write-to /tmp/interesting-lines.txt :write-to /tmp/interesting-lines.txt
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_view_to`, :ref:`write_view_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_view_to`, :ref:`write_view_to`
---- ----
@ -1579,7 +1595,7 @@
:write-view-to /tmp/table.txt :write-view-to /tmp/table.txt
**See Also** **See Also**
:ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to` :ref:`alt_msg`, :ref:`append_to`, :ref:`create_logline_table`, :ref:`create_search_table`, :ref:`echo`, :ref:`echo`, :ref:`eval`, :ref:`export_session_to`, :ref:`export_session_to`, :ref:`pipe_line_to`, :ref:`pipe_to`, :ref:`redirect_to`, :ref:`redirect_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_csv_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_json_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_jsonlines_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_raw_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_screen_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_table_to`, :ref:`write_to`, :ref:`write_to`
---- ----

View File

@ -58,6 +58,7 @@
#include "field_overlay_source.hh" #include "field_overlay_source.hh"
#include "fmt/printf.h" #include "fmt/printf.h"
#include "lnav.indexing.hh" #include "lnav.indexing.hh"
#include "session.export.hh"
#include "lnav_commands.hh" #include "lnav_commands.hh"
#include "lnav_config.hh" #include "lnav_config.hh"
#include "lnav_util.hh" #include "lnav_util.hh"
@ -3729,6 +3730,71 @@ com_save_session(exec_context& ec,
return Ok(std::string()); return Ok(std::string());
} }
static Result<std::string, lnav::console::user_message>
com_export_session_to(exec_context& ec,
std::string cmdline,
std::vector<std::string>& args)
{
if (args.empty()) {
args.emplace_back("filename");
} else if (!ec.ec_dry_run) {
auto_mem<FILE> outfile(fclose);
auto fn = trim(remaining_args(cmdline, args));
auto to_term = false;
if (fn == "-" || fn == "/dev/stdout") {
auto ec_out = ec.get_output();
if (!ec_out) {
outfile = auto_mem<FILE>::leak(stdout);
nodelay(lnav_data.ld_window, 0);
endwin();
struct termios curr_termios;
tcgetattr(1, &curr_termios);
curr_termios.c_oflag |= ONLCR | OPOST;
tcsetattr(1, TCSANOW, &curr_termios);
setvbuf(stdout, nullptr, _IONBF, 0);
to_term = true;
fprintf(outfile,
"\n---------------- Press any key to exit lo-fi display "
"----------------\n\n");
} else {
outfile = auto_mem<FILE>::leak(ec_out.value());
}
if (outfile.in() == stdout) {
lnav_data.ld_stdout_used = true;
}
} else if (fn == "/dev/clipboard") {
auto open_res = sysclip::open(sysclip::type_t::GENERAL);
if (open_res.isErr()) {
alerter::singleton().chime();
return ec.make_error("Unable to copy to clipboard: {}",
open_res.unwrapErr());
}
outfile = open_res.unwrap();
} else if (lnav_data.ld_flags & LNF_SECURE_MODE) {
return ec.make_error("{} -- unavailable in secure mode", args[0]);
} else if ((outfile = fopen(fn.c_str(), "w")) == nullptr) {
return ec.make_error("unable to open file -- {}", fn);
}
auto export_res = lnav::session::export_to(outfile.in());
if (export_res.isErr()) {
return Err(export_res.unwrapErr());
}
fflush(outfile.in());
if (to_term) {
cbreak();
getch();
refresh();
nodelay(lnav_data.ld_window, 1);
}
}
return Ok(std::string());
}
static Result<std::string, lnav::console::user_message> static Result<std::string, lnav::console::user_message>
com_set_min_log_level(exec_context& ec, com_set_min_log_level(exec_context& ec,
std::string cmdline, std::string cmdline,
@ -5521,6 +5587,13 @@ readline_context::command_t STD_COMMANDS[] = {
help_text(":save-session") help_text(":save-session")
.with_summary("Save the current state as a session")}, .with_summary("Save the current state as a session")},
{"export-session-to",
com_export_session_to,
help_text(":export-session-to")
.with_summary("Export the current lnav state to an lnav script file")
.with_parameter(help_text("path", "The path to the file to write"))
.with_tags({"io", "scripting"})},
{"set-min-log-level", {"set-min-log-level",
com_set_min_log_level, com_set_min_log_level,

View File

@ -35,6 +35,7 @@
#define lnav_util_hh #define lnav_util_hh
#include <future> #include <future>
#include <iterator>
#include <numeric> #include <numeric>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
@ -47,6 +48,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include "base/auto_mem.hh"
#include "base/intern_string.hh" #include "base/intern_string.hh"
#include "base/lnav.console.hh" #include "base/lnav.console.hh"
#include "base/result.h" #include "base/result.h"
@ -67,10 +69,10 @@
class hasher { class hasher {
public: public:
hasher() using array_t = byte_array<2, uint64_t>;
{ static constexpr size_t STRING_SIZE = array_t::STRING_SIZE;
this->h_context.Init(0, 0);
} hasher() { this->h_context.Init(0, 0); }
hasher& update(const std::string& str) hasher& update(const std::string& str)
{ {
@ -102,9 +104,17 @@ public:
return *this; return *this;
} }
void to_string(auto_buffer& buf)
{
array_t bits;
this->h_context.Final(bits.out(0), bits.out(1));
bits.to_string(std::back_inserter(buf));
}
std::string to_string() std::string to_string()
{ {
byte_array<2, uint64> bits; array_t bits;
this->h_context.Final(bits.out(0), bits.out(1)); this->h_context.Final(bits.out(0), bits.out(1));
return bits.to_string(); return bits.to_string();

View File

@ -74,7 +74,8 @@ static const char* LOG_FOOTER_COLUMNS = R"(
log_unique_path TEXT HIDDEN COLLATE naturalnocase, -- The unique portion of the path this message is from log_unique_path TEXT HIDDEN COLLATE naturalnocase, -- The unique portion of the path this message is from
log_text TEXT HIDDEN, -- The full text of the log message log_text TEXT HIDDEN, -- The full text of the log message
log_body TEXT HIDDEN, -- The body of the log message log_body TEXT HIDDEN, -- The body of the log message
log_raw_text TEXT HIDDEN -- The raw text from the log file log_raw_text TEXT HIDDEN, -- The raw text from the log file
log_line_hash TEXT HIDDEN -- A hash of the first line of the log message
)"; )";
enum class log_footer_columns : uint32_t { enum class log_footer_columns : uint32_t {
@ -87,6 +88,7 @@ enum class log_footer_columns : uint32_t {
text, text,
body, body,
raw_text, raw_text,
line_hash,
}; };
static const char* static const char*
@ -914,6 +916,29 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
} }
break; break;
} }
case log_footer_columns::line_hash: {
auto read_res = lf->read_line(ll);
if (read_res.isErr()) {
auto msg = fmt::format(
FMT_STRING("unable to read line -- {}"),
read_res.unwrapErr());
sqlite3_result_error(
ctx, msg.c_str(), msg.length());
} else {
auto sbr = read_res.unwrap();
hasher line_hasher;
auto outbuf
= auto_buffer::alloc(hasher::STRING_SIZE);
line_hasher.update(sbr.get_data(), sbr.length())
.update(cl)
.to_string(outbuf);
auto tab = text_auto_buffer{std::move(outbuf)};
to_sqlite(ctx, tab);
}
break;
}
} }
} else { } else {
if (vc->line_values.empty()) { if (vc->line_values.empty()) {
@ -1508,6 +1533,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
case log_footer_columns::text: case log_footer_columns::text:
case log_footer_columns::body: case log_footer_columns::body:
case log_footer_columns::raw_text: case log_footer_columns::raw_text:
case log_footer_columns::line_hash:
break; break;
} }
} else { } else {
@ -1789,6 +1815,7 @@ vt_best_index(sqlite3_vtab* tab, sqlite3_index_info* p_info)
case log_footer_columns::text: case log_footer_columns::text:
case log_footer_columns::body: case log_footer_columns::body:
case log_footer_columns::raw_text: case log_footer_columns::raw_text:
case log_footer_columns::line_hash:
break; break;
} }
} else if (op == SQLITE_INDEX_CONSTRAINT_EQ) { } else if (op == SQLITE_INDEX_CONSTRAINT_EQ) {

233
src/session.export.cc Normal file
View File

@ -0,0 +1,233 @@
/**
* Copyright (c) 2022, 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.
*/
#include "session.export.hh"
#include "base/injector.hh"
#include "bound_tags.hh"
#include "lnav.hh"
#include "sqlitepp.client.hh"
#include "sqlitepp.hh"
#include "textview_curses.hh"
struct log_message_session_state {
int64_t lmss_time_msecs;
std::string lmss_format;
bool lmss_mark;
nonstd::optional<std::string> lmss_comment;
nonstd::optional<std::string> lmss_tags;
std::string lmss_hash;
};
template<>
struct from_sqlite<log_message_session_state> {
inline log_message_session_state operator()(int argc,
sqlite3_value** argv,
int argi)
{
return {
from_sqlite<int64_t>()(argc, argv, argi + 0),
from_sqlite<std::string>()(argc, argv, argi + 1),
from_sqlite<bool>()(argc, argv, argi + 2),
from_sqlite<nonstd::optional<std::string>>()(argc, argv, argi + 3),
from_sqlite<nonstd::optional<std::string>>()(argc, argv, argi + 4),
from_sqlite<std::string>()(argc, argv, argi + 5),
};
}
};
struct log_filter_session_state {
std::string lfss_name;
bool lfss_enabled;
std::string lfss_type;
std::string lfss_language;
std::string lfss_pattern;
};
template<>
struct from_sqlite<log_filter_session_state> {
inline log_filter_session_state operator()(int argc,
sqlite3_value** argv,
int argi)
{
return {
from_sqlite<std::string>()(argc, argv, argi + 0),
from_sqlite<bool>()(argc, argv, argi + 1),
from_sqlite<std::string>()(argc, argv, argi + 2),
from_sqlite<std::string>()(argc, argv, argi + 3),
from_sqlite<std::string>()(argc, argv, argi + 4),
};
}
};
namespace lnav {
namespace session {
Result<void, lnav::console::user_message>
export_to(FILE* file)
{
static auto& lnav_db
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
sqlite_db_tag>();
static const char* BOOKMARK_QUERY = R"(
SELECT log_time_msecs, log_format, log_mark, log_comment, log_tags, log_line_hash
FROM all_logs
WHERE log_mark = 1 OR log_comment IS NOT NULL OR log_tags IS NOT NULL
)";
static const char* FILTER_QUERY = R"(
SELECT view_name, enabled, type, language, pattern FROM lnav_view_filters
)";
console::user_message errmsg;
auto prep_res = prepare_stmt(lnav_db.in(), BOOKMARK_QUERY);
if (prep_res.isErr()) {
return Err(
console::user_message::error("unable to export log bookmarks")
.with_reason(prep_res.unwrapErr()));
}
auto bookmark_stmt = prep_res.unwrap();
auto done = false;
while (!done) {
done = bookmark_stmt.fetch_row<log_message_session_state>().match(
[file](const log_message_session_state& lmss) {
fmt::print(file,
FMT_STRING(";UPDATE all_logs "
"SET log_mark = {}, "
"log_comment = {}, "
"log_tags = {} "
"WHERE log_time_msecs = {} AND "
"log_format = {} AND "
"log_line_hash = {}\n"),
lmss.lmss_mark ? "1" : "0",
sqlitepp::quote(lmss.lmss_comment),
sqlitepp::quote(lmss.lmss_tags),
lmss.lmss_time_msecs,
sqlitepp::quote(lmss.lmss_format),
sqlitepp::quote(lmss.lmss_hash));
return false;
},
[](prepared_stmt::end_of_rows) { return true; },
[&errmsg](const prepared_stmt::fetch_error& fe) {
errmsg
= console::user_message::error(
"failed to fetch bookmark metadata for log message")
.with_reason(fe.fe_msg);
return true;
});
}
if (!errmsg.um_message.empty()) {
return Err(errmsg);
}
auto prep_filter_res = prepare_stmt(lnav_db.in(), FILTER_QUERY);
if (prep_filter_res.isErr()) {
return Err(console::user_message::error("unable to export filter state")
.with_reason(prep_filter_res.unwrapErr()));
}
auto filter_stmt = prep_filter_res.unwrap();
done = false;
while (!done) {
done = filter_stmt.fetch_row<log_filter_session_state>().match(
[file](const log_filter_session_state& lfss) {
fmt::print(
file,
FMT_STRING(";REPLACE INTO lnav_view_filters "
"(view_name, enabled, type, language, pattern) "
"VALUES ({}, {}, {}, {}, {})\n"),
sqlitepp::quote(lfss.lfss_name),
lfss.lfss_enabled ? 1 : 0,
sqlitepp::quote(lfss.lfss_type),
sqlitepp::quote(lfss.lfss_language),
sqlitepp::quote(lfss.lfss_pattern));
return false;
},
[](prepared_stmt::end_of_rows) { return true; },
[&errmsg](const prepared_stmt::fetch_error& fe) {
errmsg = console::user_message::error(
"failed to fetch filter state for views")
.with_reason(fe.fe_msg);
return true;
});
}
if (!errmsg.um_message.empty()) {
return Err(errmsg);
}
for (auto view_index : {LNV_LOG, LNV_TEXT}) {
auto& tc = lnav_data.ld_views[view_index];
if (tc.get_inner_height() == 0_vl) {
continue;
}
fmt::print(file,
FMT_STRING(":switch-to-view {}\n"),
lnav_view_strings[view_index]);
auto* tss = tc.get_sub_source();
auto* lss = dynamic_cast<logfile_sub_source*>(tss);
if (lss != nullptr) {
auto min_level = lss->get_min_log_level();
if (min_level != LEVEL_UNKNOWN) {
fmt::print(file,
FMT_STRING(":set-min-log-level {}"),
level_names[min_level]);
}
struct timeval min_time, max_time;
char tsbuf[128];
if (lss->get_min_log_time(min_time)) {
sql_strftime(tsbuf, sizeof(tsbuf), min_time, 'T');
fmt::print(file, FMT_STRING(":hide-lines-before {}"), tsbuf);
}
if (lss->get_max_log_time(max_time)) {
sql_strftime(tsbuf, sizeof(tsbuf), max_time, 'T');
fmt::print(file, FMT_STRING(":hide-lines-after {}"), tsbuf);
}
}
if (!tc.get_current_search().empty()) {
fmt::print(file, FMT_STRING("/{}\n"), tc.get_current_search());
}
fmt::print(file, FMT_STRING(":goto {}\n"), (int) tc.get_top());
}
return Ok();
}
} // namespace session
} // namespace lnav

43
src/session.export.hh Normal file
View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2022, 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 lnav_session_export_hh
#define lnav_session_export_hh
#include "base/lnav.console.hh"
namespace lnav {
namespace session {
Result<void, lnav::console::user_message> export_to(FILE* file);
}
} // namespace lnav
#endif

View File

@ -396,30 +396,29 @@ load_time_bookmarks()
} }
{ {
if (sqlite3_prepare_v2(db.in(), auto netloc_prep_res
"SELECT netloc FROM recent_netlocs", = prepare_stmt(db.in(), "SELECT netloc FROM recent_netlocs");
-1, if (netloc_prep_res.isErr()) {
stmt.out(), log_error("unable to get netlocs: %s",
nullptr) netloc_prep_res.unwrapErr().c_str());
!= SQLITE_OK)
{
return; return;
} }
auto netloc_stmt = netloc_prep_res.unwrap();
bool done = false; bool done = false;
while (!done) { while (!done) {
switch (sqlite3_step(stmt.in())) { done = netloc_stmt.fetch_row<std::string>().match(
case SQLITE_ROW: { [](const std::string& netloc) {
const auto* netloc = sqlite3_column_text(stmt.in(), 0); session_data.sd_recent_netlocs.insert(netloc);
return false;
session_data.sd_recent_netlocs.insert((const char*) netloc); },
break; [](const prepared_stmt::fetch_error& fe) {
} log_error("failed to fetch netloc row: %s",
default: fe.fe_msg.c_str());
done = true; return true;
break; },
} [](prepared_stmt::end_of_rows) { return true; });
} }
} }
@ -855,16 +854,18 @@ read_commands(yajlpp_parse_context* ypc, const unsigned char* str, size_t len)
return 1; return 1;
} }
static struct json_path_container view_def_handlers static struct json_path_container view_def_handlers = {
= {json_path_handler("top_line", read_top_line), json_path_handler("top_line", read_top_line),
json_path_handler("search", read_current_search), json_path_handler("search", read_current_search),
json_path_handler("word_wrap", read_word_wrap), json_path_handler("word_wrap", read_word_wrap),
json_path_handler("filtering", read_filtering), json_path_handler("filtering", read_filtering),
json_path_handler("commands#", read_commands)}; json_path_handler("commands#", read_commands),
};
static struct json_path_container view_handlers static struct json_path_container view_handlers = {
= {yajlpp::pattern_property_handler("([^/]+)").with_children( yajlpp::pattern_property_handler("([^/]+)").with_children(
view_def_handlers)}; view_def_handlers),
};
static struct json_path_container file_state_handlers = { static struct json_path_container file_state_handlers = {
yajlpp::property_handler("visible") yajlpp::property_handler("visible")
@ -1313,10 +1314,9 @@ save_time_bookmarks()
} }
for (auto& ls : lss) { for (auto& ls : lss) {
logfile::iterator line_iter; if (ls->get_file() == nullptr) {
if (ls->get_file() == nullptr)
continue; continue;
}
auto lf = ls->get_file(); auto lf = ls->get_file();
@ -1324,7 +1324,7 @@ save_time_bookmarks()
continue; continue;
} }
line_iter = lf->begin() + lf->get_time_offset_line(); auto line_iter = lf->begin() + lf->get_time_offset_line();
struct timeval offset = lf->get_time_offset(); struct timeval offset = lf->get_time_offset();
auto read_result = lf->read_line(line_iter); auto read_result = lf->read_line(line_iter);

View File

@ -300,19 +300,18 @@ void SpookyHash::Update(const void *message, size_t length)
m_state[11] = h11; m_state[11] = h11;
} }
// report the hash for the concatenation of all message fragments so far // report the hash for the concatenation of all message fragments so far
void SpookyHash::Final(uint64 *hash1, uint64 *hash2) void
SpookyHash::Final(uint64* hash1, uint64* hash2) const
{ {
// init the variables // init the variables
if (m_length < sc_bufSize) if (m_length < sc_bufSize) {
{
*hash1 = m_state[0]; *hash1 = m_state[0];
*hash2 = m_state[1]; *hash2 = m_state[1];
Short( m_data, m_length, hash1, hash2); Short(m_data, m_length, hash1, hash2);
return; return;
} }
const uint64 *data = (const uint64 *)m_data; const uint64 *data = (const uint64 *)m_data;
uint8 remainder = m_remainder; uint8 remainder = m_remainder;

View File

@ -98,7 +98,6 @@ public:
const void *message, // message fragment const void *message, // message fragment
size_t length); // length of message fragment in bytes size_t length); // length of message fragment in bytes
// //
// Final: compute the hash for the current SpookyHash state // Final: compute the hash for the current SpookyHash state
// //
@ -107,9 +106,8 @@ public:
// The result is the same as if SpookyHash() had been called with // The result is the same as if SpookyHash() had been called with
// all the pieces concatenated into one message. // all the pieces concatenated into one message.
// //
void Final( void Final(uint64* hash1, // out only: first 64 bits of hash value.
uint64 *hash1, // out only: first 64 bits of hash value. uint64* hash2) const; // out only: second 64 bits of hash value.
uint64 *hash2); // out only: second 64 bits of hash value.
// //
// left rotate a 64-bit value by k bytes // left rotate a 64-bit value by k bytes

View File

@ -32,7 +32,29 @@
#ifndef lnav_sqlitepp_hh #ifndef lnav_sqlitepp_hh
#define lnav_sqlitepp_hh #define lnav_sqlitepp_hh
#include <string>
#include "base/auto_mem.hh"
/* XXX figure out how to do this with the template */ /* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void* mem); void sqlite_close_wrapper(void* mem);
namespace sqlitepp {
inline auto_mem<char>
quote(const nonstd::optional<std::string>& str)
{
auto_mem<char> retval(sqlite3_free);
if (str) {
retval = sqlite3_mprintf("%Q", str.value().c_str());
} else {
retval = sqlite3_mprintf("NULL");
}
return retval;
}
} // namespace sqlitepp
#endif #endif

View File

@ -981,6 +981,12 @@ filter_stack::get_enabled_mask(uint32_t& filter_in_mask,
} }
} }
void
filter_stack::add_filter(const std::shared_ptr<text_filter>& filter)
{
this->fs_filters.push_back(filter);
}
void void
vis_location_history::loc_history_append(vis_line_t top) vis_location_history::loc_history_append(vis_line_t top)
{ {

View File

@ -98,7 +98,9 @@ public:
} type_t; } type_t;
text_filter(type_t type, filter_lang_t lang, std::string id, size_t index) text_filter(type_t type, filter_lang_t lang, std::string id, size_t index)
: lf_type(type), lf_lang(lang), lf_id(std::move(id)), lf_index(index){}; : lf_type(type), lf_lang(lang), lf_id(std::move(id)), lf_index(index)
{
}
virtual ~text_filter() = default; virtual ~text_filter() = default;
type_t get_type() const { return this->lf_type; } type_t get_type() const { return this->lf_type; }
@ -183,10 +185,7 @@ public:
nonstd::optional<size_t> next_index(); nonstd::optional<size_t> next_index();
void add_filter(const std::shared_ptr<text_filter>& filter) void add_filter(const std::shared_ptr<text_filter>& filter);
{
this->fs_filters.push_back(filter);
}
void clear_filters() void clear_filters()
{ {

View File

@ -635,9 +635,10 @@ CREATE TABLE lnav_view_filters (
nonstd::optional<filter_lang_t> lang, nonstd::optional<filter_lang_t> lang,
sqlite3_value* pattern_str) sqlite3_value* pattern_str)
{ {
textview_curses& tc = lnav_data.ld_views[view_index]; auto* mod_vt = (vtab_module<lnav_view_filters>::vtab*) tab;
text_sub_source* tss = tc.get_sub_source(); auto& tc = lnav_data.ld_views[view_index];
filter_stack& fs = tss->get_filters(); auto* tss = tc.get_sub_source();
auto& fs = tss->get_filters();
auto filter_index auto filter_index
= lang.value_or(filter_lang_t::REGEX) == filter_lang_t::REGEX = lang.value_or(filter_lang_t::REGEX) == filter_lang_t::REGEX
? fs.next_index() ? fs.next_index()
@ -645,6 +646,7 @@ CREATE TABLE lnav_view_filters (
if (!filter_index) { if (!filter_index) {
throw sqlite_func_error("Too many filters"); throw sqlite_func_error("Too many filters");
} }
auto conflict_mode = sqlite3_vtab_on_conflict(mod_vt->v_db);
std::shared_ptr<text_filter> tf; std::shared_ptr<text_filter> tf;
switch (lang.value_or(filter_lang_t::REGEX)) { switch (lang.value_or(filter_lang_t::REGEX)) {
case filter_lang_t::REGEX: { case filter_lang_t::REGEX: {
@ -656,6 +658,26 @@ CREATE TABLE lnav_view_filters (
pattern.first, pattern.first,
*filter_index, *filter_index,
pattern.second.release()); pattern.second.release());
auto new_cmd = pf->to_command();
for (auto& filter : fs) {
if (filter->to_command() == new_cmd) {
switch (conflict_mode) {
case SQLITE_FAIL:
case SQLITE_ABORT:
tab->zErrMsg = sqlite3_mprintf(
"filter already exists -- %s",
new_cmd.c_str());
return conflict_mode;
case SQLITE_IGNORE:
return SQLITE_OK;
case SQLITE_REPLACE:
filter->set_enabled(pf->is_enabled());
return SQLITE_OK;
default:
break;
}
}
}
fs.add_filter(pf); fs.add_filter(pf);
tf = pf; tf = pf;
break; break;
@ -665,6 +687,19 @@ CREATE TABLE lnav_view_filters (
throw sqlite_func_error( throw sqlite_func_error(
"SQL filters are only supported in the log view"); "SQL filters are only supported in the log view");
} }
if (lnav_data.ld_log_source.get_sql_filter_text() != "") {
switch (conflict_mode) {
case SQLITE_FAIL:
case SQLITE_ABORT:
tab->zErrMsg = sqlite3_mprintf(
"A SQL filter already exists");
return conflict_mode;
case SQLITE_IGNORE:
return SQLITE_OK;
default:
break;
}
}
auto clause = from_sqlite<std::string>()(1, &pattern_str, 0); auto clause = from_sqlite<std::string>()(1, &pattern_str, 0);
auto expr auto expr
= fmt::format(FMT_STRING("SELECT 1 WHERE {}"), clause); = fmt::format(FMT_STRING("SELECT 1 WHERE {}"), clause);

View File

@ -324,7 +324,7 @@ struct ToSqliteVisitor {
template<typename T> template<typename T>
void operator()(T&& t) const void operator()(T&& t) const
{ {
to_sqlite(this->tsv_context, t); to_sqlite(this->tsv_context, std::forward<T>(t));
} }
sqlite3_context* tsv_context; sqlite3_context* tsv_context;
@ -612,11 +612,12 @@ struct vtab_module_base {
template<typename T> template<typename T>
struct vtab_module : public vtab_module_base { struct vtab_module : public vtab_module_base {
struct vtab { struct vtab {
explicit vtab(T& impl) : v_impl(impl) {} explicit vtab(sqlite3* db, T& impl) : v_db(db), v_impl(impl) {}
explicit operator sqlite3_vtab*() { return &this->base; } explicit operator sqlite3_vtab*() { return &this->base; }
sqlite3_vtab v_base{}; sqlite3_vtab v_base{};
sqlite3* v_db;
T& v_impl; T& v_impl;
}; };
@ -628,7 +629,7 @@ struct vtab_module : public vtab_module_base {
char** pzErr) char** pzErr)
{ {
auto* mod = static_cast<vtab_module<T>*>(pAux); auto* mod = static_cast<vtab_module<T>*>(pAux);
auto vt = new vtab(mod->vm_impl); auto vt = new vtab(db, mod->vm_impl);
*pp_vt = (sqlite3_vtab*) &vt->v_base; *pp_vt = (sqlite3_vtab*) &vt->v_base;
@ -802,7 +803,9 @@ struct vtab_module : public vtab_module_base {
} }
template<typename U> template<typename U>
void addUpdate(...){}; void addUpdate(...)
{
}
template<typename... Args> template<typename... Args>
vtab_module(Args&... args) noexcept : vm_impl(args...) vtab_module(Args&... args) noexcept : vm_impl(args...)

View File

@ -340,6 +340,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sessions.sh_68a89b56c5e7f7db620084cca1eb547cbb19a2c9.out \ $(srcdir)/%reldir%/test_sessions.sh_68a89b56c5e7f7db620084cca1eb547cbb19a2c9.out \
$(srcdir)/%reldir%/test_sessions.sh_858fd0081ed9c46dd81e2f81f1090756f2463558.err \ $(srcdir)/%reldir%/test_sessions.sh_858fd0081ed9c46dd81e2f81f1090756f2463558.err \
$(srcdir)/%reldir%/test_sessions.sh_858fd0081ed9c46dd81e2f81f1090756f2463558.out \ $(srcdir)/%reldir%/test_sessions.sh_858fd0081ed9c46dd81e2f81f1090756f2463558.out \
$(srcdir)/%reldir%/test_sessions.sh_8732dad5481be991ca7f291d9c5451c7b016cea7.err \
$(srcdir)/%reldir%/test_sessions.sh_8732dad5481be991ca7f291d9c5451c7b016cea7.out \
$(srcdir)/%reldir%/test_sessions.sh_903b41c950f5f90d7786d7a09bb6e2f217654b15.err \ $(srcdir)/%reldir%/test_sessions.sh_903b41c950f5f90d7786d7a09bb6e2f217654b15.err \
$(srcdir)/%reldir%/test_sessions.sh_903b41c950f5f90d7786d7a09bb6e2f217654b15.out \ $(srcdir)/%reldir%/test_sessions.sh_903b41c950f5f90d7786d7a09bb6e2f217654b15.out \
$(srcdir)/%reldir%/test_sessions.sh_92a98a3e4e3a10bf1f2371d21a8282c5d3d4baa5.err \ $(srcdir)/%reldir%/test_sessions.sh_92a98a3e4e3a10bf1f2371d21a8282c5d3d4baa5.err \

View File

@ -709,9 +709,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
Parameter Parameter
msg The message to display msg The message to display
See Also See Also
:echo, :eval, :redirect-to, :write-csv-to, :write-json-to, :echo, :eval, :export-session-to, :redirect-to, :write-csv-to,
:write-jsonlines-to, :write-raw-to, :write-screen-to, :write-table-to, :write-json-to, :write-jsonlines-to, :write-raw-to, :write-screen-to,
:write-to, :write-view-to :write-table-to, :write-to, :write-view-to
Example Example
#1 To display 'Press t to switch to the text view' on the bottom right: #1 To display 'Press t to switch to the text view' on the bottom right:
:alt-msg Press t to switch to the text view  :alt-msg Press t to switch to the text view 
@ -724,9 +724,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
Parameter Parameter
path The path to the file to append to path The path to the file to append to
See Also See Also
:echo, :pipe-line-to, :pipe-to, :redirect-to, :write-csv-to, :echo, :export-session-to, :pipe-line-to, :pipe-to, :redirect-to,
:write-json-to, :write-jsonlines-to, :write-raw-to, :write-screen-to, :write-csv-to, :write-json-to, :write-jsonlines-to, :write-raw-to,
:write-table-to, :write-to, :write-view-to :write-screen-to, :write-table-to, :write-to, :write-view-to
Example Example
#1 To append marked lines to the file /tmp/interesting-lines.txt: #1 To append marked lines to the file /tmp/interesting-lines.txt:
:append-to /tmp/interesting-lines.txt  :append-to /tmp/interesting-lines.txt 
@ -938,12 +938,12 @@ lnav@googlegroups.com[1] support@lnav.org[2]
Parameter Parameter
msg The message to display msg The message to display
See Also See Also
:alt-msg, :append-to, :eval, :pipe-line-to, :pipe-to, :redirect-to, :alt-msg, :append-to, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-json-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-json-to, :write-jsonlines-to, :write-jsonlines-to, :write-csv-to, :write-json-to, :write-json-to, :write-jsonlines-to,
:write-raw-to, :write-raw-to, :write-screen-to, :write-screen-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-screen-to,
:write-table-to, :write-table-to, :write-to, :write-to, :write-view-to, :write-screen-to, :write-table-to, :write-table-to, :write-to,
:write-view-to :write-to, :write-view-to, :write-view-to
Example Example
#1 To output 'Hello, World!': #1 To output 'Hello, World!':
:echo Hello, World!  :echo Hello, World! 
@ -978,15 +978,28 @@ lnav@googlegroups.com[1] support@lnav.org[2]
Parameter Parameter
command The command or query to perform substitution on. command The command or query to perform substitution on.
See Also See Also
:alt-msg, :echo, :redirect-to, :write-csv-to, :write-json-to, :alt-msg, :echo, :export-session-to, :redirect-to, :write-csv-to,
:write-jsonlines-to, :write-raw-to, :write-screen-to, :write-table-to, :write-json-to, :write-jsonlines-to, :write-raw-to, :write-screen-to,
:write-to, :write-view-to :write-table-to, :write-to, :write-view-to
Example Example
#1 To substitute the table name from a variable: #1 To substitute the table name from a variable:
:eval ;SELECT * FROM ${table}  :eval ;SELECT * FROM ${table} 
:export-session-to path
══════════════════════════════════════════════════════════════════════
Export the current lnav state to an lnav script file
Parameter
path The path to the file to write
See Also
:alt-msg, :append-to, :echo, :echo, :eval, :pipe-line-to, :pipe-to,
:redirect-to, :redirect-to, :write-csv-to, :write-csv-to,
:write-json-to, :write-json-to, :write-jsonlines-to,
:write-jsonlines-to, :write-raw-to, :write-raw-to, :write-screen-to,
:write-screen-to, :write-table-to, :write-table-to, :write-to,
:write-to, :write-view-to, :write-view-to
:filter-expr expr :filter-expr expr
══════════════════════════════════════════════════════════════════════ ══════════════════════════════════════════════════════════════════════
Set the filter expression Set the filter expression
@ -1235,9 +1248,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
Parameter Parameter
shell-cmd The shell command-line to execute shell-cmd The shell command-line to execute
See Also See Also
:append-to, :echo, :pipe-to, :redirect-to, :write-csv-to, :append-to, :echo, :export-session-to, :pipe-to, :redirect-to,
:write-json-to, :write-jsonlines-to, :write-raw-to, :write-screen-to, :write-csv-to, :write-json-to, :write-jsonlines-to, :write-raw-to,
:write-table-to, :write-to, :write-view-to :write-screen-to, :write-table-to, :write-to, :write-view-to
Example Example
#1 To write the top line to 'sed' for processing: #1 To write the top line to 'sed' for processing:
:pipe-line-to sed -e 's/foo/bar/g'  :pipe-line-to sed -e 's/foo/bar/g' 
@ -1250,9 +1263,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
Parameter Parameter
shell-cmd The shell command-line to execute shell-cmd The shell command-line to execute
See Also See Also
:append-to, :echo, :pipe-line-to, :redirect-to, :write-csv-to, :append-to, :echo, :export-session-to, :pipe-line-to, :redirect-to,
:write-json-to, :write-jsonlines-to, :write-raw-to, :write-screen-to, :write-csv-to, :write-json-to, :write-jsonlines-to, :write-raw-to,
:write-table-to, :write-to, :write-view-to :write-screen-to, :write-table-to, :write-to, :write-view-to
Example Example
#1 To write marked lines to 'sed' for processing: #1 To write marked lines to 'sed' for processing:
:pipe-to sed -e s/foo/bar/g  :pipe-to sed -e s/foo/bar/g 
@ -1325,11 +1338,12 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write. If not specified, the path The path to the file to write. If not specified, the
current redirect will be cleared current redirect will be cleared
See Also See Also
:alt-msg, :append-to, :echo, :echo, :eval, :pipe-line-to, :pipe-to, :alt-msg, :append-to, :echo, :echo, :eval, :export-session-to,
:write-csv-to, :write-csv-to, :write-json-to, :write-json-to, :export-session-to, :pipe-line-to, :pipe-to, :write-csv-to,
:write-jsonlines-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-csv-to, :write-json-to, :write-json-to, :write-jsonlines-to,
:write-screen-to, :write-screen-to, :write-table-to, :write-table-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-screen-to,
:write-to, :write-to, :write-view-to, :write-view-to :write-screen-to, :write-table-to, :write-table-to, :write-to,
:write-to, :write-view-to, :write-view-to
Example Example
#1 To write the output of lnav commands to the file /tmp/script-output.txt: #1 To write the output of lnav commands to the file /tmp/script-output.txt:
:redirect-to /tmp/script-output.txt  :redirect-to /tmp/script-output.txt 
@ -1553,12 +1567,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-csv-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-json-to, :write-json-to, :write-json-to, :write-jsonlines-to, :write-csv-to, :write-csv-to, :write-json-to, :write-json-to,
:write-jsonlines-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-json-to, :write-jsonlines-to, :write-jsonlines-to,
:write-raw-to, :write-screen-to, :write-screen-to, :write-screen-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-raw-to,
:write-to, :write-to, :write-view-to, :write-view-to, :write-view-to :write-screen-to, :write-screen-to, :write-screen-to, :write-to,
:write-to, :write-view-to, :write-view-to, :write-view-to
Example Example
#1 To write SQL results as text to /tmp/table.txt: #1 To write SQL results as text to /tmp/table.txt:
:write-table-to /tmp/table.txt  :write-table-to /tmp/table.txt 
@ -1572,13 +1587,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-json-to, :write-json-to, :write-json-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-json-to,
:write-jsonlines-to, :write-jsonlines-to, :write-jsonlines-to, :write-json-to, :write-json-to, :write-jsonlines-to,
:write-raw-to, :write-raw-to, :write-raw-to, :write-screen-to, :write-jsonlines-to, :write-jsonlines-to, :write-raw-to, :write-raw-to,
:write-screen-to, :write-screen-to, :write-table-to, :write-table-to, :write-raw-to, :write-screen-to, :write-screen-to, :write-screen-to,
:write-table-to, :write-to, :write-to, :write-view-to, :write-view-to, :write-table-to, :write-table-to, :write-table-to, :write-to,
:write-view-to :write-to, :write-view-to, :write-view-to, :write-view-to
Example Example
#1 To write SQL results as CSV to /tmp/table.csv: #1 To write SQL results as CSV to /tmp/table.csv:
:write-csv-to /tmp/table.csv  :write-csv-to /tmp/table.csv 
@ -1592,13 +1607,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-csv-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-jsonlines-to, :write-jsonlines-to, :write-jsonlines-to, :write-csv-to, :write-csv-to, :write-jsonlines-to, :write-jsonlines-to,
:write-raw-to, :write-raw-to, :write-raw-to, :write-screen-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-raw-to,
:write-screen-to, :write-screen-to, :write-table-to, :write-table-to, :write-screen-to, :write-screen-to, :write-screen-to, :write-table-to,
:write-table-to, :write-to, :write-to, :write-view-to, :write-view-to, :write-table-to, :write-table-to, :write-to, :write-to, :write-view-to,
:write-view-to :write-view-to, :write-view-to
Example Example
#1 To write SQL results as JSON to /tmp/table.json: #1 To write SQL results as JSON to /tmp/table.json:
:write-json-to /tmp/table.json  :write-json-to /tmp/table.json 
@ -1612,12 +1627,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-csv-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-json-to, :write-json-to, :write-json-to, :write-raw-to, :write-csv-to, :write-csv-to, :write-json-to, :write-json-to,
:write-raw-to, :write-raw-to, :write-screen-to, :write-screen-to, :write-json-to, :write-raw-to, :write-raw-to, :write-raw-to,
:write-screen-to, :write-table-to, :write-table-to, :write-table-to, :write-screen-to, :write-screen-to, :write-screen-to, :write-table-to,
:write-to, :write-to, :write-view-to, :write-view-to, :write-view-to :write-table-to, :write-table-to, :write-to, :write-to, :write-view-to,
:write-view-to, :write-view-to
Example Example
#1 To write SQL results as JSON Lines to /tmp/table.json: #1 To write SQL results as JSON Lines to /tmp/table.json:
:write-jsonlines-to /tmp/table.json  :write-jsonlines-to /tmp/table.json 
@ -1635,13 +1651,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-csv-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-json-to, :write-json-to, :write-json-to, :write-jsonlines-to, :write-csv-to, :write-csv-to, :write-json-to, :write-json-to,
:write-jsonlines-to, :write-jsonlines-to, :write-screen-to, :write-json-to, :write-jsonlines-to, :write-jsonlines-to,
:write-screen-to, :write-screen-to, :write-table-to, :write-table-to, :write-jsonlines-to, :write-screen-to, :write-screen-to,
:write-table-to, :write-to, :write-to, :write-view-to, :write-view-to, :write-screen-to, :write-table-to, :write-table-to, :write-table-to,
:write-view-to :write-to, :write-to, :write-view-to, :write-view-to, :write-view-to
Example Example
#1 To write the marked lines in the log view to /tmp/table.txt: #1 To write the marked lines in the log view to /tmp/table.txt:
:write-raw-to /tmp/table.txt  :write-raw-to /tmp/table.txt 
@ -1656,12 +1672,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-csv-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-json-to, :write-json-to, :write-json-to, :write-jsonlines-to, :write-csv-to, :write-csv-to, :write-json-to, :write-json-to,
:write-jsonlines-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-json-to, :write-jsonlines-to, :write-jsonlines-to,
:write-raw-to, :write-table-to, :write-table-to, :write-table-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-raw-to,
:write-to, :write-to, :write-view-to, :write-view-to, :write-view-to :write-table-to, :write-table-to, :write-table-to, :write-to,
:write-to, :write-view-to, :write-view-to, :write-view-to
Example Example
#1 To write only the displayed text to /tmp/table.txt: #1 To write only the displayed text to /tmp/table.txt:
:write-screen-to /tmp/table.txt  :write-screen-to /tmp/table.txt 
@ -1675,12 +1692,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-csv-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-json-to, :write-json-to, :write-json-to, :write-jsonlines-to, :write-csv-to, :write-csv-to, :write-json-to, :write-json-to,
:write-jsonlines-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-json-to, :write-jsonlines-to, :write-jsonlines-to,
:write-raw-to, :write-screen-to, :write-screen-to, :write-screen-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-raw-to,
:write-to, :write-to, :write-view-to, :write-view-to, :write-view-to :write-screen-to, :write-screen-to, :write-screen-to, :write-to,
:write-to, :write-view-to, :write-view-to, :write-view-to
Example Example
#1 To write SQL results as text to /tmp/table.txt: #1 To write SQL results as text to /tmp/table.txt:
:write-table-to /tmp/table.txt  :write-table-to /tmp/table.txt 
@ -1693,12 +1711,12 @@ lnav@googlegroups.com[1] support@lnav.org[2]
Parameter Parameter
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :echo, :echo, :eval, :pipe-line-to, :pipe-to, :alt-msg, :append-to, :echo, :echo, :eval, :export-session-to,
:redirect-to, :redirect-to, :write-csv-to, :write-csv-to, :export-session-to, :pipe-line-to, :pipe-to, :redirect-to,
:write-json-to, :write-json-to, :write-jsonlines-to, :redirect-to, :write-csv-to, :write-csv-to, :write-json-to,
:write-jsonlines-to, :write-raw-to, :write-raw-to, :write-screen-to, :write-json-to, :write-jsonlines-to, :write-jsonlines-to,
:write-screen-to, :write-table-to, :write-table-to, :write-view-to, :write-raw-to, :write-raw-to, :write-screen-to, :write-screen-to,
:write-view-to :write-table-to, :write-table-to, :write-view-to, :write-view-to
Example Example
#1 To write marked lines to the file /tmp/interesting-lines.txt: #1 To write marked lines to the file /tmp/interesting-lines.txt:
:write-to /tmp/interesting-lines.txt  :write-to /tmp/interesting-lines.txt 
@ -1713,13 +1731,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
path The path to the file to write path The path to the file to write
See Also See Also
:alt-msg, :append-to, :create-logline-table, :create-search-table, :alt-msg, :append-to, :create-logline-table, :create-search-table,
:echo, :echo, :eval, :pipe-line-to, :pipe-to, :redirect-to, :echo, :echo, :eval, :export-session-to, :export-session-to,
:redirect-to, :write-csv-to, :write-csv-to, :write-csv-to, :pipe-line-to, :pipe-to, :redirect-to, :redirect-to, :write-csv-to,
:write-json-to, :write-json-to, :write-json-to, :write-jsonlines-to, :write-csv-to, :write-csv-to, :write-json-to, :write-json-to,
:write-jsonlines-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-json-to, :write-jsonlines-to, :write-jsonlines-to,
:write-raw-to, :write-screen-to, :write-screen-to, :write-screen-to, :write-jsonlines-to, :write-raw-to, :write-raw-to, :write-raw-to,
:write-table-to, :write-table-to, :write-table-to, :write-to, :write-screen-to, :write-screen-to, :write-screen-to, :write-table-to,
:write-to :write-table-to, :write-table-to, :write-to, :write-to
Example Example
#1 To write the top view to /tmp/table.txt: #1 To write the top view to /tmp/table.txt:
:write-view-to /tmp/table.txt  :write-view-to /tmp/table.txt 

View File

@ -0,0 +1,3 @@
;UPDATE all_logs SET log_mark = 1, log_comment = NULL, log_tags = NULL WHERE log_time_msecs = 1248130769000 AND log_format = 'access_log' AND log_line_hash = 'b05c1bdfe75cde41e151c89087e31951'
:switch-to-view log
:goto 1

View File

@ -81,6 +81,10 @@ TEST_CASE("byte_array")
ba1.clear(); ba1.clear();
CHECK(ba1.to_string() == "0000000000000000"); CHECK(ba1.to_string() == "0000000000000000");
CHECK(ba2.to_string() == "6162636431323334"); CHECK(ba2.to_string() == "6162636431323334");
auto outbuf = auto_buffer::alloc(my_array_t::STRING_SIZE);
ba2.to_string(std::back_inserter(outbuf));
CHECK(std::string(outbuf.in(), outbuf.size()) == "6162636431323334");
} }
TEST_CASE("ptime_fmt") TEST_CASE("ptime_fmt")

View File

@ -26,6 +26,12 @@ run_cap_test ${lnav_test} -nq \
-c ":save-session" \ -c ":save-session" \
${test_dir}/logfile_access_log.0 ${test_dir}/logfile_access_log.0
run_cap_test ${lnav_test} -nq \
-c ";update access_log set log_mark = 1 where sc_bytes > 60000" \
-c ":goto 1" \
-c ":export-session-to -" \
${test_dir}/logfile_access_log.0
# log mark was not saved in session # log mark was not saved in session
run_cap_test ${lnav_test} -n \ run_cap_test ${lnav_test} -n \
-c ":load-session" \ -c ":load-session" \