mirror of https://github.com/tstack/lnav.git
[cmds] add :export-session command
This commit is contained in:
parent
1abc77e129
commit
6712a33163
8
NEWS
8
NEWS
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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`
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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...)
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -709,9 +709,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mParameter[0m
|
[4mParameter[0m
|
||||||
[4mmsg[0m The message to display
|
[4mmsg[0m The message to display
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:echo[0m, [1m:eval[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m,
|
[1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
||||||
[1m:write-to[0m, [1m:write-view-to[0m
|
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#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:
|
||||||
[37m[40m:[0m[1m[36m[40malt-msg[0m[37m[40m Press t to switch to the text view [0m
|
[37m[40m:[0m[1m[36m[40malt-msg[0m[37m[40m Press t to switch to the text view [0m
|
||||||
|
@ -724,9 +724,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mParameter[0m
|
[4mParameter[0m
|
||||||
[4mpath[0m The path to the file to append to
|
[4mpath[0m The path to the file to append to
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:echo[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
[1m:echo[0m, [1m:export-session-to[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
[1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To append marked lines to the file /tmp/interesting-lines.txt:
|
#1 To append marked lines to the file /tmp/interesting-lines.txt:
|
||||||
[37m[40m:[0m[1m[36m[40mappend-to[0m[37m[40m /tmp/interesting-lines.txt [0m
|
[37m[40m:[0m[1m[36m[40mappend-to[0m[37m[40m /tmp/interesting-lines.txt [0m
|
||||||
|
@ -938,12 +938,12 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mParameter[0m
|
[4mParameter[0m
|
||||||
[4mmsg[0m The message to display
|
[4mmsg[0m The message to display
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m,
|
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m,
|
||||||
[1m:write-view-to[0m
|
[1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To output 'Hello, World!':
|
#1 To output 'Hello, World!':
|
||||||
[37m[40m:[0m[1m[36m[40mecho[0m[37m[40m Hello, World! [0m
|
[37m[40m:[0m[1m[36m[40mecho[0m[37m[40m Hello, World! [0m
|
||||||
|
@ -978,15 +978,28 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mParameter[0m
|
[4mParameter[0m
|
||||||
[4mcommand[0m The command or query to perform substitution on.
|
[4mcommand[0m The command or query to perform substitution on.
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:echo[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m,
|
[1m:alt-msg[0m, [1m:echo[0m, [1m:export-session-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
||||||
[1m:write-to[0m, [1m:write-view-to[0m
|
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To substitute the table name from a variable:
|
#1 To substitute the table name from a variable:
|
||||||
[37m[40m:[0m[1m[36m[40meval[0m[37m[40m ;SELECT * FROM [0m[1m[37m[40m${[0m[37m[40mtable[0m[1m[37m[40m}[0m[37m[40m [0m
|
[37m[40m:[0m[1m[36m[40meval[0m[37m[40m ;SELECT * FROM [0m[1m[37m[40m${[0m[37m[40mtable[0m[1m[37m[40m}[0m[37m[40m [0m
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[4m:[0m[1m[4mexport-session-to[0m[4m [0m[4mpath[0m
|
||||||
|
══════════════════════════════════════════════════════════════════════
|
||||||
|
Export the current lnav state to an lnav script file
|
||||||
|
[4mParameter[0m
|
||||||
|
[4mpath[0m The path to the file to write
|
||||||
|
[4mSee Also[0m
|
||||||
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m,
|
||||||
|
[1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
||||||
|
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
||||||
|
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m,
|
||||||
|
[1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
|
|
||||||
[4m:[0m[1m[4mfilter-expr[0m[4m [0m[4mexpr[0m
|
[4m:[0m[1m[4mfilter-expr[0m[4m [0m[4mexpr[0m
|
||||||
══════════════════════════════════════════════════════════════════════
|
══════════════════════════════════════════════════════════════════════
|
||||||
Set the filter expression
|
Set the filter expression
|
||||||
|
@ -1235,9 +1248,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mParameter[0m
|
[4mParameter[0m
|
||||||
[4mshell-cmd[0m The shell command-line to execute
|
[4mshell-cmd[0m The shell command-line to execute
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:append-to[0m, [1m:echo[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
[1m:append-to[0m, [1m:echo[0m, [1m:export-session-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
[1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write the top line to 'sed' for processing:
|
#1 To write the top line to 'sed' for processing:
|
||||||
[37m[40m:[0m[1m[36m[40mpipe-line-to[0m[37m[40m sed -e 's/foo/bar/g' [0m
|
[37m[40m:[0m[1m[36m[40mpipe-line-to[0m[37m[40m sed -e 's/foo/bar/g' [0m
|
||||||
|
@ -1250,9 +1263,9 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mParameter[0m
|
[4mParameter[0m
|
||||||
[4mshell-cmd[0m The shell command-line to execute
|
[4mshell-cmd[0m The shell command-line to execute
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:append-to[0m, [1m:echo[0m, [1m:pipe-line-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
[1m:append-to[0m, [1m:echo[0m, [1m:export-session-to[0m, [1m:pipe-line-to[0m, [1m:redirect-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
[1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write marked lines to 'sed' for processing:
|
#1 To write marked lines to 'sed' for processing:
|
||||||
[37m[40m:[0m[1m[36m[40mpipe-to[0m[37m[40m sed -e s/foo/bar/g [0m
|
[37m[40m:[0m[1m[36m[40mpipe-to[0m[37m[40m sed -e s/foo/bar/g [0m
|
||||||
|
@ -1325,11 +1338,12 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write. If not specified, the
|
[4mpath[0m The path to the file to write. If not specified, the
|
||||||
current redirect will be cleared
|
current redirect will be cleared
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m,
|
||||||
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
[1m:export-session-to[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
[1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
||||||
[1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m,
|
||||||
|
[1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#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:
|
||||||
[37m[40m:[0m[1m[36m[40mredirect-to[0m[37m[40m /tmp/script-output.txt [0m
|
[37m[40m:[0m[1m[36m[40mredirect-to[0m[37m[40m /tmp/script-output.txt [0m
|
||||||
|
@ -1553,12 +1567,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-to[0m,
|
||||||
|
[1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write SQL results as text to /tmp/table.txt:
|
#1 To write SQL results as text to /tmp/table.txt:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-table-to[0m[37m[40m /tmp/table.txt [0m
|
[37m[40m:[0m[1m[36m[40mwrite-table-to[0m[37m[40m /tmp/table.txt [0m
|
||||||
|
@ -1572,13 +1587,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m,
|
[1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m,
|
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m,
|
||||||
[1m:write-view-to[0m
|
[1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write SQL results as CSV to /tmp/table.csv:
|
#1 To write SQL results as CSV to /tmp/table.csv:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-csv-to[0m[37m[40m /tmp/table.csv [0m
|
[37m[40m:[0m[1m[36m[40mwrite-csv-to[0m[37m[40m /tmp/table.csv [0m
|
||||||
|
@ -1592,13 +1607,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m,
|
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m,
|
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m,
|
||||||
[1m:write-view-to[0m
|
[1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write SQL results as JSON to /tmp/table.json:
|
#1 To write SQL results as JSON to /tmp/table.json:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-json-to[0m[37m[40m /tmp/table.json [0m
|
[37m[40m:[0m[1m[36m[40mwrite-json-to[0m[37m[40m /tmp/table.json [0m
|
||||||
|
@ -1612,12 +1627,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-raw-to[0m,
|
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
[1m:write-json-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m,
|
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m,
|
||||||
[1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m,
|
||||||
|
[1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write SQL results as JSON Lines to /tmp/table.json:
|
#1 To write SQL results as JSON Lines to /tmp/table.json:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-jsonlines-to[0m[37m[40m /tmp/table.json [0m
|
[37m[40m:[0m[1m[36m[40mwrite-jsonlines-to[0m[37m[40m /tmp/table.json [0m
|
||||||
|
@ -1635,13 +1651,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-screen-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m,
|
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m,
|
||||||
[1m:write-view-to[0m
|
[1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#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:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-raw-to[0m[37m[40m /tmp/table.txt [0m
|
[37m[40m:[0m[1m[36m[40mwrite-raw-to[0m[37m[40m /tmp/table.txt [0m
|
||||||
|
@ -1656,12 +1672,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m,
|
||||||
|
[1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write only the displayed text to /tmp/table.txt:
|
#1 To write only the displayed text to /tmp/table.txt:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-screen-to[0m[37m[40m /tmp/table.txt [0m
|
[37m[40m:[0m[1m[36m[40mwrite-screen-to[0m[37m[40m /tmp/table.txt [0m
|
||||||
|
@ -1675,12 +1692,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-to[0m, [1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-to[0m,
|
||||||
|
[1m:write-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write SQL results as text to /tmp/table.txt:
|
#1 To write SQL results as text to /tmp/table.txt:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-table-to[0m[37m[40m /tmp/table.txt [0m
|
[37m[40m:[0m[1m[36m[40mwrite-table-to[0m[37m[40m /tmp/table.txt [0m
|
||||||
|
@ -1693,12 +1711,12 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mParameter[0m
|
[4mParameter[0m
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:export-session-to[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-screen-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-view-to[0m,
|
[1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
||||||
[1m:write-view-to[0m
|
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-view-to[0m, [1m:write-view-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write marked lines to the file /tmp/interesting-lines.txt:
|
#1 To write marked lines to the file /tmp/interesting-lines.txt:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-to[0m[37m[40m /tmp/interesting-lines.txt [0m
|
[37m[40m:[0m[1m[36m[40mwrite-to[0m[37m[40m /tmp/interesting-lines.txt [0m
|
||||||
|
@ -1713,13 +1731,13 @@ lnav@googlegroups.com[1] support@lnav.org[2]
|
||||||
[4mpath[0m The path to the file to write
|
[4mpath[0m The path to the file to write
|
||||||
[4mSee Also[0m
|
[4mSee Also[0m
|
||||||
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
[1m:alt-msg[0m, [1m:append-to[0m, [1m:create-logline-table[0m, [1m:create-search-table[0m,
|
||||||
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m,
|
[1m:echo[0m, [1m:echo[0m, [1m:eval[0m, [1m:export-session-to[0m, [1m:export-session-to[0m,
|
||||||
[1m:redirect-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-csv-to[0m,
|
[1m:pipe-line-to[0m, [1m:pipe-to[0m, [1m:redirect-to[0m, [1m:redirect-to[0m, [1m:write-csv-to[0m,
|
||||||
[1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m, [1m:write-jsonlines-to[0m,
|
[1m:write-csv-to[0m, [1m:write-csv-to[0m, [1m:write-json-to[0m, [1m:write-json-to[0m,
|
||||||
[1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
[1m:write-json-to[0m, [1m:write-jsonlines-to[0m, [1m:write-jsonlines-to[0m,
|
||||||
[1m:write-raw-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m,
|
[1m:write-jsonlines-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m, [1m:write-raw-to[0m,
|
||||||
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m,
|
[1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-screen-to[0m, [1m:write-table-to[0m,
|
||||||
[1m:write-to[0m
|
[1m:write-table-to[0m, [1m:write-table-to[0m, [1m:write-to[0m, [1m:write-to[0m
|
||||||
[4mExample[0m
|
[4mExample[0m
|
||||||
#1 To write the top view to /tmp/table.txt:
|
#1 To write the top view to /tmp/table.txt:
|
||||||
[37m[40m:[0m[1m[36m[40mwrite-view-to[0m[37m[40m /tmp/table.txt [0m
|
[37m[40m:[0m[1m[36m[40mwrite-view-to[0m[37m[40m /tmp/table.txt [0m
|
||||||
|
|
|
@ -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
|
|
@ -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")
|
||||||
|
|
|
@ -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" \
|
||||||
|
|
Loading…
Reference in New Issue