mirror of https://github.com/tstack/lnav.git
[ui] add back top status bar
This commit is contained in:
parent
d1521496cc
commit
f5cc4b298f
9
NEWS
9
NEWS
|
@ -1,7 +1,12 @@
|
|||
lnav v0.10.2:
|
||||
Features:
|
||||
* Redesigned the top status bar to make it display breadcrumbs that
|
||||
are interactive. Pressing ENTER will activate the breadcrumb bar
|
||||
* Redesigned the top status area to allow for user-specified
|
||||
messages and added a second line that displays an interactive
|
||||
breadcrumb bar. The top status line now shows the clock and
|
||||
the remaining area displays whatever messages are inserted
|
||||
into the lnav_user_notifications table. The information that
|
||||
was originally on top is now in a second line and organized
|
||||
as breadcrumbs. Pressing ENTER will activate the breadcrumb bar
|
||||
and the left/right cursor keys can be used to select a particular
|
||||
crumb while the up/down keys can select a value to switch to.
|
||||
While a crumb is selected, you can also type in some text to do
|
||||
|
|
|
@ -560,6 +560,11 @@
|
|||
"title": "/ui/theme-defs/<theme_name>/status-styles/subtitle",
|
||||
"$ref": "#/definitions/style"
|
||||
},
|
||||
"info": {
|
||||
"description": "Styling for informational messages in status bars",
|
||||
"title": "/ui/theme-defs/<theme_name>/status-styles/info",
|
||||
"$ref": "#/definitions/style"
|
||||
},
|
||||
"hotkey": {
|
||||
"description": "Styling for hotkey highlights of status bars",
|
||||
"title": "/ui/theme-defs/<theme_name>/status-styles/hotkey",
|
||||
|
|
|
@ -64,6 +64,7 @@ enum class role_t : int32_t {
|
|||
VCR_ACTIVE_STATUS2, /*< */
|
||||
VCR_STATUS_TITLE,
|
||||
VCR_STATUS_SUBTITLE,
|
||||
VCR_STATUS_INFO,
|
||||
VCR_STATUS_STITCH_TITLE_TO_SUB,
|
||||
VCR_STATUS_STITCH_SUB_TO_TITLE,
|
||||
VCR_STATUS_STITCH_SUB_TO_NORMAL,
|
||||
|
|
|
@ -83,6 +83,8 @@ sql_progress(const struct log_cursor& lc)
|
|||
|
||||
if (ui_periodic_timer::singleton().time_to_update(sql_counter)) {
|
||||
lnav_data.ld_bottom_source.update_loading(off, total);
|
||||
lnav_data.ld_top_source.update_time();
|
||||
lnav_data.ld_status[LNS_TOP].do_update();
|
||||
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
||||
refresh();
|
||||
}
|
||||
|
@ -98,6 +100,8 @@ sql_progress_finished()
|
|||
}
|
||||
|
||||
lnav_data.ld_bottom_source.update_loading(0, 0);
|
||||
lnav_data.ld_top_source.update_time();
|
||||
lnav_data.ld_status[LNS_TOP].do_update();
|
||||
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
||||
lnav_data.ld_views[LNV_DB].redo_search();
|
||||
}
|
||||
|
|
68
src/help.md
68
src/help.md
|
@ -15,12 +15,12 @@ efficiently zero in on problems.
|
|||
|
||||
## Opening Paths/URLs
|
||||
|
||||
The main arguments to lnav are the files, directories, glob patterns,
|
||||
or URLs to be viewed. If no arguments are given, the default syslog
|
||||
file for your system will be opened. These arguments will be polled
|
||||
periodically so that any new data or files will be automatically
|
||||
loaded. If a previously loaded file is removed or replaced, it will
|
||||
be closed and the replacement opened.
|
||||
The main arguments to lnav are the local/remote files, directories,
|
||||
glob patterns, or URLs to be viewed. If no arguments are given, the
|
||||
default syslog file for your system will be opened. These arguments
|
||||
will be polled periodically so that any new data or files will be
|
||||
automatically loaded. If a previously loaded file is removed or
|
||||
replaced, it will be closed and the replacement opened.
|
||||
|
||||
Note: When opening SFTP URLs, if the password is not provided for the
|
||||
host, the SSH agent can be used to do authentication.
|
||||
|
@ -118,32 +118,59 @@ display has a proportionally sized 'scroll bar' that indicates your
|
|||
current position in the files. The scroll bar will also show areas of
|
||||
the file where warnings or errors are detected by coloring the bar
|
||||
yellow or red, respectively. Tick marks will also be added to the
|
||||
left and right hand side of the bar, for search hits and bookmarks.
|
||||
left and right-hand side of the bar, for search hits and bookmarks.
|
||||
|
||||
A bar on the left side is color coded and broken up to indicate which
|
||||
messages are from the same file. Pressing the left-arrow or `h` will
|
||||
reveal the source file names for each message and pressing again will
|
||||
show the full paths.
|
||||
The bar on the left side indicates the file the log message is from. A
|
||||
break in the bar means that the next log message comes from a different
|
||||
file. The color of the bar is derived from the file name. Pressing the
|
||||
left-arrow or `h` will reveal the source file names for each message and
|
||||
pressing again will show the full paths.
|
||||
|
||||
Above and below the main body are status lines that display:
|
||||
Above and below the main body are status lines that display a variety
|
||||
of information. The top line displays:
|
||||
|
||||
* the current time;
|
||||
* the name of the file the top line was pulled from;
|
||||
* the log format for the top line;
|
||||
* the current view;
|
||||
* the line number for the top line in the display;
|
||||
* the current search hit, the total number of hits, and the search term;
|
||||
* The current time, configurable by the `/ui/clock-format` property.
|
||||
* The highest priority message from the `lnav_user_notifications` table.
|
||||
You can insert rows into this table to display your own status messages.
|
||||
The default message displayed on startup explains how to focus on the
|
||||
next status line at the top, which is an interactive breadcrumb bar.
|
||||
|
||||
The second status line at the top display breadcrumbs for the top line
|
||||
in the main view. Pressing `ENTER` will focus input on the breadcrumb
|
||||
bar, the cursor keys can be used to select a breadcrumb. The common
|
||||
breadcrumbs are:
|
||||
|
||||
* The name of the current view.
|
||||
* In the log view, the timestamp of the top log message.
|
||||
* In the log view, the format of the log file the top log message is from.
|
||||
* The name of the file the top line was pulled from.
|
||||
* If the top line is within a larger chunk of structured data, the path to
|
||||
the value in the top line will be shown.
|
||||
|
||||
Notes:
|
||||
|
||||
1. Pressing `CTRL-A`/`CTRL-E` will select the first/last breadcrumb.
|
||||
1. Typing text while a breadcrumb is selected will perform a fuzzy
|
||||
search on the possibilities.
|
||||
|
||||
The bottom status bar displays:
|
||||
|
||||
* The line number for the top line in the display.
|
||||
* The current search hit, the total number of hits, and the search term.
|
||||
|
||||
If the view supports filtering, there will be a status line showing the
|
||||
following:
|
||||
|
||||
* the number of enabled filters and the total number of filters;
|
||||
* the number of lines not displayed because of filtering.
|
||||
* The number of enabled filters and the total number of filters.
|
||||
* The number of lines not displayed because of filtering.
|
||||
|
||||
To edit the filters, you can press TAB to change the focus from the main
|
||||
view to the filter editor. The editor allows you to create, enable/disable,
|
||||
and delete filters easily.
|
||||
|
||||
Along with filters, a "Files" panel will also be available for viewing
|
||||
and controlling the files that lnav is currently monitoring.
|
||||
|
||||
Finally, the last line on the display is where you can enter search
|
||||
patterns and execute internal commands, such as converting a
|
||||
unix-timestamp into a human-readable date. The command-line is
|
||||
|
@ -169,6 +196,7 @@ that you can always use `q` to pop the top view off of the stack.
|
|||
| **q** | Leave the current view or quit the program when in the log file view. |
|
||||
| Q | Similar to `q`, except it will try to sync the top time between the current and former views. For example, when leaving the spectrogram view with `Q`, the top time in that view will be matched to the top time in the log view. |
|
||||
| TAB | Toggle focusing on the filter editor or the main view. |
|
||||
| ENTER | Focus on the breadcrumb bar. |
|
||||
| a/A | Restore the view that was previously popped with `q`/`Q`. The `A` hotkey will try to match the top times between the two views. |
|
||||
| X | Close the current text file or log file. |
|
||||
|
||||
|
|
80
src/init.sql
80
src/init.sql
|
@ -1,8 +1,9 @@
|
|||
CREATE TABLE IF NOT EXISTS http_status_codes (
|
||||
status integer PRIMARY KEY,
|
||||
message text,
|
||||
CREATE TABLE IF NOT EXISTS http_status_codes
|
||||
(
|
||||
status INTEGER PRIMARY KEY,
|
||||
message TEXT,
|
||||
|
||||
FOREIGN KEY(status) REFERENCES access_log(sc_status)
|
||||
FOREIGN KEY (status) REFERENCES access_log (sc_status)
|
||||
);
|
||||
|
||||
INSERT INTO http_status_codes VALUES (100, 'Continue');
|
||||
|
@ -65,33 +66,56 @@ INSERT INTO http_status_codes VALUES (508, 'Loop Detected');
|
|||
INSERT INTO http_status_codes VALUES (510, 'Not Extended');
|
||||
INSERT INTO http_status_codes VALUES (511, 'Network Authentication Required');
|
||||
|
||||
CREATE TABLE lnav_example_log (
|
||||
log_line INTEGER PRIMARY KEY,
|
||||
log_part TEXT collate naturalnocase,
|
||||
log_time datetime,
|
||||
log_actual_time datetime hidden,
|
||||
log_idle_msecs int,
|
||||
log_level TEXT collate loglevel,
|
||||
log_mark boolean,
|
||||
log_comment TEXT,
|
||||
log_tags TEXT,
|
||||
log_filters TEXT,
|
||||
CREATE TABLE lnav_example_log
|
||||
(
|
||||
log_line INTEGER PRIMARY KEY,
|
||||
log_part TEXT collate naturalnocase,
|
||||
log_time datetime,
|
||||
log_actual_time datetime hidden,
|
||||
log_idle_msecs int,
|
||||
log_level TEXT collate loglevel,
|
||||
log_mark boolean,
|
||||
log_comment TEXT,
|
||||
log_tags TEXT,
|
||||
log_filters TEXT,
|
||||
|
||||
ex_procname TEXT collate 'BINARY',
|
||||
ex_duration INTEGER,
|
||||
ex_procname TEXT collate 'BINARY',
|
||||
ex_duration INTEGER,
|
||||
|
||||
log_time_msecs int hidden,
|
||||
log_path TEXT hidden collate naturalnocase,
|
||||
log_text TEXT hidden,
|
||||
log_body TEXT hidden
|
||||
log_time_msecs int hidden,
|
||||
log_path TEXT hidden collate naturalnocase,
|
||||
log_text TEXT hidden,
|
||||
log_body TEXT hidden
|
||||
);
|
||||
|
||||
CREATE VIEW lnav_top_view AS
|
||||
SELECT * FROM lnav_views WHERE name = (
|
||||
SELECT name FROM lnav_view_stack ORDER BY rowid DESC LIMIT 1);
|
||||
SELECT *
|
||||
FROM lnav_views
|
||||
WHERE name = (SELECT name FROM lnav_view_stack ORDER BY rowid DESC LIMIT 1);
|
||||
|
||||
INSERT INTO lnav_example_log VALUES
|
||||
(0, null, '2017-02-03T04:05:06.100', '2017-02-03T04:05:06.100', 0, 'info', 0, null, null, null, 'hw', 2, 1486094706000, '/tmp/log', '2017-02-03T04:05:06.100 hw(2): Hello, World!', 'Hello, World!'),
|
||||
(1, null, '2017-02-03T04:05:06.200', '2017-02-03T04:05:06.200', 100, 'error', 0, null, null, null, 'gw', 4, 1486094706000, '/tmp/log', '2017-02-03T04:05:06.200 gw(4): Goodbye, World!', 'Goodbye, World!'),
|
||||
(2, 'new', '2017-02-03T04:25:06.200', '2017-02-03T04:25:06.200', 1200000, 'warn', 0, null, null, null, 'gw', 1, 1486095906000, '/tmp/log', '2017-02-03T04:25:06.200 gw(1): Goodbye, World!', 'Goodbye, World!'),
|
||||
(3, 'new', '2017-02-03T04:55:06.200', '2017-02-03T04:55:06.200', 1800000, 'debug', 0, null, null, null, 'gw', 10, 1486097706000, '/tmp/log', '2017-02-03T04:55:06.200 gw(10): Goodbye, World!', 'Goodbye, World!');
|
||||
INSERT INTO lnav_example_log
|
||||
VALUES (0, null, '2017-02-03T04:05:06.100', '2017-02-03T04:05:06.100', 0,
|
||||
'info', 0, null, null, null, 'hw', 2, 1486094706000, '/tmp/log',
|
||||
'2017-02-03T04:05:06.100 hw(2): Hello, World!', 'Hello, World!'),
|
||||
(1, null, '2017-02-03T04:05:06.200', '2017-02-03T04:05:06.200', 100,
|
||||
'error', 0, null, null, null, 'gw', 4, 1486094706000, '/tmp/log',
|
||||
'2017-02-03T04:05:06.200 gw(4): Goodbye, World!', 'Goodbye, World!'),
|
||||
(2, 'new', '2017-02-03T04:25:06.200', '2017-02-03T04:25:06.200', 1200000,
|
||||
'warn', 0, null, null, null, 'gw', 1, 1486095906000, '/tmp/log',
|
||||
'2017-02-03T04:25:06.200 gw(1): Goodbye, World!', 'Goodbye, World!'),
|
||||
(3, 'new', '2017-02-03T04:55:06.200', '2017-02-03T04:55:06.200', 1800000,
|
||||
'debug', 0, null, null, null, 'gw', 10, 1486097706000, '/tmp/log',
|
||||
'2017-02-03T04:55:06.200 gw(10): Goodbye, World!', 'Goodbye, World!');
|
||||
|
||||
CREATE TABLE lnav_user_notifications
|
||||
(
|
||||
id TEXT NOT NULL DEFAULT 'org.lnav.unknown',
|
||||
priority INTEGER NOT NULL DEFAULT 0,
|
||||
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expiration DATETIME DEFAULT NULL,
|
||||
message TEXT
|
||||
);
|
||||
|
||||
INSERT INTO lnav_user_notifications (id, priority, expiration, message)
|
||||
VALUES ('org.lnav.breadcrumb.help.focus', -1, datetime('now', '+1 minute'),
|
||||
'Press ENTER to focus on the breadcrumb bar');
|
||||
|
|
|
@ -583,8 +583,18 @@ void
|
|||
listview_curses::set_selection(vis_line_t sel)
|
||||
{
|
||||
if (this->lv_selectable) {
|
||||
if (this->lv_selection == sel) {
|
||||
return;
|
||||
}
|
||||
if (sel == -1_vl) {
|
||||
this->lv_selection = sel;
|
||||
this->lv_source->listview_selection_changed(*this);
|
||||
this->set_needs_update();
|
||||
return;
|
||||
}
|
||||
|
||||
auto inner_height = this->get_inner_height();
|
||||
if (this->lv_selection != sel && sel >= 0_vl && sel < inner_height) {
|
||||
if (sel >= 0_vl && sel < inner_height) {
|
||||
auto found = false;
|
||||
vis_line_t step;
|
||||
|
||||
|
|
16
src/lnav.cc
16
src/lnav.cc
|
@ -1170,7 +1170,7 @@ looper()
|
|||
|
||||
vsb.push_back(sb);
|
||||
|
||||
breadcrumb_view.set_y(0);
|
||||
breadcrumb_view.set_y(1);
|
||||
breadcrumb_view.set_window(lnav_data.ld_window);
|
||||
breadcrumb_view.set_line_source(lnav_crumb_source);
|
||||
auto event_handler = [](auto&& tc) {
|
||||
|
@ -1182,7 +1182,7 @@ looper()
|
|||
};
|
||||
for (lpc = 0; lpc < LNV__MAX; lpc++) {
|
||||
lnav_data.ld_views[lpc].set_window(lnav_data.ld_window);
|
||||
lnav_data.ld_views[lpc].set_y(1);
|
||||
lnav_data.ld_views[lpc].set_y(2);
|
||||
lnav_data.ld_views[lpc].set_height(
|
||||
vis_line_t(-(rlc->get_height() + 1)));
|
||||
lnav_data.ld_views[lpc].set_scroll_action(sb);
|
||||
|
@ -1232,6 +1232,8 @@ looper()
|
|||
lnav_data.ld_spectro_source->ss_exec_context
|
||||
= &lnav_data.ld_exec_context;
|
||||
|
||||
lnav_data.ld_status[LNS_TOP].set_top(0);
|
||||
lnav_data.ld_status[LNS_TOP].set_data_source(&lnav_data.ld_top_source);
|
||||
lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc->get_height() + 1));
|
||||
for (auto& sc : lnav_data.ld_status) {
|
||||
sc.set_window(lnav_data.ld_window);
|
||||
|
@ -1338,6 +1340,7 @@ looper()
|
|||
|
||||
gettimeofday(¤t_time, nullptr);
|
||||
|
||||
lnav_data.ld_top_source.update_time(current_time);
|
||||
lnav_data.ld_preview_view.set_needs_update();
|
||||
|
||||
layout_views();
|
||||
|
@ -1444,6 +1447,7 @@ looper()
|
|||
lnav_data.ld_spectro_details_view.do_update();
|
||||
lnav_data.ld_user_message_view.do_update();
|
||||
if (ui_clock::now() >= next_status_update_time) {
|
||||
lnav_data.ld_top_source.update_user_msg();
|
||||
for (auto& sc : lnav_data.ld_status) {
|
||||
sc.do_update();
|
||||
}
|
||||
|
@ -1594,14 +1598,14 @@ looper()
|
|||
next_rebuild_time = next_rescan_time;
|
||||
}
|
||||
|
||||
ps->check_poll_set(pollfds);
|
||||
lnav_data.ld_view_stack.top() |
|
||||
[](auto tc) { lnav_data.ld_bottom_source.update_hits(tc); };
|
||||
|
||||
auto old_mode = lnav_data.ld_mode;
|
||||
auto old_file_names_size
|
||||
= lnav_data.ld_active_files.fc_file_names.size();
|
||||
|
||||
ps->check_poll_set(pollfds);
|
||||
lnav_data.ld_view_stack.top() |
|
||||
[](auto tc) { lnav_data.ld_bottom_source.update_hits(tc); };
|
||||
|
||||
if (lnav_data.ld_mode != old_mode) {
|
||||
switch (lnav_data.ld_mode) {
|
||||
case ln_mode_t::PAGING:
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include "sql_util.hh"
|
||||
#include "statusview_curses.hh"
|
||||
#include "textfile_sub_source.hh"
|
||||
#include "top_status_source.hh"
|
||||
#include "view_helpers.hh"
|
||||
|
||||
class spectrogram_source;
|
||||
|
@ -92,6 +93,7 @@ extern const std::vector<std::string> lnav_zoom_strings;
|
|||
|
||||
/** The status bars. */
|
||||
typedef enum {
|
||||
LNS_TOP,
|
||||
LNS_BOTTOM,
|
||||
LNS_FILTER,
|
||||
LNS_FILTER_HELP,
|
||||
|
@ -195,6 +197,7 @@ struct lnav_data_t {
|
|||
ln_mode_t ld_last_config_mode{ln_mode_t::FILTER};
|
||||
|
||||
statusview_curses ld_status[LNS__MAX];
|
||||
top_status_source ld_top_source;
|
||||
bottom_status_source ld_bottom_source;
|
||||
filter_status_source ld_filter_status_source;
|
||||
filter_help_status_source ld_filter_help_status_source;
|
||||
|
|
|
@ -81,6 +81,7 @@ do_observer_update(const std::shared_ptr<logfile>& lf)
|
|||
if (isendwin()) {
|
||||
return;
|
||||
}
|
||||
lnav_data.ld_top_source.update_time();
|
||||
for (auto& sc : lnav_data.ld_status) {
|
||||
sc.do_update();
|
||||
}
|
||||
|
|
|
@ -768,6 +768,10 @@ static const struct json_path_container theme_status_styles_handlers = {
|
|||
.with_description("Styling for subtitle sections of status bars")
|
||||
.for_child(&lnav_theme::lt_style_status_subtitle)
|
||||
.with_children(style_config_handlers),
|
||||
yajlpp::property_handler("info")
|
||||
.with_description("Styling for informational messages in status bars")
|
||||
.for_child(&lnav_theme::lt_style_status_info)
|
||||
.with_children(style_config_handlers),
|
||||
yajlpp::property_handler("hotkey")
|
||||
.with_description("Styling for hotkey highlights of status bars")
|
||||
.for_child(&lnav_theme::lt_style_status_hotkey)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "https://lnav.org/schemas/config-v1.schema.json",
|
||||
"ui" : {
|
||||
"clock-format": "%a %b %d %H:%M:%S %Z",
|
||||
"clock-format": "%Y-%m-%dT%H:%M:%S %Z",
|
||||
"dim-text": false,
|
||||
"default-colors": true,
|
||||
"keymap": "default",
|
||||
|
|
|
@ -183,6 +183,7 @@ struct lnav_theme {
|
|||
style_config lt_style_status_title_hotkey;
|
||||
style_config lt_style_status_disabled_title;
|
||||
style_config lt_style_status_subtitle;
|
||||
style_config lt_style_status_info;
|
||||
style_config lt_style_status_hotkey;
|
||||
style_config lt_style_quoted_code;
|
||||
style_config lt_style_code_border;
|
||||
|
|
|
@ -204,6 +204,10 @@
|
|||
"background-color": "#66d9ee",
|
||||
"bold": true
|
||||
},
|
||||
"info": {
|
||||
"color": "#aaa",
|
||||
"background-color": "#353535"
|
||||
},
|
||||
"title-hotkey": {
|
||||
"color": "$black",
|
||||
"background-color": "#5394ec",
|
||||
|
|
|
@ -29,40 +29,28 @@
|
|||
|
||||
#include "top_status_source.hh"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "base/injector.hh"
|
||||
#include "bound_tags.hh"
|
||||
#include "config.h"
|
||||
#include "lnav_config.hh"
|
||||
#include "logfile_sub_source.hh"
|
||||
#include "sql_util.hh"
|
||||
|
||||
top_status_source::top_status_source()
|
||||
{
|
||||
this->tss_fields[TSF_TIME].set_width(28);
|
||||
this->tss_fields[TSF_PARTITION_NAME].set_width(34);
|
||||
this->tss_fields[TSF_PARTITION_NAME].set_left_pad(1);
|
||||
this->tss_fields[TSF_VIEW_NAME].set_width(8);
|
||||
this->tss_fields[TSF_VIEW_NAME].set_role(role_t::VCR_STATUS_TITLE);
|
||||
this->tss_fields[TSF_VIEW_NAME].right_justify(true);
|
||||
this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_stitch_value(
|
||||
role_t::VCR_STATUS_STITCH_SUB_TO_TITLE,
|
||||
role_t::VCR_STATUS_STITCH_TITLE_TO_SUB);
|
||||
this->tss_fields[TSF_STITCH_VIEW_FORMAT].right_justify(true);
|
||||
this->tss_fields[TSF_FORMAT].set_width(20);
|
||||
this->tss_fields[TSF_FORMAT].set_role(role_t::VCR_STATUS_SUBTITLE);
|
||||
this->tss_fields[TSF_FORMAT].right_justify(true);
|
||||
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_stitch_value(
|
||||
role_t::VCR_STATUS_STITCH_NORMAL_TO_SUB,
|
||||
role_t::VCR_STATUS_STITCH_SUB_TO_NORMAL);
|
||||
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].right_justify(true);
|
||||
this->tss_fields[TSF_FILENAME].set_min_width(35); /* XXX */
|
||||
this->tss_fields[TSF_FILENAME].set_share(1);
|
||||
this->tss_fields[TSF_FILENAME].right_justify(true);
|
||||
this->tss_fields[TSF_TIME].set_role(role_t::VCR_STATUS_INFO);
|
||||
this->tss_fields[TSF_USER_MSG].set_share(1);
|
||||
this->tss_fields[TSF_USER_MSG].right_justify(true);
|
||||
this->tss_fields[TSF_USER_MSG].set_role(role_t::VCR_STATUS_INFO);
|
||||
}
|
||||
|
||||
void
|
||||
top_status_source::update_time(const timeval& current_time)
|
||||
{
|
||||
status_field& sf = this->tss_fields[TSF_TIME];
|
||||
auto& sf = this->tss_fields[TSF_TIME];
|
||||
char buffer[32];
|
||||
|
||||
buffer[0] = ' ';
|
||||
|
@ -82,64 +70,76 @@ top_status_source::update_time()
|
|||
this->update_time(tv);
|
||||
}
|
||||
|
||||
struct user_msg_stmt {
|
||||
user_msg_stmt()
|
||||
{
|
||||
static const char* MSG_QUERY = R"(
|
||||
SELECT message FROM lnav_user_notifications
|
||||
WHERE expiration IS NULL OR expiration > datetime('now')
|
||||
ORDER BY priority DESC
|
||||
LIMIT 1
|
||||
)";
|
||||
|
||||
auto& lnav_db = injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
|
||||
auto retcode = sqlite3_prepare_v2(
|
||||
lnav_db, MSG_QUERY, -1, this->ums_stmt.out(), nullptr);
|
||||
|
||||
ensure(retcode == SQLITE_OK);
|
||||
}
|
||||
|
||||
auto_mem<sqlite3_stmt> ums_stmt{sqlite3_finalize};
|
||||
};
|
||||
|
||||
void
|
||||
top_status_source::update_filename(listview_curses* lc)
|
||||
top_status_source::update_user_msg()
|
||||
{
|
||||
auto& sf_partition = this->tss_fields[TSF_PARTITION_NAME];
|
||||
auto& sf_format = this->tss_fields[TSF_FORMAT];
|
||||
auto& sf_filename = this->tss_fields[TSF_FILENAME];
|
||||
static user_msg_stmt um_stmt;
|
||||
static auto& lnav_db
|
||||
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
|
||||
sqlite_db_tag>();
|
||||
|
||||
if (lc->get_inner_height() > 0) {
|
||||
std::vector<attr_line_t> rows(1);
|
||||
auto& al = this->tss_fields[TSF_USER_MSG].get_value();
|
||||
al.clear();
|
||||
|
||||
lc->get_data_source()->listview_value_for_rows(
|
||||
*lc, lc->get_top(), rows);
|
||||
auto& sa = rows[0].get_attrs();
|
||||
auto file_attr_opt = get_string_attr(sa, logline::L_FILE);
|
||||
if (file_attr_opt) {
|
||||
auto lf = file_attr_opt.value().get();
|
||||
auto* stmt = um_stmt.ums_stmt.in();
|
||||
sqlite3_reset(stmt);
|
||||
|
||||
if (lf->get_format()) {
|
||||
sf_format.set_value("% 13s",
|
||||
lf->get_format()->get_name().get());
|
||||
} else if (!lf->get_filename().empty()) {
|
||||
sf_format.set_value("% 13s", "plain text");
|
||||
} else {
|
||||
sf_format.clear();
|
||||
auto count = sqlite3_bind_parameter_count(stmt);
|
||||
for (int lpc = 0; lpc < count; lpc++) {
|
||||
const auto* name = sqlite3_bind_parameter_name(stmt, lpc + 1);
|
||||
|
||||
if (name[0] == '$') {
|
||||
const char* env_value;
|
||||
|
||||
if ((env_value = getenv(&name[1])) != nullptr) {
|
||||
sqlite3_bind_text(stmt, lpc + 1, env_value, -1, SQLITE_STATIC);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sf_filename.get_width() > (ssize_t) lf->get_filename().length())
|
||||
{
|
||||
sf_filename.set_value(lf->get_filename());
|
||||
} else {
|
||||
sf_filename.set_value(lf->get_unique_path());
|
||||
auto step_res = sqlite3_step(stmt);
|
||||
|
||||
switch (step_res) {
|
||||
case SQLITE_OK:
|
||||
case SQLITE_DONE:
|
||||
break;
|
||||
case SQLITE_ROW: {
|
||||
int ncols = sqlite3_column_count(stmt);
|
||||
for (int lpc = 0; lpc < ncols; lpc++) {
|
||||
const auto* text = (const char*) sqlite3_column_text(stmt, lpc);
|
||||
|
||||
al.with_ansi_string(text);
|
||||
al.append(" ");
|
||||
}
|
||||
} else {
|
||||
sf_format.clear();
|
||||
sf_filename.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
auto part_attr_opt = get_string_attr(sa, logline::L_PARTITION);
|
||||
if (part_attr_opt) {
|
||||
auto bm = part_attr_opt.value().get();
|
||||
|
||||
sf_partition.set_value(bm->bm_name.c_str());
|
||||
} else {
|
||||
sf_partition.clear();
|
||||
}
|
||||
} else {
|
||||
sf_format.clear();
|
||||
if (lc->get_data_source() != nullptr) {
|
||||
sf_filename.set_value(
|
||||
lc->get_data_source()->listview_source_name(*lc));
|
||||
default: {
|
||||
log_error("failed to execute user-message expression: %s",
|
||||
sqlite3_errmsg(lnav_db));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
top_status_source::update_view_name(listview_curses* lc)
|
||||
{
|
||||
status_field& sf_view_name = this->tss_fields[TSF_VIEW_NAME];
|
||||
|
||||
sf_view_name.set_value("%s ", lc->get_title().c_str());
|
||||
}
|
||||
|
|
|
@ -39,12 +39,7 @@ class top_status_source : public status_data_source {
|
|||
public:
|
||||
typedef enum {
|
||||
TSF_TIME,
|
||||
TSF_PARTITION_NAME,
|
||||
TSF_VIEW_NAME,
|
||||
TSF_STITCH_VIEW_FORMAT,
|
||||
TSF_FORMAT,
|
||||
TSF_STITCH_FORMAT_FILENAME,
|
||||
TSF_FILENAME,
|
||||
TSF_USER_MSG,
|
||||
|
||||
TSF__MAX
|
||||
} field_t;
|
||||
|
@ -62,9 +57,7 @@ public:
|
|||
|
||||
void update_time();
|
||||
|
||||
void update_filename(listview_curses* lc);
|
||||
|
||||
void update_view_name(listview_curses* lc);
|
||||
void update_user_msg();
|
||||
|
||||
private:
|
||||
status_field tss_fields[TSF__MAX];
|
||||
|
|
|
@ -879,6 +879,12 @@ view_colors::init_roles(const lnav_theme& lt,
|
|||
lt.lt_style_status_subtitle,
|
||||
lt.lt_style_status,
|
||||
reporter);
|
||||
this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS_INFO)]
|
||||
= this->to_attrs(color_pair_base,
|
||||
lt,
|
||||
lt.lt_style_status_info,
|
||||
lt.lt_style_status,
|
||||
reporter);
|
||||
|
||||
this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS_HOTKEY)]
|
||||
= this->to_attrs(color_pair_base,
|
||||
|
|
|
@ -1 +1 @@
|
|||
/ui/clock-format = "%a %b %d %H:%M:%S %Z"
|
||||
/ui/clock-format = "%Y-%m-%dT%H:%M:%S %Z"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
/ui/clock-format = "%a %b %d %H:%M:%S %Z"
|
||||
/ui/clock-format = "%Y-%m-%dT%H:%M:%S %Z"
|
||||
info: changed config option -- /ui/clock-format
|
||||
/ui/clock-format = "abc"
|
||||
|
|
|
@ -16,12 +16,12 @@ efficiently zero in on problems.
|
|||
|
||||
[1mOpening Paths/URLs[0m
|
||||
|
||||
The main arguments to lnav are the files, directories, glob patterns,
|
||||
or URLs to be viewed. If no arguments are given, the default syslog
|
||||
file for your system will be opened. These arguments will be polled
|
||||
periodically so that any new data or files will be automatically
|
||||
loaded. If a previously loaded file is removed or replaced, it will be
|
||||
closed and the replacement opened.
|
||||
The main arguments to lnav are the local/remote files, directories,
|
||||
glob patterns, or URLs to be viewed. If no arguments are given, the
|
||||
default syslog file for your system will be opened. These arguments
|
||||
will be polled periodically so that any new data or files will be
|
||||
automatically loaded. If a previously loaded file is removed or
|
||||
replaced, it will be closed and the replacement opened.
|
||||
|
||||
Note: When opening SFTP URLs, if the password is not provided for the
|
||||
host, the SSH agent can be used to do authentication.
|
||||
|
@ -121,34 +121,66 @@ display has a proportionally sized 'scroll bar' that indicates your
|
|||
current position in the files. The scroll bar will also show areas of
|
||||
the file where warnings or errors are detected by coloring the bar
|
||||
yellow or red, respectively. Tick marks will also be added to the left
|
||||
and right hand side of the bar, for search hits and bookmarks.
|
||||
and right-hand side of the bar, for search hits and bookmarks.
|
||||
|
||||
A bar on the left side is color coded and broken up to indicate which
|
||||
messages are from the same file. Pressing the left-arrow or [37m[40m h [0m will
|
||||
reveal the source file names for each message and pressing again will
|
||||
show the full paths.
|
||||
The bar on the left side indicates the file the log message is from. A
|
||||
break in the bar means that the next log message comes from a
|
||||
different file. The color of the bar is derived from the file name.
|
||||
Pressing the left-arrow or [37m[40m h [0m will reveal the source file names for
|
||||
each message and pressing again will show the full paths.
|
||||
|
||||
Above and below the main body are status lines that display:
|
||||
Above and below the main body are status lines that display a variety
|
||||
of information. The top line displays:
|
||||
|
||||
[33m•[0m the current time;
|
||||
[33m•[0m the name of the file the top line was pulled from;
|
||||
[33m•[0m the log format for the top line;
|
||||
[33m•[0m the current view;
|
||||
[33m•[0m the line number for the top line in the display;
|
||||
[33m•[0m the current search hit, the total number of hits, and
|
||||
the search term;
|
||||
[33m•[0m The current time, configurable by the [37m[40m /ui/clock-format [0m
|
||||
property.
|
||||
[33m•[0m The highest priority message from the [37m[40m lnav_user_notifications [0m
|
||||
table. You can insert rows into this table to display
|
||||
your own status messages. The default message displayed
|
||||
on startup explains how to focus on the next status line
|
||||
at the top, which is an interactive breadcrumb bar.
|
||||
|
||||
The second status line at the top display breadcrumbs for the top line
|
||||
in the main view. Pressing [37m[40m ENTER [0m will focus input on the breadcrumb
|
||||
bar, the cursor keys can be used to select a breadcrumb. The common
|
||||
breadcrumbs are:
|
||||
|
||||
[33m•[0m The name of the current view.
|
||||
[33m•[0m In the log view, the timestamp of the top log message.
|
||||
[33m•[0m In the log view, the format of the log file the top log
|
||||
message is from.
|
||||
[33m•[0m The name of the file the top line was pulled from.
|
||||
[33m•[0m If the top line is within a larger chunk of structured
|
||||
data, the path to the value in the top line will be
|
||||
shown.
|
||||
|
||||
Notes:
|
||||
|
||||
[33m1.[0m Pressing [37m[40m CTRL-A [0m/[37m[40m CTRL-E [0m will select the first/last
|
||||
breadcrumb.
|
||||
[33m2.[0m Typing text while a breadcrumb is selected will
|
||||
perform a fuzzy search on the possibilities.
|
||||
|
||||
The bottom status bar displays:
|
||||
|
||||
[33m•[0m The line number for the top line in the display.
|
||||
[33m•[0m The current search hit, the total number of hits, and
|
||||
the search term.
|
||||
|
||||
If the view supports filtering, there will be a status line showing
|
||||
the following:
|
||||
|
||||
[33m•[0m the number of enabled filters and the total number of
|
||||
filters;
|
||||
[33m•[0m the number of lines not displayed because of filtering.
|
||||
[33m•[0m The number of enabled filters and the total number of
|
||||
filters.
|
||||
[33m•[0m The number of lines not displayed because of filtering.
|
||||
|
||||
To edit the filters, you can press TAB to change the focus from the
|
||||
main view to the filter editor. The editor allows you to create,
|
||||
enable/disable, and delete filters easily.
|
||||
|
||||
Along with filters, a "Files" panel will also be available for viewing
|
||||
and controlling the files that lnav is currently monitoring.
|
||||
|
||||
Finally, the last line on the display is where you can enter search
|
||||
patterns and execute internal commands, such as converting a
|
||||
unix-timestamp into a human-readable date. The command-line is
|
||||
|
@ -180,6 +212,7 @@ can always use [37m[40m q [0m to pop the top view off of the stack.
|
|||
top time in the log view.
|
||||
TAB Toggle focusing on the filter editor or the main
|
||||
view.
|
||||
ENTER Focus on the breadcrumb bar.
|
||||
a/A Restore the view that was previously popped with [37m[40m q[0m
|
||||
/[37m[40m Q [0m. The [37m[40m A [0m hotkey will try to match the top
|
||||
times between the two views.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
info: changed config option -- /ui/clock-format
|
||||
info: reset option -- /ui/clock-format
|
||||
/ui/clock-format = "%a %b %d %H:%M:%S %Z"
|
||||
/ui/clock-format = "%Y-%m-%dT%H:%M:%S %Z"
|
||||
|
|
|
@ -1 +1 @@
|
|||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to readlink(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":44},{"start":17,"end":21,"type":"role","value":43},{"start":8,"end":22,"type":"role","value":57}]},"reason":{"str":"unable to stat path: non-existent-link -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to readlink(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":45},{"start":17,"end":21,"type":"role","value":44},{"start":8,"end":22,"type":"role","value":58}]},"reason":{"str":"unable to stat path: non-existent-link -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to realpath(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":44},{"start":17,"end":21,"type":"role","value":43},{"start":8,"end":22,"type":"role","value":57}]},"reason":{"str":"Could not get real path for non-existent-path -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to realpath(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":45},{"start":17,"end":21,"type":"role","value":44},{"start":8,"end":22,"type":"role","value":58}]},"reason":{"str":"Could not get real path for non-existent-path -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to json_contains(json, value) failed","attrs":[{"start":8,"end":21,"type":"role","value":44},{"start":22,"end":26,"type":"role","value":43},{"start":28,"end":33,"type":"role","value":43},{"start":8,"end":34,"type":"role","value":57}]},"reason":{"str":"parse error: premature EOF\n [\"hi\", \"bye\", \"solong]\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to json_contains(json, value) failed","attrs":[{"start":8,"end":21,"type":"role","value":45},{"start":22,"end":26,"type":"role","value":44},{"start":28,"end":33,"type":"role","value":44},{"start":8,"end":34,"type":"role","value":58}]},"reason":{"str":"parse error: premature EOF\n [\"hi\", \"bye\", \"solong]\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to regexp_match(re, str) failed","attrs":[{"start":8,"end":20,"type":"role","value":44},{"start":21,"end":23,"type":"role","value":43},{"start":25,"end":28,"type":"role","value":43},{"start":8,"end":29,"type":"role","value":57}]},"reason":{"str":"regular expression does not have any captures","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to regexp_match(re, str) failed","attrs":[{"start":8,"end":20,"type":"role","value":45},{"start":21,"end":23,"type":"role","value":44},{"start":25,"end":28,"type":"role","value":44},{"start":8,"end":29,"type":"role","value":58}]},"reason":{"str":"regular expression does not have any captures","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":44},{"start":18,"end":22,"type":"role","value":43},{"start":24,"end":29,"type":"role","value":43},{"start":8,"end":30,"type":"role","value":57}]},"reason":{"str":"unable to parse time slice value: blah -- Unrecognized input","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":45},{"start":18,"end":22,"type":"role","value":44},{"start":24,"end":29,"type":"role","value":44},{"start":8,"end":30,"type":"role","value":58}]},"reason":{"str":"unable to parse time slice value: blah -- Unrecognized input","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":44},{"start":18,"end":22,"type":"role","value":43},{"start":24,"end":29,"type":"role","value":43},{"start":8,"end":30,"type":"role","value":57}]},"reason":{"str":"no time slice value given","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":45},{"start":18,"end":22,"type":"role","value":44},{"start":24,"end":29,"type":"role","value":44},{"start":8,"end":30,"type":"role","value":58}]},"reason":{"str":"no time slice value given","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
|
||||
|
|
|
@ -888,7 +888,7 @@ CREATE TABLE lnav_events (
|
|||
ts TEXT NOT NULL DEFAULT(strftime('%Y-%m-%dT%H:%M:%f', 'now')),
|
||||
content TEXT
|
||||
);
|
||||
CREATE TABLE http_status_codes (
|
||||
CREATE TABLE http_status_codes
|
||||
EOF
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue