[partitions] revive partition functionality

pull/1242/head
Tim Stack 2 months ago
parent 5f28edd1c1
commit 554f0e2439

@ -1,5 +1,16 @@
## lnav v0.12.1 ## lnav v0.12.1
Features:
* Log partitions can automatically be created by defining a log
message pattern in a log format. Under a format definition,
add an entry into the "partitions" object in a format definition.
The "pattern" property specifies the regular expression to match
against a line in a file that matches the format. If a match is
found, the partition name will be set to the value(s) captured
by the regex. To restrict matches to certain files, you can add
a "paths" array whose object elements contain a "glob" property
that will be matched against file names.
Interface changes: Interface changes:
* Changed the breadcrumb bar styling to space things out * Changed the breadcrumb bar styling to space things out
more and make the divisions between items clearer. more and make the divisions between items clearer.
@ -14,6 +25,14 @@ Interface changes:
one is active). one is active).
* The focused line should be preserved more reliably in * The focused line should be preserved more reliably in
the LOG/TEXT views. the LOG/TEXT views.
* In the LOG view, the current partition name (as set
with the `:partition-name` command) is shown as the
first breadcrumb in the breadcrumb bar. And, when
that breadcrumb is selected, you can select another
partition to jump to.
* The `{` / `}` hotkeys, `:next-section`, and `:prev-section`
commands now work in the LOG view and take you to the
next/previous partition.
## lnav v0.12.0 ## lnav v0.12.0

@ -518,6 +518,74 @@
}, },
"additionalProperties": false "additionalProperties": false
}, },
"partitions": {
"description": "The partitions to automatically apply to log messages",
"title": "/<format_name>/partitions",
"type": "object",
"patternProperties": {
"([\\w:;\\._\\-]+)": {
"description": "The type of partition to apply",
"title": "/<format_name>/partitions/<partition_type>",
"type": "object",
"properties": {
"paths": {
"description": "Restrict partitioning to the given paths",
"title": "/<format_name>/partitions/<partition_type>/paths",
"type": "array",
"items": {
"type": "object",
"properties": {
"glob": {
"title": "/<format_name>/partitions/<partition_type>/paths/glob",
"description": "The glob to match against file paths",
"type": "string",
"examples": [
"*/system.log*"
]
}
},
"additionalProperties": false
}
},
"pattern": {
"title": "/<format_name>/partitions/<partition_type>/pattern",
"description": "The regular expression to match against the body of the log message",
"type": "string",
"examples": [
"\\w+ is down"
]
},
"description": {
"title": "/<format_name>/partitions/<partition_type>/description",
"description": "A description of this partition",
"type": "string"
},
"level": {
"title": "/<format_name>/partitions/<partition_type>/level",
"description": "Constrain hits to log messages with this level",
"type": "string",
"enum": [
"trace",
"debug5",
"debug4",
"debug3",
"debug2",
"debug",
"info",
"stats",
"notice",
"warning",
"error",
"critical",
"fatal"
]
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"action": { "action": {
"title": "/<format_name>/action", "title": "/<format_name>/action",
"type": "object", "type": "object",

@ -367,6 +367,19 @@ object with the following fields:
:glob: A glob pattern to check against the log files read by lnav. :glob: A glob pattern to check against the log files read by lnav.
:partitions: This object contains a description of partitions that should
automatically be created in the log view.
:pattern: The regular expression evaluated over a line in the log file as
it is read in. If there is a match, the log message the line is a part
of will be used as the start of the partition. The name of the
partition will be taken from any captures in the regex.
:paths: This array contains objects that define restrictions on the file
paths in which partitions will be created. The objects in this array
can contain:
:glob: A glob pattern to check against the log files read by lnav.
.. _format_sample: .. _format_sample:
:sample: A list of objects that contain sample log messages. All formats :sample: A list of objects that contain sample log messages. All formats

@ -265,10 +265,41 @@ columns will be included in the table.
Taking Notes Taking Notes
------------ ------------
A few of the columns in the log tables can be updated on a row-by-row basis to As you are looking through logs, you might find that you want to leave some
allow you to take notes. The majority of the columns in a log table are notes of your findings. **lnav** can help here by saving information in
read-only since they are backed by the log files themselves. However, the the session without needing to modify the actual log files. Thus, when
following columns can be changed by an :code:`UPDATE` statement: you re-open the files in lnav, the notes will be restored. The following
types of information can be saved:
:tags: Log messages can be tagged with the :ref:`:tag<tag>` command as a
simple way to leave a descriptive mark. The tags attached to a
message will be shown underneath the message. You can press
:kbd:`u` and :kbd:`Shift` + :kbd:`u` to jump to the next/previous
marked line. A regular search will also match tags.
:comments: Free-form text can be attached to a log message with the
:ref:`:comment<comment>` command. The comment will be shown
underneath the message. If the text contains markdown syntax,
it will be rendered to the best of the terminal's ability.
You can press :kbd:`u` and :kbd:`Shift` + :kbd:`u` to jump to the
next/previous marked line. A regular search will also match the
comment text.
:partitions: The log view can be partitioned to provide some context
about where you are in a collection of logs. For example, in logs
for a test run, partitions could be created with the name for each
test. The current partition is shown in the breadcrumb bar and
prefixed by the "⊑" symbol. You can select the partition breadcrumb
to jump to another partition. Pressing :kbd:`{` and :kbd:`}` will
jump to the next/previous partition.
Accessing notes through the SQLite interface
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The note taking functionality in lnav can also be accessed through the
log tables exposed through SQLite. The majority of the columns in a log
table are read-only since they are backed by the log files themselves.
However, the following columns can be changed by an :code:`UPDATE` statement:
* **log_part** - The "partition" the log message belongs to. This column can * **log_part** - The "partition" the log message belongs to. This column can
also be changed by the :ref:`:partition-name<partition_name>` command. also be changed by the :ref:`:partition-name<partition_name>` command.

@ -64,10 +64,19 @@ bookmark_metadata::remove_tag(const std::string& tag)
} }
bool bool
bookmark_metadata::empty() const bookmark_metadata::empty(bookmark_metadata::categories props) const
{ {
return this->bm_name.empty() && this->bm_comment.empty() switch (props) {
&& this->bm_tags.empty() && this->bm_annotations.la_pairs.empty(); case categories::any:
return this->bm_name.empty() && this->bm_comment.empty()
&& this->bm_tags.empty()
&& this->bm_annotations.la_pairs.empty();
case categories::partition:
return this->bm_name.empty();
case categories::notes:
return this->bm_comment.empty() && this->bm_tags.empty()
&& this->bm_annotations.la_pairs.empty();
}
} }
void void

@ -47,6 +47,33 @@ struct logmsg_annotations {
struct bookmark_metadata { struct bookmark_metadata {
static std::unordered_set<std::string> KNOWN_TAGS; static std::unordered_set<std::string> KNOWN_TAGS;
enum class categories : int {
any = 0,
partition = 0x01,
notes = 0x02,
};
bool has(categories props) const
{
if (props == categories::any) {
return true;
}
if (props == categories::partition && !this->bm_name.empty()) {
return true;
}
if (props == categories::notes
&& (!this->bm_comment.empty()
|| !this->bm_annotations.la_pairs.empty()
|| !this->bm_tags.empty()))
{
return true;
}
return false;
}
std::string bm_name; std::string bm_name;
std::string bm_comment; std::string bm_comment;
logmsg_annotations bm_annotations; logmsg_annotations bm_annotations;
@ -56,7 +83,7 @@ struct bookmark_metadata {
bool remove_tag(const std::string& tag); bool remove_tag(const std::string& tag);
bool empty() const; bool empty(categories props) const;
void clear(); void clear();
}; };

@ -67,8 +67,7 @@ breadcrumb_curses::do_update()
attr_line_t crumbs_line; attr_line_t crumbs_line;
for (const auto& crumb : crumbs) { for (const auto& crumb : crumbs) {
auto accum_width = crumbs_line.column_width(); auto accum_width = crumbs_line.column_width();
auto elem_width = utf8_string_length(crumb.c_display_value.get_string()) auto elem_width = crumb.c_display_value.column_width();
.template unwrap();
auto is_selected = this->bc_selected_crumb auto is_selected = this->bc_selected_crumb
&& (crumb_index == this->bc_selected_crumb.value()); && (crumb_index == this->bc_selected_crumb.value());

@ -1,6 +1,7 @@
{ {
"$schema": "https://lnav.org/schemas/format-v1.schema.json", "$schema": "https://lnav.org/schemas/format-v1.schema.json",
"nextflow_log": { "nextflow_log": {
"title": "Nextflow log format",
"description": "Format file for nextflow.io logs", "description": "Format file for nextflow.io logs",
"url": [ "url": [
"https://nextflow.io/docs/latest/cli.html#execution-logs" "https://nextflow.io/docs/latest/cli.html#execution-logs"

@ -241,6 +241,17 @@
"pattern": "^Expected equality of these values:" "pattern": "^Expected equality of these values:"
} }
}, },
"partitions": {
"test-partition": {
"description": "Partition for gtest sections",
"paths": [
{
"glob": "*/test.log"
}
],
"pattern": "^\\[ RUN \\] ([^\\n]+)"
}
},
"sample": [ "sample": [
{ {
"line": "2021-05-24T20:31:05.671Z - last log rotation time, 2021-05-24T09:30:02.683Z - time the service was last started, Section for VMware ESX, pid=1000080910, version=7.0.3, build=0, option=DEBUG" "line": "2021-05-24T20:31:05.671Z - last log rotation time, 2021-05-24T09:30:02.683Z - time the service was last started, Section for VMware ESX, pid=1000080910, version=7.0.3, build=0, option=DEBUG"

@ -219,7 +219,7 @@ that you can always use `q` to pop the top view off of the stack.
| o/O | Move forward/backward to the log message with a matching 'operation ID' (opid) field. | | o/O | Move forward/backward to the log message with a matching 'operation ID' (opid) field. |
| u/U | Move forward/backward through any user bookmarks you have added using the 'm' key. This hotkey will also jump to the start of any log partitions that have been created with the 'partition-name' command. | | u/U | Move forward/backward through any user bookmarks you have added using the 'm' key. This hotkey will also jump to the start of any log partitions that have been created with the 'partition-name' command. |
| s/S | Move to the next/previous "slow down" in the log message rate. A slow down is detected by measuring how quickly the message rate has changed over the previous several messages. For example, if one message is logged every second for five seconds and then the last message arrives five seconds later, the last message will be highlighted as a slow down. | | s/S | Move to the next/previous "slow down" in the log message rate. A slow down is detected by measuring how quickly the message rate has changed over the previous several messages. For example, if one message is logged every second for five seconds and then the last message arrives five seconds later, the last message will be highlighted as a slow down. |
| {/} | Move to the previous/next location in history. Whenever you jump to a new location in the view, the location will be added to the history. The history is not updated when using only the arrow keys. | | {/} | Move to the previous/next section in the view. In the LOG view, this moves through partitions. In other views, it moves through sections of documents. |
### Chronological Navigation ### Chronological Navigation

@ -11,8 +11,8 @@
"keymap_def_pop_view": "Press ${ansi_bold}q${ansi_norm} to return to the previous view", "keymap_def_pop_view": "Press ${ansi_bold}q${ansi_norm} to return to the previous view",
"keymap_def_zoom": "Press ${ansi_bold}z${ansi_norm}/${ansi_bold}Z${ansi_norm} to zoom in/out", "keymap_def_zoom": "Press ${ansi_bold}z${ansi_norm}/${ansi_bold}Z${ansi_norm} to zoom in/out",
"keymap_def_clear": "Press ${ansi_bold}C${ansi_norm} to clear marked messages", "keymap_def_clear": "Press ${ansi_bold}C${ansi_norm} to clear marked messages",
"keymap_def_prev_section": "Press ${ansi_bold}{${ansi_norm} to move to the previous section in history", "keymap_def_prev_section": "Press ${ansi_bold}{${ansi_norm} to move to the previous section in the view",
"keymap_def_next_section": "Press ${ansi_bold}}${ansi_norm} to move to the next section in history", "keymap_def_next_section": "Press ${ansi_bold}}${ansi_norm} to move to the next section in the view",
"keymap_def_next_mark": "Press ${ansi_bold}c${ansi_norm} to copy marked lines to the clipboard; press ${ansi_bold}C${ansi_norm} to clear marked lines", "keymap_def_next_mark": "Press ${ansi_bold}c${ansi_norm} to copy marked lines to the clipboard; press ${ansi_bold}C${ansi_norm} to clear marked lines",
"keymap_def_time_offset": "Press ${ansi_bold}s${ansi_norm}/${ansi_bold}S${ansi_norm} to move forward/backward through slow downs" "keymap_def_time_offset": "Press ${ansi_bold}s${ansi_norm}/${ansi_bold}S${ansi_norm} to move forward/backward through slow downs"
}, },

@ -3703,10 +3703,12 @@ com_clear_comment(exec_context& ec,
bookmark_metadata& line_meta = *(line_meta_opt.value()); bookmark_metadata& line_meta = *(line_meta_opt.value());
line_meta.bm_comment.clear(); line_meta.bm_comment.clear();
if (line_meta.empty()) { if (line_meta.empty(bookmark_metadata::categories::notes)) {
lss.erase_bookmark_metadata(tc->get_selection());
tc->set_user_mark( tc->set_user_mark(
&textview_curses::BM_META, tc->get_selection(), false); &textview_curses::BM_META, tc->get_selection(), false);
if (line_meta.empty(bookmark_metadata::categories::any)) {
lss.erase_bookmark_metadata(tc->get_selection());
}
} }
lss.set_line_meta_changed(); lss.set_line_meta_changed();
@ -3786,7 +3788,7 @@ com_untag(exec_context& ec, std::string cmdline, std::vector<std::string>& args)
auto line_meta_opt = lss.find_bookmark_metadata(tc->get_selection()); auto line_meta_opt = lss.find_bookmark_metadata(tc->get_selection());
if (line_meta_opt) { if (line_meta_opt) {
bookmark_metadata& line_meta = *(line_meta_opt.value()); auto& line_meta = *(line_meta_opt.value());
for (size_t lpc = 1; lpc < args.size(); lpc++) { for (size_t lpc = 1; lpc < args.size(); lpc++) {
std::string tag = args[lpc]; std::string tag = args[lpc];
@ -3796,7 +3798,7 @@ com_untag(exec_context& ec, std::string cmdline, std::vector<std::string>& args)
} }
line_meta.remove_tag(tag); line_meta.remove_tag(tag);
} }
if (line_meta.empty()) { if (line_meta.empty(bookmark_metadata::categories::notes)) {
tc->set_user_mark( tc->set_user_mark(
&textview_curses::BM_META, tc->get_selection(), false); &textview_curses::BM_META, tc->get_selection(), false);
} }
@ -3868,12 +3870,14 @@ com_delete_tags(exec_context& ec,
line_meta->remove_tag(tag); line_meta->remove_tag(tag);
} }
if (line_meta->empty()) { if (line_meta->empty(bookmark_metadata::categories::notes)) {
lss.erase_bookmark_metadata(*iter); size_t off = std::distance(vbm.begin(), iter);
size_t off = distance(vbm.begin(), iter);
tc->set_user_mark(&textview_curses::BM_META, *iter, false); tc->set_user_mark(&textview_curses::BM_META, *iter, false);
iter = next(vbm.begin(), off); if (line_meta->empty(bookmark_metadata::categories::any)) {
lss.erase_bookmark_metadata(*iter);
}
iter = std::next(vbm.begin(), off);
} else { } else {
++iter; ++iter;
} }
@ -3906,7 +3910,7 @@ com_partition_name(exec_context& ec,
args[1] = trim(remaining_args(cmdline, args)); args[1] = trim(remaining_args(cmdline, args));
tc.set_user_mark( tc.set_user_mark(
&textview_curses::BM_META, tc.get_selection(), true); &textview_curses::BM_PARTITION, tc.get_selection(), true);
auto& line_meta = lss.get_bookmark_metadata(tc.get_selection()); auto& line_meta = lss.get_bookmark_metadata(tc.get_selection());
@ -3932,7 +3936,7 @@ com_clear_partition(exec_context& ec,
} else if (args.size() == 1) { } else if (args.size() == 1) {
textview_curses& tc = lnav_data.ld_views[LNV_LOG]; textview_curses& tc = lnav_data.ld_views[LNV_LOG];
logfile_sub_source& lss = lnav_data.ld_log_source; logfile_sub_source& lss = lnav_data.ld_log_source;
auto& bv = tc.get_bookmarks()[&textview_curses::BM_META]; auto& bv = tc.get_bookmarks()[&textview_curses::BM_PARTITION];
nonstd::optional<vis_line_t> part_start; nonstd::optional<vis_line_t> part_start;
if (binary_search(bv.begin(), bv.end(), tc.get_selection())) { if (binary_search(bv.begin(), bv.end(), tc.get_selection())) {
@ -3948,10 +3952,12 @@ com_clear_partition(exec_context& ec,
auto& line_meta = lss.get_bookmark_metadata(part_start.value()); auto& line_meta = lss.get_bookmark_metadata(part_start.value());
line_meta.bm_name.clear(); line_meta.bm_name.clear();
if (line_meta.empty()) { if (line_meta.empty(bookmark_metadata::categories::partition)) {
lss.erase_bookmark_metadata(part_start.value());
tc.set_user_mark( tc.set_user_mark(
&textview_curses::BM_META, part_start.value(), false); &textview_curses::BM_PARTITION, part_start.value(), false);
if (line_meta.empty(bookmark_metadata::categories::any)) {
lss.erase_bookmark_metadata(part_start.value());
}
} }
retval = "info: cleared partition name"; retval = "info: cleared partition name";

@ -4240,5 +4240,11 @@ format_tag_def::path_restriction::matches(const char* fn) const
return fnmatch(this->p_glob.c_str(), fn, 0) == 0; return fnmatch(this->p_glob.c_str(), fn, 0) == 0;
} }
bool
format_partition_def::path_restriction::matches(const char* fn) const
{
return fnmatch(this->p_glob.c_str(), fn, 0) == 0;
}
/* XXX */ /* XXX */
#include "log_format_impls.cc" #include "log_format_impls.cc"

@ -581,6 +581,9 @@ public:
std::map<const intern_string_t, std::shared_ptr<format_tag_def>> std::map<const intern_string_t, std::shared_ptr<format_tag_def>>
lf_tag_defs; lf_tag_defs;
std::map<const intern_string_t, std::shared_ptr<format_partition_def>>
lf_partition_defs;
struct opid_descriptor { struct opid_descriptor {
positioned_property<intern_string_t> od_field; positioned_property<intern_string_t> od_field;
factory_container<lnav::pcre2pp::code> od_extractor; factory_container<lnav::pcre2pp::code> od_extractor;

@ -146,7 +146,7 @@ public:
uint8_t opid = 0) uint8_t opid = 0)
: ll_offset(off), ll_has_ansi(false), ll_time(t), ll_millis(millis), : ll_offset(off), ll_has_ansi(false), ll_time(t), ll_millis(millis),
ll_opid(opid), ll_sub_offset(0), ll_valid_utf(1), ll_level(lev), ll_opid(opid), ll_sub_offset(0), ll_valid_utf(1), ll_level(lev),
ll_module_id(mod), ll_expr_mark(0) ll_module_id(mod), ll_meta_mark(0), ll_expr_mark(0)
{ {
memset(this->ll_schema, 0, sizeof(this->ll_schema)); memset(this->ll_schema, 0, sizeof(this->ll_schema));
} }
@ -157,7 +157,8 @@ public:
uint8_t mod = 0, uint8_t mod = 0,
uint8_t opid = 0) uint8_t opid = 0)
: ll_offset(off), ll_has_ansi(false), ll_opid(opid), ll_sub_offset(0), : ll_offset(off), ll_has_ansi(false), ll_opid(opid), ll_sub_offset(0),
ll_valid_utf(1), ll_level(lev), ll_module_id(mod), ll_expr_mark(0) ll_valid_utf(1), ll_level(lev), ll_module_id(mod), ll_meta_mark(0),
ll_expr_mark(0)
{ {
this->set_time(tv); this->set_time(tv);
memset(this->ll_schema, 0, sizeof(this->ll_schema)); memset(this->ll_schema, 0, sizeof(this->ll_schema));
@ -226,6 +227,10 @@ public:
bool is_marked() const { return this->ll_level & LEVEL_MARK; } bool is_marked() const { return this->ll_level & LEVEL_MARK; }
void set_meta_mark(bool val) { this->ll_meta_mark = val; }
bool is_meta_marked() const { return this->ll_meta_mark; }
void set_expr_mark(bool val) { this->ll_expr_mark = val; } void set_expr_mark(bool val) { this->ll_expr_mark = val; }
bool is_expr_marked() const { return this->ll_expr_mark; } bool is_expr_marked() const { return this->ll_expr_mark; }
@ -367,7 +372,8 @@ private:
unsigned int ll_sub_offset : 15; unsigned int ll_sub_offset : 15;
unsigned int ll_valid_utf : 1; unsigned int ll_valid_utf : 1;
uint8_t ll_level; uint8_t ll_level;
uint8_t ll_module_id : 7; uint8_t ll_module_id : 6;
uint8_t ll_meta_mark : 1;
uint8_t ll_expr_mark : 1; uint8_t ll_expr_mark : 1;
char ll_schema[2]; char ll_schema[2];
}; };
@ -389,4 +395,23 @@ struct format_tag_def {
log_level_t ftd_level{LEVEL_UNKNOWN}; log_level_t ftd_level{LEVEL_UNKNOWN};
}; };
struct format_partition_def {
explicit format_partition_def(std::string name) : fpd_name(std::move(name))
{
}
struct path_restriction {
std::string p_glob;
bool matches(const char* fn) const;
};
std::string fpd_name;
std::string fpd_description;
std::vector<path_restriction> fpd_paths;
factory_container<lnav::pcre2pp::code, int>::with_default_args<PCRE2_DOTALL>
fpd_pattern;
log_level_t fpd_level{LEVEL_UNKNOWN};
};
#endif #endif

@ -171,6 +171,26 @@ format_tag_def_provider(const yajlpp_provider_context& ypc,
return retval.get(); return retval.get();
} }
static format_partition_def*
format_partition_def_provider(const yajlpp_provider_context& ypc,
external_log_format* elf)
{
const intern_string_t partition_name = ypc.get_substr_i(0);
auto iter = elf->lf_partition_defs.find(partition_name);
std::shared_ptr<format_partition_def> retval;
if (iter == elf->lf_partition_defs.end()) {
retval = std::make_shared<format_partition_def>(
partition_name.to_string());
elf->lf_partition_defs[partition_name] = retval;
} else {
retval = iter->second;
}
return retval.get();
}
static scaling_factor* static scaling_factor*
scaling_factor_provider(const yajlpp_provider_context& ypc, scaling_factor_provider(const yajlpp_provider_context& ypc,
external_log_format::value_def* value_def) external_log_format::value_def* value_def)
@ -759,6 +779,35 @@ static const struct json_path_container tag_handlers = {
.with_children(format_tag_def_handlers), .with_children(format_tag_def_handlers),
}; };
static const struct json_path_container format_partition_def_handlers = {
yajlpp::property_handler("paths#")
.with_description("Restrict partitioning to the given paths")
.for_field(&format_partition_def::fpd_paths)
.with_children(tag_path_handlers),
yajlpp::property_handler("pattern")
.with_synopsis("<regex>")
.with_description("The regular expression to match against the body of "
"the log message")
.with_example("\\w+ is down")
.for_field(&format_partition_def::fpd_pattern),
yajlpp::property_handler("description")
.with_synopsis("<string>")
.with_description("A description of this partition")
.for_field(&format_partition_def::fpd_description),
json_path_handler("level")
.with_synopsis("<log-level>")
.with_description("Constrain hits to log messages with this level")
.with_enum_values(LEVEL_ENUM)
.for_field(&format_partition_def::fpd_level),
};
static const struct json_path_container partition_handlers = {
yajlpp::pattern_property_handler(R"((?<partition_type>[\w:;\._\-]+))")
.with_description("The type of partition to apply")
.with_obj_provider(format_partition_def_provider)
.with_children(format_partition_def_handlers),
};
static const struct json_path_container highlight_handlers = { static const struct json_path_container highlight_handlers = {
yajlpp::pattern_property_handler(R"((?<highlight_name>[^/]+))") yajlpp::pattern_property_handler(R"((?<highlight_name>[^/]+))")
.with_description("The definition of a highlight") .with_description("The definition of a highlight")
@ -1010,6 +1059,11 @@ const struct json_path_container format_handlers = {
.with_description("The tags to automatically apply to log messages") .with_description("The tags to automatically apply to log messages")
.with_children(tag_handlers), .with_children(tag_handlers),
yajlpp::property_handler("partitions")
.with_description(
"The partitions to automatically apply to log messages")
.with_children(partition_handlers),
yajlpp::property_handler("action").with_children(action_handlers), yajlpp::property_handler("action").with_children(action_handlers),
yajlpp::property_handler("sample#") yajlpp::property_handler("sample#")
.with_description("An array of sample log messages to be tested " .with_description("An array of sample log messages to be tested "

@ -626,7 +626,7 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
case VT_COL_PARTITION: { case VT_COL_PARTITION: {
auto& vb = vt->tc->get_bookmarks(); auto& vb = vt->tc->get_bookmarks();
const auto& bv = vb[&textview_curses::BM_META]; const auto& bv = vb[&textview_curses::BM_PARTITION];
if (bv.empty()) { if (bv.empty()) {
sqlite3_result_null(ctx); sqlite3_result_null(ctx);
@ -1985,23 +1985,35 @@ vt_update(sqlite3_vtab* tab,
tmp_bm.bm_annotations = parse_res.unwrap(); tmp_bm.bm_annotations = parse_res.unwrap();
} }
auto& bv = vt->tc->get_bookmarks()[&textview_curses::BM_META]; auto& bv_meta = vt->tc->get_bookmarks()[&textview_curses::BM_META];
bool has_meta = part_name != nullptr || log_comment != nullptr bool has_meta = log_comment != nullptr || log_tags.has_value()
|| log_tags.has_value() || log_annos.has_value(); || log_annos.has_value();
if (binary_search(bv.begin(), bv.end(), vrowid) && !has_meta) { if (std::binary_search(bv_meta.begin(), bv_meta.end(), vrowid)
&& !has_meta)
{
vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, false); vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, false);
vt->lss->erase_bookmark_metadata(vrowid);
vt->lss->set_line_meta_changed(); vt->lss->set_line_meta_changed();
} }
if (!has_meta && part_name == nullptr) {
vt->lss->erase_bookmark_metadata(vrowid);
}
if (part_name) {
auto& line_meta = vt->lss->get_bookmark_metadata(vrowid);
line_meta.bm_name = std::string((const char*) part_name);
vt->tc->set_user_mark(&textview_curses::BM_PARTITION, vrowid, true);
} else {
vt->tc->set_user_mark(
&textview_curses::BM_PARTITION, vrowid, false);
}
if (has_meta) { if (has_meta) {
auto& line_meta = vt->lss->get_bookmark_metadata(vrowid); auto& line_meta = vt->lss->get_bookmark_metadata(vrowid);
vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, true); vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, true);
if (part_name) { if (part_name == nullptr) {
line_meta.bm_name = std::string((const char*) part_name);
} else {
line_meta.bm_name.clear(); line_meta.bm_name.clear();
} }
if (log_comment) { if (log_comment) {

@ -433,6 +433,27 @@ logfile::process_prefix(shared_buffer_ref& sbr,
this->lf_applicable_taggers.emplace_back(td_pair.second); this->lf_applicable_taggers.emplace_back(td_pair.second);
} }
for (auto& pd_pair : this->lf_format->lf_partition_defs) {
bool matches = pd_pair.second->fpd_paths.empty();
for (const auto& pr : pd_pair.second->fpd_paths) {
if (pr.matches(this->lf_filename.c_str())) {
matches = true;
break;
}
}
if (!matches) {
continue;
}
log_info(
"%s: found applicable partition definition "
"/%s/partitions/%s",
this->lf_filename.c_str(),
this->lf_format->get_name().get(),
pd_pair.second->fpd_name.c_str());
this->lf_applicable_partitioners.emplace_back(pd_pair.second);
}
/* /*
* We'll go ahead and assume that any previous lines were * We'll go ahead and assume that any previous lines were
* written out at the same time as the last one, so we need to * written out at the same time as the last one, so we need to
@ -844,33 +865,60 @@ logfile::rebuild_index(nonstd::optional<ui_clock::time_point> deadline)
} }
#endif #endif
if (this->lf_format) { if (this->lf_format) {
if (!this->lf_applicable_taggers.empty()) { auto sf = sbr.to_string_fragment();
auto sf = sbr.to_string_fragment();
for (const auto& td : this->lf_applicable_taggers) {
auto curr_ll = this->end() - 1;
for (const auto& td : this->lf_applicable_taggers) { if (td->ftd_level != LEVEL_UNKNOWN
auto curr_ll = this->end() - 1; && td->ftd_level != curr_ll->get_msg_level())
{
continue;
}
if (td->ftd_level != LEVEL_UNKNOWN if (td->ftd_pattern.pp_value
&& td->ftd_level != curr_ll->get_msg_level()) ->find_in(sf, PCRE2_NO_UTF_CHECK)
{ .ignore_error()
continue; .has_value())
{
while (curr_ll->is_continued()) {
--curr_ll;
} }
curr_ll->set_meta_mark(true);
auto line_number = static_cast<uint32_t>(
std::distance(this->begin(), curr_ll));
this->lf_bookmark_metadata[line_number].add_tag(
td->ftd_name);
}
}
if (td->ftd_pattern.pp_value for (const auto& pd : this->lf_applicable_partitioners) {
->find_in(sf, PCRE2_NO_UTF_CHECK) static thread_local auto part_md
.ignore_error() = lnav::pcre2pp::match_data::unitialized();
.has_value())
{ auto curr_ll = this->end() - 1;
while (curr_ll->is_continued()) {
--curr_ll; if (pd->fpd_level != LEVEL_UNKNOWN
} && pd->fpd_level != curr_ll->get_msg_level())
curr_ll->set_mark(true); {
auto line_number = static_cast<uint32_t>( continue;
std::distance(this->begin(), curr_ll)); }
this->lf_bookmark_metadata[line_number].add_tag( auto match_res = pd->fpd_pattern.pp_value->capture_from(sf)
td->ftd_name); .into(part_md)
.matches(PCRE2_NO_UTF_CHECK)
.ignore_error();
if (match_res) {
while (curr_ll->is_continued()) {
--curr_ll;
} }
curr_ll->set_meta_mark(true);
auto line_number = static_cast<uint32_t>(
std::distance(this->begin(), curr_ll));
this->lf_bookmark_metadata[line_number].bm_name
= part_md.to_string();
} }
} }

@ -472,6 +472,8 @@ private:
robin_hood::unordered_map<uint32_t, bookmark_metadata> lf_bookmark_metadata; robin_hood::unordered_map<uint32_t, bookmark_metadata> lf_bookmark_metadata;
std::vector<std::shared_ptr<format_tag_def>> lf_applicable_taggers; std::vector<std::shared_ptr<format_tag_def>> lf_applicable_taggers;
std::vector<std::shared_ptr<format_partition_def>>
lf_applicable_partitioners;
std::map<std::string, metadata> lf_embedded_metadata; std::map<std::string, metadata> lf_embedded_metadata;
size_t lf_file_options_generation{0}; size_t lf_file_options_generation{0};
nonstd::optional<std::pair<std::string, lnav::file_options>> nonstd::optional<std::pair<std::string, lnav::file_options>>

@ -214,10 +214,10 @@ struct filtered_logline_cmp {
nonstd::optional<vis_line_t> nonstd::optional<vis_line_t>
logfile_sub_source::find_from_time(const struct timeval& start) const logfile_sub_source::find_from_time(const struct timeval& start) const
{ {
auto lb = lower_bound(this->lss_filtered_index.begin(), auto lb = std::lower_bound(this->lss_filtered_index.begin(),
this->lss_filtered_index.end(), this->lss_filtered_index.end(),
start, start,
filtered_logline_cmp(*this)); filtered_logline_cmp(*this));
if (lb != this->lss_filtered_index.end()) { if (lb != this->lss_filtered_index.end()) {
return vis_line_t(lb - this->lss_filtered_index.begin()); return vis_line_t(lb - this->lss_filtered_index.begin());
} }
@ -604,20 +604,15 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv,
lr, SA_FORMAT.value(this->lss_token_file->get_format()->get_name())); lr, SA_FORMAT.value(this->lss_token_file->get_format()->get_name()));
{ {
const auto& bv = lv.get_bookmarks()[&textview_curses::BM_META]; auto line_meta_context = this->get_bookmark_metadata_context(
bookmark_vector<vis_line_t>::const_iterator bv_iter; vis_line_t(row + 1), bookmark_metadata::categories::partition);
if (line_meta_context.bmc_current_metadata) {
bv_iter = lower_bound(bv.begin(), bv.end(), vis_line_t(row + 1)); lr.lr_start = 0;
if (bv_iter != bv.begin()) { lr.lr_end = -1;
--bv_iter; value_out.emplace_back(
auto line_meta_opt = this->find_bookmark_metadata(*bv_iter); lr,
logline::L_PARTITION.value(
if (line_meta_opt && !line_meta_opt.value()->bm_name.empty()) { line_meta_context.bmc_current_metadata.value()));
lr.lr_start = 0;
lr.lr_end = -1;
value_out.emplace_back(
lr, logline::L_PARTITION.value(line_meta_opt.value()));
}
} }
auto line_meta_opt = this->find_bookmark_metadata(vis_line_t(row)); auto line_meta_opt = this->find_bookmark_metadata(vis_line_t(row));
@ -1021,7 +1016,7 @@ logfile_sub_source::rebuild_index(
content_line_t con_line( content_line_t con_line(
ld->ld_file_index * MAX_LINES_PER_FILE + line_index); ld->ld_file_index * MAX_LINES_PER_FILE + line_index);
if (lf_iter->is_marked()) { if (lf_iter->is_meta_marked()) {
auto start_iter = lf_iter; auto start_iter = lf_iter;
while (start_iter->is_continued()) { while (start_iter->is_continued()) {
--start_iter; --start_iter;
@ -1032,9 +1027,20 @@ logfile_sub_source::rebuild_index(
* MAX_LINES_PER_FILE * MAX_LINES_PER_FILE
+ start_index); + start_index);
this->lss_user_marks[&textview_curses::BM_META] auto& line_meta
.insert_once(start_con_line); = ld->get_file_ptr()
lf_iter->set_mark(false); ->get_bookmark_metadata()[start_index];
if (line_meta.has(bookmark_metadata::categories::notes))
{
this->lss_user_marks[&textview_curses::BM_META]
.insert_once(start_con_line);
}
if (line_meta.has(
bookmark_metadata::categories::partition))
{
this->lss_user_marks[&textview_curses::BM_PARTITION]
.insert_once(start_con_line);
}
} }
this->lss_index.push_back(con_line); this->lss_index.push_back(con_line);
} }
@ -1088,7 +1094,7 @@ logfile_sub_source::rebuild_index(
content_line_t con_line(file_index * MAX_LINES_PER_FILE content_line_t con_line(file_index * MAX_LINES_PER_FILE
+ line_index); + line_index);
if (lf_iter->is_marked()) { if (lf_iter->is_meta_marked()) {
auto start_iter = lf_iter; auto start_iter = lf_iter;
while (start_iter->is_continued()) { while (start_iter->is_continued()) {
--start_iter; --start_iter;
@ -1098,9 +1104,20 @@ logfile_sub_source::rebuild_index(
content_line_t start_con_line( content_line_t start_con_line(
file_index * MAX_LINES_PER_FILE + start_index); file_index * MAX_LINES_PER_FILE + start_index);
this->lss_user_marks[&textview_curses::BM_META] auto& line_meta
.insert_once(start_con_line); = ld->get_file_ptr()
lf_iter->set_mark(false); ->get_bookmark_metadata()[start_index];
if (line_meta.has(bookmark_metadata::categories::notes))
{
this->lss_user_marks[&textview_curses::BM_META]
.insert_once(start_con_line);
}
if (line_meta.has(
bookmark_metadata::categories::partition))
{
this->lss_user_marks[&textview_curses::BM_PARTITION]
.insert_once(start_con_line);
}
} }
this->lss_index.push_back(con_line); this->lss_index.push_back(con_line);
} }
@ -2347,7 +2364,43 @@ logfile_sub_source::text_crumbs_for_line(int line,
return; return;
} }
auto line_pair_opt = this->find_line_with_file(vis_line_t(line)); auto vl = vis_line_t(line);
auto bmc = this->get_bookmark_metadata_context(
vl, bookmark_metadata::categories::partition);
if (bmc.bmc_current_metadata) {
const auto& name = bmc.bmc_current_metadata.value()->bm_name;
auto key = text_anchors::to_anchor_string(name);
auto display = attr_line_t()
.append("\u2291 "_symbol)
.append(lnav::roles::variable(name));
crumbs.emplace_back(
key,
display,
[this]() -> std::vector<breadcrumb::possibility> {
auto& vb = this->tss_view->get_bookmarks();
const auto& bv = vb[&textview_curses::BM_PARTITION];
std::vector<breadcrumb::possibility> retval;
for (const auto& vl : bv) {
auto meta_opt = this->find_bookmark_metadata(vl);
if (!meta_opt || meta_opt.value()->bm_name.empty()) {
continue;
}
const auto& name = meta_opt.value()->bm_name;
retval.emplace_back(text_anchors::to_anchor_string(name),
name);
}
return retval;
},
[ec = this->lss_exec_context](const auto& part) {
ec->execute(fmt::format(FMT_STRING(":goto {}"),
part.template get<std::string>()));
});
}
auto line_pair_opt = this->find_line_with_file(vl);
if (!line_pair_opt) { if (!line_pair_opt) {
return; return;
} }
@ -2627,8 +2680,62 @@ logfile_sub_source::get_bookmark_metadata(content_line_t cl)
return line_pair.first->get_bookmark_metadata()[line_number]; return line_pair.first->get_bookmark_metadata()[line_number];
} }
logfile_sub_source::bookmark_metadata_context
logfile_sub_source::get_bookmark_metadata_context(
vis_line_t vl, bookmark_metadata::categories desired) const
{
const auto& vb = this->tss_view->get_bookmarks();
const auto bv_iter
= vb.find(desired == bookmark_metadata::categories::partition
? &textview_curses::BM_PARTITION
: &textview_curses::BM_META);
if (bv_iter == vb.end()) {
return bookmark_metadata_context{};
}
const auto& bv = bv_iter->second;
auto vl_iter = std::lower_bound(bv.begin(), bv.end(), vl + 1_vl);
nonstd::optional<vis_line_t> next_line;
for (auto next_vl_iter = vl_iter; next_vl_iter != bv.end(); ++next_vl_iter)
{
auto bm_opt = this->find_bookmark_metadata(*next_vl_iter);
if (!bm_opt) {
continue;
}
if (bm_opt.value()->has(desired)) {
next_line = *next_vl_iter;
break;
}
}
if (vl_iter == bv.begin()) {
return bookmark_metadata_context{
nonstd::nullopt, nonstd::nullopt, next_line};
}
--vl_iter;
while (true) {
auto bm_opt = this->find_bookmark_metadata(*vl_iter);
if (bm_opt) {
if (bm_opt.value()->has(desired)) {
return bookmark_metadata_context{
*vl_iter, bm_opt.value(), next_line};
}
}
if (vl_iter == bv.begin()) {
return bookmark_metadata_context{
nonstd::nullopt, nonstd::nullopt, next_line};
}
--vl_iter;
}
return bookmark_metadata_context{
nonstd::nullopt, nonstd::nullopt, next_line};
}
nonstd::optional<bookmark_metadata*> nonstd::optional<bookmark_metadata*>
logfile_sub_source::find_bookmark_metadata(content_line_t cl) logfile_sub_source::find_bookmark_metadata(content_line_t cl) const
{ {
auto line_pair = this->find_line_with_file(cl).value(); auto line_pair = this->find_line_with_file(cl).value();
auto line_number = static_cast<uint32_t>( auto line_number = static_cast<uint32_t>(
@ -2806,3 +2913,84 @@ logfile_sub_source::row_for(const row_info& ri)
return nonstd::nullopt; return nonstd::nullopt;
} }
nonstd::optional<vis_line_t>
logfile_sub_source::row_for_anchor(const std::string& id)
{
auto& vb = this->tss_view->get_bookmarks();
const auto& bv = vb[&textview_curses::BM_PARTITION];
for (const auto& vl : bv) {
auto meta_opt = this->find_bookmark_metadata(vl);
if (!meta_opt || meta_opt.value()->bm_name.empty()) {
continue;
}
const auto& name = meta_opt.value()->bm_name;
if (id == text_anchors::to_anchor_string(name)) {
return vl;
}
}
return nonstd::nullopt;
}
nonstd::optional<vis_line_t>
logfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir)
{
auto bmc = this->get_bookmark_metadata_context(
vl, bookmark_metadata::categories::partition);
switch (dir) {
case text_anchors::direction::prev: {
if (bmc.bmc_current && bmc.bmc_current.value() != vl) {
return bmc.bmc_current;
}
if (!bmc.bmc_current || bmc.bmc_current.value() == 0_vl) {
return 0_vl;
}
auto prev_bmc = this->get_bookmark_metadata_context(
bmc.bmc_current.value() - 1_vl,
bookmark_metadata::categories::partition);
if (!prev_bmc.bmc_current) {
return 0_vl;
}
return prev_bmc.bmc_current;
}
case text_anchors::direction::next:
return bmc.bmc_next_line;
}
return nonstd::nullopt;
}
nonstd::optional<std::string>
logfile_sub_source::anchor_for_row(vis_line_t vl)
{
auto line_meta = this->get_bookmark_metadata_context(
vl, bookmark_metadata::categories::partition);
if (!line_meta.bmc_current_metadata) {
return nonstd::nullopt;
}
return text_anchors::to_anchor_string(
line_meta.bmc_current_metadata.value()->bm_name);
}
std::unordered_set<std::string>
logfile_sub_source::get_anchors()
{
auto& vb = this->tss_view->get_bookmarks();
const auto& bv = vb[&textview_curses::BM_PARTITION];
std::unordered_set<std::string> retval;
for (const auto& vl : bv) {
auto meta_opt = this->find_bookmark_metadata(vl);
if (!meta_opt || meta_opt.value()->bm_name.empty()) {
continue;
}
const auto& name = meta_opt.value()->bm_name;
retval.emplace(text_anchors::to_anchor_string(name));
}
return retval;
}

@ -200,7 +200,8 @@ class logfile_sub_source
: public text_sub_source : public text_sub_source
, public text_time_translator , public text_time_translator
, public text_accel_source , public text_accel_source
, public list_input_delegate { , public list_input_delegate
, public text_anchors {
public: public:
const static bookmark_type_t BM_ERRORS; const static bookmark_type_t BM_ERRORS;
const static bookmark_type_t BM_WARNINGS; const static bookmark_type_t BM_WARNINGS;
@ -351,10 +352,22 @@ public:
return this->get_bookmark_metadata(this->at(vl)); return this->get_bookmark_metadata(this->at(vl));
} }
struct bookmark_metadata_context {
nonstd::optional<vis_line_t> bmc_current;
nonstd::optional<bookmark_metadata*> bmc_current_metadata;
nonstd::optional<vis_line_t> bmc_next_line;
};
bookmark_metadata_context get_bookmark_metadata_context(
vis_line_t vl,
bookmark_metadata::categories desired
= bookmark_metadata::categories::any) const;
nonstd::optional<bookmark_metadata*> find_bookmark_metadata( nonstd::optional<bookmark_metadata*> find_bookmark_metadata(
content_line_t cl); content_line_t cl) const;
nonstd::optional<bookmark_metadata*> find_bookmark_metadata(vis_line_t vl) nonstd::optional<bookmark_metadata*> find_bookmark_metadata(
vis_line_t vl) const
{ {
return this->find_bookmark_metadata(this->at(vl)); return this->find_bookmark_metadata(this->at(vl));
} }
@ -712,6 +725,14 @@ public:
big_array<indexed_content> lss_index; big_array<indexed_content> lss_index;
nonstd::optional<vis_line_t> row_for_anchor(const std::string& id);
nonstd::optional<vis_line_t> adjacent_anchor(vis_line_t vl, direction dir);
nonstd::optional<std::string> anchor_for_row(vis_line_t vl);
std::unordered_set<std::string> get_anchors();
protected: protected:
void text_accel_display_changed() { this->clear_line_size_cache(); } void text_accel_display_changed() { this->clear_line_size_cache(); }

@ -482,10 +482,10 @@ add_tag_possibilities()
if (lnav_data.ld_view_stack.top().value_or(nullptr) if (lnav_data.ld_view_stack.top().value_or(nullptr)
== &lnav_data.ld_views[LNV_LOG]) == &lnav_data.ld_views[LNV_LOG])
{ {
logfile_sub_source& lss = lnav_data.ld_log_source; auto& lss = lnav_data.ld_log_source;
if (lss.text_line_count() > 0) { if (lss.text_line_count() > 0) {
auto line_meta_opt = lss.find_bookmark_metadata( auto line_meta_opt = lss.find_bookmark_metadata(
lnav_data.ld_views[LNV_LOG].get_top()); lnav_data.ld_views[LNV_LOG].get_selection());
if (line_meta_opt) { if (line_meta_opt) {
rc->add_possibility(ln_mode_t::COMMAND, rc->add_possibility(ln_mode_t::COMMAND,
"line-tags", "line-tags",

@ -604,7 +604,7 @@ load_time_bookmarks()
bool meta = false; bool meta = false;
if (part_name != nullptr && part_name[0] != '\0') { if (part_name != nullptr && part_name[0] != '\0') {
lss.set_user_mark(&textview_curses::BM_META, lss.set_user_mark(&textview_curses::BM_PARTITION,
line_cl); line_cl);
bm_meta[line_number].bm_name = part_name; bm_meta[line_number].bm_name = part_name;
meta = true; meta = true;
@ -1041,7 +1041,7 @@ save_user_bookmarks(sqlite3* db,
} }
} else { } else {
const auto& line_meta = *(line_meta_opt.value()); const auto& line_meta = *(line_meta_opt.value());
if (line_meta.empty()) { if (line_meta.empty(bookmark_metadata::categories::any)) {
continue; continue;
} }
@ -1286,7 +1286,11 @@ save_time_bookmarks()
} }
save_user_bookmarks(db.in(), stmt.in(), bm[&textview_curses::BM_USER]); save_user_bookmarks(db.in(), stmt.in(), bm[&textview_curses::BM_USER]);
save_user_bookmarks(db.in(), stmt.in(), bm[&textview_curses::BM_META]); auto all_meta_marks = bm[&textview_curses::BM_META];
const auto& bm_parts = bm[&textview_curses::BM_PARTITION];
all_meta_marks.insert(
all_meta_marks.end(), bm_parts.begin(), bm_parts.end());
save_user_bookmarks(db.in(), stmt.in(), all_meta_marks);
if (sqlite3_prepare_v2(db.in(), if (sqlite3_prepare_v2(db.in(),
"DELETE FROM time_offset WHERE " "DELETE FROM time_offset WHERE "

@ -180,6 +180,7 @@ const bookmark_type_t textview_curses::BM_USER("user");
const bookmark_type_t textview_curses::BM_USER_EXPR("user-expr"); const bookmark_type_t textview_curses::BM_USER_EXPR("user-expr");
const bookmark_type_t textview_curses::BM_SEARCH("search"); const bookmark_type_t textview_curses::BM_SEARCH("search");
const bookmark_type_t textview_curses::BM_META("meta"); const bookmark_type_t textview_curses::BM_META("meta");
const bookmark_type_t textview_curses::BM_PARTITION("partition");
textview_curses::textview_curses() textview_curses::textview_curses()
: lnav_config_listener(__FILE__), tc_search_action(noop_func{}) : lnav_config_listener(__FILE__), tc_search_action(noop_func{})
@ -555,8 +556,9 @@ textview_curses::textview_value_for_row(vis_line_t row, attr_line_t& value_out)
const auto& user_marks = this->tc_bookmarks[&BM_USER]; const auto& user_marks = this->tc_bookmarks[&BM_USER];
const auto& user_expr_marks = this->tc_bookmarks[&BM_USER_EXPR]; const auto& user_expr_marks = this->tc_bookmarks[&BM_USER_EXPR];
if (binary_search(user_marks.begin(), user_marks.end(), row) if (std::binary_search(user_marks.begin(), user_marks.end(), row)
|| binary_search(user_expr_marks.begin(), user_expr_marks.end(), row)) || std::binary_search(
user_expr_marks.begin(), user_expr_marks.end(), row))
{ {
sa.emplace_back(line_range{orig_line.lr_start, -1}, sa.emplace_back(line_range{orig_line.lr_start, -1},
VC_STYLE.value(text_attrs{A_REVERSE})); VC_STYLE.value(text_attrs{A_REVERSE}));

@ -576,6 +576,7 @@ public:
const static bookmark_type_t BM_USER_EXPR; const static bookmark_type_t BM_USER_EXPR;
const static bookmark_type_t BM_SEARCH; const static bookmark_type_t BM_SEARCH;
const static bookmark_type_t BM_META; const static bookmark_type_t BM_META;
const static bookmark_type_t BM_PARTITION;
textview_curses(); textview_curses();

@ -160,7 +160,7 @@ view_curses::mvwattrline(WINDOW* window,
line_range lr_bytes; line_range lr_bytes;
int char_index = 0; int char_index = 0;
for (size_t lpc = 0; lpc < line.size(); lpc++) { for (size_t lpc = 0; lpc < line.size();) {
int exp_start_index = expanded_line.size(); int exp_start_index = expanded_line.size();
auto ch = static_cast<unsigned char>(line[lpc]); auto ch = static_cast<unsigned char>(line[lpc]);
@ -178,6 +178,7 @@ view_curses::mvwattrline(WINDOW* window,
} while (expanded_line.size() % 8); } while (expanded_line.size() % 8);
utf_adjustments.emplace_back( utf_adjustments.emplace_back(
lpc, expanded_line.size() - exp_start_index - 1); lpc, expanded_line.size() - exp_start_index - 1);
lpc += 1;
break; break;
} }
@ -185,49 +186,48 @@ view_curses::mvwattrline(WINDOW* window,
expanded_line.append("\u238b"); expanded_line.append("\u238b");
utf_adjustments.emplace_back(lpc, -1); utf_adjustments.emplace_back(lpc, -1);
char_index += 1; char_index += 1;
lpc += 1;
break; break;
case '\b': case '\b':
expanded_line.append("\u232b"); expanded_line.append("\u232b");
utf_adjustments.emplace_back(lpc, -1); utf_adjustments.emplace_back(lpc, -1);
char_index += 1; char_index += 1;
lpc += 1;
break; break;
case '\r': case '\r':
case '\n': case '\n':
expanded_line.push_back(' '); expanded_line.push_back(' ');
char_index += 1; char_index += 1;
lpc += 1;
break; break;
default: { default: {
auto size_result = ww898::utf::utf8::char_size([&line, lpc]() { auto exp_read_start = expanded_line.size();
return std::make_pair(line[lpc], line.length() - lpc - 1); auto lpc_start = lpc;
}); auto read_res
= ww898::utf::utf8::read([&line, &expanded_line, &lpc]() {
auto ch = line[lpc++];
expanded_line.push_back(ch);
return ch;
});
if (size_result.isErr()) { if (read_res.isErr()) {
log_trace(
"error:%d:%d:%s", y, x + lpc, read_res.unwrapErr());
expanded_line.resize(exp_read_start);
expanded_line.push_back('?'); expanded_line.push_back('?');
char_index += 1;
lpc = lpc_start + 1;
} else { } else {
auto offset = 1 - (int) size_result.unwrap(); if (lpc > (lpc_start + 1)) {
utf_adjustments.emplace_back(lpc_start,
expanded_line.push_back(ch); 1 - (lpc - lpc_start));
if (offset) {
#if 0
if (char_index < lr_chars.lr_start) {
lr_bytes.lr_start += abs(offset);
}
if (char_index < lr_chars.lr_end) {
lr_bytes.lr_end += abs(offset);
}
#endif
utf_adjustments.emplace_back(lpc, offset);
for (; offset && (lpc + 1) < line.size();
lpc++, offset++)
{
expanded_line.push_back(line[lpc + 1]);
}
} }
auto wch = read_res.unwrap();
char_index += wcwidth(wch);
} }
char_index += 1;
break; break;
} }
} }

@ -89,8 +89,7 @@ struct utf8 final {
if (ch0 < 0x80) // 0xxx_xxxx if (ch0 < 0x80) // 0xxx_xxxx
return Ok((uint32_t) ch0); return Ok((uint32_t) ch0);
if (ch0 < 0xC0) if (ch0 < 0xC0)
throw std::runtime_error( return Err("The utf8 first char in sequence is incorrect");
"The utf8 first char in sequence is incorrect");
if (ch0 < 0xE0) // 110x_xxxx 10xx_xxxx if (ch0 < 0xE0) // 110x_xxxx 10xx_xxxx
{ {
char_type const ch1 = read_fn(); char_type const ch1 = read_fn();

@ -343,6 +343,7 @@ dist_noinst_DATA = \
logfile_nested_json.json \ logfile_nested_json.json \
logfile_nextcloud.0 \ logfile_nextcloud.0 \
logfile_openam.0 \ logfile_openam.0 \
logfile_partitions.0 \
logfile_plain.0 \ logfile_plain.0 \
logfile_pretty.0 \ logfile_pretty.0 \
logfile_procstate.0 \ logfile_procstate.0 \
@ -412,6 +413,7 @@ dist_noinst_DATA = \
formats/jsontest3/format.json \ formats/jsontest3/format.json \
formats/jsontest-subsec/format.json \ formats/jsontest-subsec/format.json \
formats/nestedjson/format.json \ formats/nestedjson/format.json \
formats/partitions/format.json \
formats/scripts/multiline-echo.lnav \ formats/scripts/multiline-echo.lnav \
formats/scripts/redirecting.lnav \ formats/scripts/redirecting.lnav \
formats/scripts/nested-redirecting.lnav \ formats/scripts/nested-redirecting.lnav \

@ -530,6 +530,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sessions.sh_430b9522ba1a37983138f3c4935cba91b781e415.out \ $(srcdir)/%reldir%/test_sessions.sh_430b9522ba1a37983138f3c4935cba91b781e415.out \
$(srcdir)/%reldir%/test_sessions.sh_4f13dd3858546b6e04a27e244159d355e368f2ae.err \ $(srcdir)/%reldir%/test_sessions.sh_4f13dd3858546b6e04a27e244159d355e368f2ae.err \
$(srcdir)/%reldir%/test_sessions.sh_4f13dd3858546b6e04a27e244159d355e368f2ae.out \ $(srcdir)/%reldir%/test_sessions.sh_4f13dd3858546b6e04a27e244159d355e368f2ae.out \
$(srcdir)/%reldir%/test_sessions.sh_639b83ce8f67975dfdc7086946ec287b43b6fa8c.err \
$(srcdir)/%reldir%/test_sessions.sh_639b83ce8f67975dfdc7086946ec287b43b6fa8c.out \
$(srcdir)/%reldir%/test_sessions.sh_68a89b56c5e7f7db620084cca1eb547cbb19a2c9.err \ $(srcdir)/%reldir%/test_sessions.sh_68a89b56c5e7f7db620084cca1eb547cbb19a2c9.err \
$(srcdir)/%reldir%/test_sessions.sh_68a89b56c5e7f7db620084cca1eb547cbb19a2c9.out \ $(srcdir)/%reldir%/test_sessions.sh_68a89b56c5e7f7db620084cca1eb547cbb19a2c9.out \
$(srcdir)/%reldir%/test_sessions.sh_6d87ff483d5785c58fb271a405ff1c35e4f83cd9.err \ $(srcdir)/%reldir%/test_sessions.sh_6d87ff483d5785c58fb271a405ff1c35e4f83cd9.err \
@ -610,6 +612,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql.sh_2f15b8a38673ac4db45dc6ed2eafe609c332575b.out \ $(srcdir)/%reldir%/test_sql.sh_2f15b8a38673ac4db45dc6ed2eafe609c332575b.out \
$(srcdir)/%reldir%/test_sql.sh_31df37f254255115611fc321b63374a2fa4a1cd5.err \ $(srcdir)/%reldir%/test_sql.sh_31df37f254255115611fc321b63374a2fa4a1cd5.err \
$(srcdir)/%reldir%/test_sql.sh_31df37f254255115611fc321b63374a2fa4a1cd5.out \ $(srcdir)/%reldir%/test_sql.sh_31df37f254255115611fc321b63374a2fa4a1cd5.out \
$(srcdir)/%reldir%/test_sql.sh_3445b783808f174b76f55dc6b998f721a1aae271.err \
$(srcdir)/%reldir%/test_sql.sh_3445b783808f174b76f55dc6b998f721a1aae271.out \
$(srcdir)/%reldir%/test_sql.sh_3d77a2092192caf98e141a6039e886ede836f044.err \ $(srcdir)/%reldir%/test_sql.sh_3d77a2092192caf98e141a6039e886ede836f044.err \
$(srcdir)/%reldir%/test_sql.sh_3d77a2092192caf98e141a6039e886ede836f044.out \ $(srcdir)/%reldir%/test_sql.sh_3d77a2092192caf98e141a6039e886ede836f044.out \
$(srcdir)/%reldir%/test_sql.sh_4090f96ea11a344c1e2939211da778992dab47d8.err \ $(srcdir)/%reldir%/test_sql.sh_4090f96ea11a344c1e2939211da778992dab47d8.err \

@ -5081,10 +5081,10 @@
"keymap_def_db_view": "Press ${ansi_bold}v${ansi_norm}/${ansi_bold}V${ansi_norm} to switch to the SQL result view", "keymap_def_db_view": "Press ${ansi_bold}v${ansi_norm}/${ansi_bold}V${ansi_norm} to switch to the SQL result view",
"keymap_def_hist_view": "Press ${ansi_bold}i${ansi_norm}/${ansi_bold}I${ansi_norm} to switch to the histogram view", "keymap_def_hist_view": "Press ${ansi_bold}i${ansi_norm}/${ansi_bold}I${ansi_norm} to switch to the histogram view",
"keymap_def_next_mark": "Press ${ansi_bold}c${ansi_norm} to copy marked lines to the clipboard; press ${ansi_bold}C${ansi_norm} to clear marked lines", "keymap_def_next_mark": "Press ${ansi_bold}c${ansi_norm} to copy marked lines to the clipboard; press ${ansi_bold}C${ansi_norm} to clear marked lines",
"keymap_def_next_section": "Press ${ansi_bold}}${ansi_norm} to move to the next section in history", "keymap_def_next_section": "Press ${ansi_bold}}${ansi_norm} to move to the next section in the view",
"keymap_def_next_user_mark": "Press ${ansi_bold}u${ansi_norm}/${ansi_bold}U${ansi_norm} to move forward/backward through user bookmarks", "keymap_def_next_user_mark": "Press ${ansi_bold}u${ansi_norm}/${ansi_bold}U${ansi_norm} to move forward/backward through user bookmarks",
"keymap_def_pop_view": "Press ${ansi_bold}q${ansi_norm} to return to the previous view", "keymap_def_pop_view": "Press ${ansi_bold}q${ansi_norm} to return to the previous view",
"keymap_def_prev_section": "Press ${ansi_bold}{${ansi_norm} to move to the previous section in history", "keymap_def_prev_section": "Press ${ansi_bold}{${ansi_norm} to move to the previous section in the view",
"keymap_def_scroll_horiz": "Press \\'${ansi_bold}>${ansi_norm}\\' or \\'${ansi_bold}<${ansi_norm}\\' to scroll horizontally to a search result", "keymap_def_scroll_horiz": "Press \\'${ansi_bold}>${ansi_norm}\\' or \\'${ansi_bold}<${ansi_norm}\\' to scroll horizontally to a search result",
"keymap_def_text_view": "Press ${ansi_bold}t${ansi_norm} to switch to the text view", "keymap_def_text_view": "Press ${ansi_bold}t${ansi_norm} to switch to the text view",
"keymap_def_time_offset": "Press ${ansi_bold}s${ansi_norm}/${ansi_bold}S${ansi_norm} to move forward/backward through slow downs", "keymap_def_time_offset": "Press ${ansi_bold}s${ansi_norm}/${ansi_bold}S${ansi_norm} to move forward/backward through slow downs",

@ -1,4 +1,4 @@
✘ error: unknown bookmark type: foobar ✘ error: unknown bookmark type: foobar
 --> command-option:2  --> command-option:2
 | :next-mark foobar   | :next-mark foobar 
 = help: available types: error, file, meta, search, user, user-expr, warning  = help: available types: error, file, meta, partition, search, user, user-expr, warning

@ -260,11 +260,10 @@ can always use  q  to pop the top view off of the stack.
and then the last message arrives five seconds and then the last message arrives five seconds
later, the last message will be highlighted as a later, the last message will be highlighted as a
slow down. slow down.
{/} Move to the previous/next location in history. {/} Move to the previous/next section in the view. In
Whenever you jump to a new location in the view, the LOG view, this moves through partitions. In
the location will be added to the history. The other views, it moves through sections of
history is not updated when using only the arrow documents.
keys.
Chronological Navigation Chronological Navigation

@ -0,0 +1,89 @@
[
{
"top_meta": {
"time": "2009-07-20 22:59:29.000",
"file": "{test_dir}/logfile_access_log.0",
"anchor": "#middle",
"breadcrumbs": [
{
"display_value": "⊑ middle",
"search_placeholder": "",
"possibilities": [
{
"display_value": "middle"
}
]
},
{
"display_value": "2009-07-20T22:59:29.000",
"search_placeholder": "(Enter an absolute or relative time)",
"possibilities": [
{
"display_value": "-1 day"
},
{
"display_value": "-1h"
},
{
"display_value": "-30m"
},
{
"display_value": "-15m"
},
{
"display_value": "-5m"
},
{
"display_value": "-1m"
},
{
"display_value": "+1m"
},
{
"display_value": "+5m"
},
{
"display_value": "+15m"
},
{
"display_value": "+30m"
},
{
"display_value": "+1h"
},
{
"display_value": "+1 day"
}
]
},
{
"display_value": "access_log",
"search_placeholder": "",
"possibilities": [
{
"display_value": "access_log"
}
]
},
{
"display_value": "logfile_access_log.0[2]",
"search_placeholder": "",
"possibilities": [
{
"display_value": "logfile_access_log.0"
}
]
},
{
"display_value": "192.168.202.254",
"search_placeholder": "",
"possibilities": [
{
"display_value": "192.168.202.254"
}
]
}
]
}
}
]

@ -0,0 +1,83 @@
log_line,log_part,log_body
0,<NULL>,restart.
1,<NULL>,Invalid query packet.
2,<NULL>,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x654a04aa)
3,<NULL>,DHCPNAK from 10.1.10.1 (xid=0x654a04aa)
4,<NULL>,/sbin/dhclient-script : updated /etc/resolv.conf
5,<NULL>,Withdrawing address record for 10.1.10.49 on eth0.
6,<NULL>,Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.49.
7,<NULL>,iface.c: interface_mdns_mcast_join() called but no local address available.
8,<NULL>,Interface eth0.IPv4 no longer relevant for mDNS.
9,<NULL>,DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 5 (xid=0x4e17f141)
10,<NULL>,DHCPOFFER from 10.1.10.1
11,<NULL>,DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x4e17f141)
12,<NULL>,DHCPACK from 10.1.10.1 (xid=0x4e17f141)
13,<NULL>,New relevant interface eth0.IPv4 for mDNS.
14,<NULL>,Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
15,<NULL>,Registering new address record for 10.1.10.103 on eth0.
16,<NULL>,Withdrawing address record for 10.1.10.103 on eth0.
17,<NULL>,Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
18,<NULL>,iface.c: interface_mdns_mcast_join() called but no local address available.
19,<NULL>,Interface eth0.IPv4 no longer relevant for mDNS.
20,<NULL>,New relevant interface eth0.IPv4 for mDNS.
21,<NULL>,Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
22,<NULL>,Registering new address record for 10.1.10.103 on eth0.
23,<NULL>,/sbin/dhclient-script : updated /etc/resolv.conf
24,10.1.10.103,bound to 10.1.10.103 -- renewal in 54694 seconds.
25,10.1.10.103,Invalid query packet.
26,10.1.10.103,Invalid query packet.
27,10.1.10.103,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
28,10.1.10.103,DHCPACK from 10.1.10.1 (xid=0x4e17f141)
29,10.1.10.103,bound to 10.1.10.103 -- renewal in 8787 seconds.
30,10.1.10.103,Invalid query packet.
31,10.1.10.103,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
32,10.1.10.103,DHCPACK from 10.1.10.1 (xid=0x4e17f141)
33,10.1.10.103,bound to 10.1.10.103 -- renewal in 9938 seconds.
34,10.1.10.103,Invalid query packet.
35,10.1.10.103,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
36,10.1.10.103,DHCPACK from 10.1.10.1 (xid=0x4e17f141)
37,10.1.10.103,bound to 10.1.10.103 -- renewal in 2656 seconds.
38,10.1.10.103,Invalid query packet.
39,10.1.10.103,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
40,10.1.10.103,DHCPACK from 10.1.10.1 (xid=0x4e17f141)
41,10.1.10.103,bound to 10.1.10.103 -- renewal in 15112 seconds.
42,10.1.10.103,Invalid query packet.
43,10.1.10.103,Invalid query packet.
44,10.1.10.103,Invalid query packet.
45,10.1.10.103,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
46,10.1.10.103,DHCPNAK from 10.1.10.1 (xid=0x4e17f141)
47,10.1.10.103,/sbin/dhclient-script : updated /etc/resolv.conf
48,10.1.10.103,Withdrawing address record for 10.1.10.103 on eth0.
49,10.1.10.103,Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
50,10.1.10.103,iface.c: interface_mdns_mcast_join() called but no local address available.
51,10.1.10.103,Interface eth0.IPv4 no longer relevant for mDNS.
52,10.1.10.103,DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 5 (xid=0xd16b79d)
53,10.1.10.103,DHCPOFFER from 10.1.10.1
54,10.1.10.103,DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0xd16b79d)
55,10.1.10.103,DHCPACK from 10.1.10.1 (xid=0xd16b79d)
56,10.1.10.103,New relevant interface eth0.IPv4 for mDNS.
57,10.1.10.103,Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.62.
58,10.1.10.103,Registering new address record for 10.1.10.62 on eth0.
59,10.1.10.103,Withdrawing address record for 10.1.10.62 on eth0.
60,10.1.10.103,Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.62.
61,10.1.10.103,iface.c: interface_mdns_mcast_join() called but no local address available.
62,10.1.10.103,Interface eth0.IPv4 no longer relevant for mDNS.
63,10.1.10.103,New relevant interface eth0.IPv4 for mDNS.
64,10.1.10.103,Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.62.
65,10.1.10.103,Registering new address record for 10.1.10.62 on eth0.
66,10.1.10.103,/sbin/dhclient-script : updated /etc/resolv.conf
67,10.1.10.62,bound to 10.1.10.62 -- renewal in 31782 seconds.
68,10.1.10.62,Invalid query packet.
69,10.1.10.62,Invalid query packet.
70,10.1.10.62,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0xd16b79d)
71,10.1.10.62,DHCPACK from 10.1.10.1 (xid=0xd16b79d)
72,10.1.10.62,bound to 10.1.10.62 -- renewal in 19742 seconds.
73,10.1.10.62,Invalid query packet.
74,10.1.10.62,Invalid query packet.
75,10.1.10.62,DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0xd16b79d)
76,10.1.10.62,DHCPACK from 10.1.10.1 (xid=0xd16b79d)
77,10.1.10.62,bound to 10.1.10.62 -- renewal in 55327 seconds.
78,10.1.10.62,Invalid query packet.
79,10.1.10.62,Invalid response packet from host 10.1.10.10.
80,10.1.10.62,Invalid response packet from host fe80::22c9:d0ff:fe15:1b7c.
81,10.1.10.62,Invalid query packet.

@ -0,0 +1,11 @@
{
"$schema": "https://lnav.org/schemas/format-v1.schema.json",
"syslog_log": {
"partitions": {
"dhclient-binding": {
"description": "Set partition name to current IP",
"pattern": " bound to ([^ ]+) --"
}
}
}
}

@ -0,0 +1,82 @@
Apr 28 04:02:03 tstack-centos5 syslogd 1.4.1: restart.
Apr 28 04:04:01 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 28 06:53:54 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x654a04aa)
Apr 28 06:53:54 tstack-centos5 dhclient: DHCPNAK from 10.1.10.1 (xid=0x654a04aa)
Apr 28 06:53:54 tstack-centos5 NET[31050]: /sbin/dhclient-script : updated /etc/resolv.conf
Apr 28 06:53:54 tstack-centos5 avahi-daemon[2467]: Withdrawing address record for 10.1.10.49 on eth0.
Apr 28 06:53:54 tstack-centos5 avahi-daemon[2467]: Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.49.
Apr 28 06:53:54 tstack-centos5 avahi-daemon[2467]: iface.c: interface_mdns_mcast_join() called but no local address available.
Apr 28 06:53:54 tstack-centos5 avahi-daemon[2467]: Interface eth0.IPv4 no longer relevant for mDNS.
Apr 28 06:53:54 tstack-centos5 dhclient: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 5 (xid=0x4e17f141)
Apr 28 06:53:55 tstack-centos5 dhclient: DHCPOFFER from 10.1.10.1
Apr 28 06:53:55 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x4e17f141)
Apr 28 06:53:55 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0x4e17f141)
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: New relevant interface eth0.IPv4 for mDNS.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: Registering new address record for 10.1.10.103 on eth0.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: Withdrawing address record for 10.1.10.103 on eth0.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: iface.c: interface_mdns_mcast_join() called but no local address available.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: Interface eth0.IPv4 no longer relevant for mDNS.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: New relevant interface eth0.IPv4 for mDNS.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
Apr 28 06:53:55 tstack-centos5 avahi-daemon[2467]: Registering new address record for 10.1.10.103 on eth0.
Apr 28 06:53:55 tstack-centos5 NET[31132]: /sbin/dhclient-script : updated /etc/resolv.conf
Apr 28 06:53:55 tstack-centos5 dhclient: bound to 10.1.10.103 -- renewal in 54694 seconds.
Apr 28 07:03:50 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 28 17:01:19 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 28 22:05:28 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
Apr 28 22:05:29 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0x4e17f141)
Apr 28 22:05:29 tstack-centos5 dhclient: bound to 10.1.10.103 -- renewal in 8787 seconds.
Apr 28 22:10:01 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 00:31:55 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
Apr 29 00:31:56 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0x4e17f141)
Apr 29 00:31:56 tstack-centos5 dhclient: bound to 10.1.10.103 -- renewal in 9938 seconds.
Apr 29 00:39:19 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 03:17:34 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
Apr 29 03:17:34 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0x4e17f141)
Apr 29 03:17:34 tstack-centos5 dhclient: bound to 10.1.10.103 -- renewal in 2656 seconds.
Apr 29 03:18:07 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 04:01:50 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
Apr 29 04:01:50 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0x4e17f141)
Apr 29 04:01:50 tstack-centos5 dhclient: bound to 10.1.10.103 -- renewal in 15112 seconds.
Apr 29 04:10:03 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 05:55:18 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 06:39:04 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 08:13:41 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0x4e17f141)
Apr 29 08:13:42 tstack-centos5 dhclient: DHCPNAK from 10.1.10.1 (xid=0x4e17f141)
Apr 29 08:13:42 tstack-centos5 NET[13600]: /sbin/dhclient-script : updated /etc/resolv.conf
Apr 29 08:13:42 tstack-centos5 avahi-daemon[2467]: Withdrawing address record for 10.1.10.103 on eth0.
Apr 29 08:13:42 tstack-centos5 avahi-daemon[2467]: Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.103.
Apr 29 08:13:42 tstack-centos5 avahi-daemon[2467]: iface.c: interface_mdns_mcast_join() called but no local address available.
Apr 29 08:13:42 tstack-centos5 avahi-daemon[2467]: Interface eth0.IPv4 no longer relevant for mDNS.
Apr 29 08:13:42 tstack-centos5 dhclient: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 5 (xid=0xd16b79d)
Apr 29 08:13:43 tstack-centos5 dhclient: DHCPOFFER from 10.1.10.1
Apr 29 08:13:43 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0xd16b79d)
Apr 29 08:13:43 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0xd16b79d)
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: New relevant interface eth0.IPv4 for mDNS.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.62.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: Registering new address record for 10.1.10.62 on eth0.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: Withdrawing address record for 10.1.10.62 on eth0.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: Leaving mDNS multicast group on interface eth0.IPv4 with address 10.1.10.62.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: iface.c: interface_mdns_mcast_join() called but no local address available.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: Interface eth0.IPv4 no longer relevant for mDNS.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: New relevant interface eth0.IPv4 for mDNS.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: Joining mDNS multicast group on interface eth0.IPv4 with address 10.1.10.62.
Apr 29 08:13:43 tstack-centos5 avahi-daemon[2467]: Registering new address record for 10.1.10.62 on eth0.
Apr 29 08:13:43 tstack-centos5 NET[13682]: /sbin/dhclient-script : updated /etc/resolv.conf
Apr 29 08:13:43 tstack-centos5 dhclient: bound to 10.1.10.62 -- renewal in 31782 seconds.
Apr 29 08:15:06 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 17:03:19 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 17:03:25 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0xd16b79d)
Apr 29 17:03:25 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0xd16b79d)
Apr 29 17:03:25 tstack-centos5 dhclient: bound to 10.1.10.62 -- renewal in 19742 seconds.
Apr 29 17:03:51 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 17:20:00 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 22:32:26 tstack-centos5 dhclient: DHCPREQUEST on eth0 to 10.1.10.1 port 67 (xid=0xd16b79d)
Apr 29 22:32:27 tstack-centos5 dhclient: DHCPACK from 10.1.10.1 (xid=0xd16b79d)
Apr 29 22:32:27 tstack-centos5 dhclient: bound to 10.1.10.62 -- renewal in 55327 seconds.
Apr 29 22:45:57 tstack-centos5 avahi-daemon[2467]: Invalid query packet.
Apr 29 23:02:45 tstack-centos5 avahi-daemon[2467]: Invalid response packet from host 10.1.10.10.
Apr 29 23:02:45 tstack-centos5 avahi-daemon[2467]: Invalid response packet from host fe80::22c9:d0ff:fe15:1b7c.
Apr 29 23:02:46 tstack-centos5 avahi-daemon[2467]: Invalid query packet.

@ -78,6 +78,14 @@ run_cap_test ${lnav_test} -n \
-c ':write-csv-to -' \ -c ':write-csv-to -' \
${test_dir}/logfile_access_log.0 ${test_dir}/logfile_access_log.0
# partition name was not saved in session and doesn't not show up in crumbs
run_cap_test ${lnav_test} -n \
-c ":load-session" \
-c ':goto 2' \
-c ";SELECT top_meta FROM lnav_views WHERE name = 'log'" \
-c ':write-json-to -' \
${test_dir}/logfile_access_log.0
# adjust time is not working # adjust time is not working
run_cap_test ${lnav_test} -nq \ run_cap_test ${lnav_test} -nq \
-c ":adjust-log-time 2010-01-01T00:00:00" \ -c ":adjust-log-time 2010-01-01T00:00:00" \

@ -822,6 +822,12 @@ log_line,log_part
2,<NULL> 2,<NULL>
EOF EOF
# test the partitions defined in the format
run_cap_test ${lnav_test} -n \
-I ${test_dir} \
-c ";SELECT log_line, log_part, log_body FROM syslog_log" \
-c ":write-csv-to -" \
${test_dir}/logfile_partitions.0
run_test ${lnav_test} -n \ run_test ${lnav_test} -n \
-c ";SELECT * FROM openam_log" \ -c ";SELECT * FROM openam_log" \

Loading…
Cancel
Save