Skip to content

Commit edc89c8

Browse files
committed
[formats] allow highlights to be limited to a field
Related to #1620
1 parent 60d155a commit edc89c8

42 files changed

Lines changed: 884 additions & 273 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ Features:
2929
has been translated to Python3. If the remote host
3030
does not have Python, lnav will fall back to the APE
3131
binary.
32+
* Highlights can now be applied to a particular field
33+
instead of the whole line. For log formats, a
34+
`value` entry can now have a `highlights` object
35+
that contains definitions for the pattern to match
36+
and the style to apply. For interactive use, the
37+
`:highlight-field` command was added.
3238
* The "Files" panel now shows a progress bar for each
3339
file as it is being indexed and finishes with a
3440
check-mark if indexing was successful, a warning

docs/schemas/format-v1.schema.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,52 @@
471471
"title": "/<format_name>/value/<value_name>/description",
472472
"description": "A description of the field",
473473
"type": "string"
474+
},
475+
"highlights": {
476+
"description": "The set of highlight definitions",
477+
"title": "/<format_name>/value/<value_name>/highlights",
478+
"type": "object",
479+
"patternProperties": {
480+
"^(.+)$": {
481+
"description": "The definition of a highlight",
482+
"title": "/<format_name>/value/<value_name>/highlights/<highlight_name>",
483+
"type": "object",
484+
"properties": {
485+
"pattern": {
486+
"title": "/<format_name>/value/<value_name>/highlights/<highlight_name>/pattern",
487+
"description": "A regular expression to highlight in logs of this format.",
488+
"type": "string"
489+
},
490+
"color": {
491+
"title": "/<format_name>/value/<value_name>/highlights/<highlight_name>/color",
492+
"description": "The color to use when highlighting this pattern.",
493+
"type": "string"
494+
},
495+
"background-color": {
496+
"title": "/<format_name>/value/<value_name>/highlights/<highlight_name>/background-color",
497+
"description": "The background color to use when highlighting this pattern.",
498+
"type": "string"
499+
},
500+
"underline": {
501+
"title": "/<format_name>/value/<value_name>/highlights/<highlight_name>/underline",
502+
"description": "Highlight this pattern with an underline.",
503+
"type": "boolean"
504+
},
505+
"blink": {
506+
"title": "/<format_name>/value/<value_name>/highlights/<highlight_name>/blink",
507+
"description": "Highlight this pattern by blinking.",
508+
"type": "boolean"
509+
},
510+
"nestable": {
511+
"title": "/<format_name>/value/<value_name>/highlights/<highlight_name>/nestable",
512+
"description": "This highlight can be nested in another highlight.",
513+
"type": "boolean"
514+
}
515+
},
516+
"additionalProperties": false
517+
}
518+
},
519+
"additionalProperties": false
474520
}
475521
},
476522
"additionalProperties": false

docs/source/cookbook.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ This chapter contains recipes for common tasks that can be done in **lnav**.
77
These recipes can be used as a starting point for your own needs after some
88
adaptation.
99

10+
Custom Web Access Log Highlights
11+
--------------------------------
12+
13+
To highlight log message fields with custom colors based on their values, you
14+
can install a file that patches the format with the desired highlights.
15+
The following patch updates the :code:`access_log` format. A
16+
:code:`highlights` entry is added to the :code:`value/sc_status` object that
17+
applies a color for codes of interest.
18+
19+
.. literalinclude:: ../../example-scripts/access_log_highlights.json
20+
:language: json
21+
:caption: access_log_highlights.json
22+
:linenos:
1023

1124
Annotating Logs
1225
---------------

src/cmd.parser.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ parse_for(mode_t mode,
342342
case help_parameter_format_t::HPF_LOADED_FILE:
343343
case help_parameter_format_t::HPF_FORMAT_FIELD:
344344
case help_parameter_format_t::HPF_NUMERIC_FIELD:
345+
case help_parameter_format_t::HPF_HIGHLIGHTED_FIELD:
345346
case help_parameter_format_t::HPF_TIMEZONE:
346347
case help_parameter_format_t::HPF_FILE_WITH_ZONE:
347348
case help_parameter_format_t::HPF_VISIBLE_FILES:

src/command_executor.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,12 @@ execute_sql(exec_context& ec, const std::string& sql, std::string& alt_msg)
384384

385385
require(!ec.ec_source.empty());
386386
const auto& source = ec.ec_source.back();
387-
sql_progress_guard progress_guard(sql_progress,
388-
sql_progress_finished,
389-
source.s_location,
390-
source.s_content);
387+
sql_progress_guard progress_guard(
388+
sql_progress,
389+
sql_progress_finished,
390+
source.s_location,
391+
source.s_content,
392+
!ec.get_provenance<exec_context::format_rewrite>().has_value());
391393
gettimeofday(&start_tv, nullptr);
392394

393395
const auto* curr_stmt = stmt_str.c_str();

src/command_executor.hh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ struct exec_context {
145145

146146
struct mouse_input {};
147147
struct keyboard_input {};
148+
struct format_rewrite {};
148149
struct user {};
149150
struct file_open {
150151
std::string fo_name;
@@ -153,8 +154,12 @@ struct exec_context {
153154
std::string ea_src;
154155
};
155156

156-
using provenance_t = mapbox::util::
157-
variant<user, keyboard_input, mouse_input, file_open, external_access>;
157+
using provenance_t = mapbox::util::variant<user,
158+
format_rewrite,
159+
keyboard_input,
160+
mouse_input,
161+
file_open,
162+
external_access>;
158163

159164
struct provenance_guard {
160165
explicit provenance_guard(exec_context* context, provenance_t prov)

src/help_text.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ enum class help_parameter_format_t {
8686
HPF_ENABLED_FILTERS,
8787
HPF_DISABLED_FILTERS,
8888
HPF_HIGHLIGHTS,
89+
HPF_HIGHLIGHTED_FIELD,
8990
HPF_TIMEZONE,
9091
HPF_FILE_WITH_ZONE,
9192
HPF_CONFIG_PATH,

src/highlighter.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ highlighter::annotate_capture(attr_line_t& al, const line_range& lr) const
6666
}
6767
}
6868

69-
void
69+
bool
7070
highlighter::annotate(attr_line_t& al, const line_range& lr) const
7171
{
72+
auto retval = false;
73+
7274
if (!this->h_regex) {
73-
return;
75+
return retval;
7476
}
7577

7678
auto& vc = view_colors::singleton();
@@ -82,11 +84,12 @@ highlighter::annotate(attr_line_t& al, const line_range& lr) const
8284
std::min(size_t{8192}, std::min((size_t) lr.lr_end, str.size())));
8385

8486
if (!sf.is_valid()) {
85-
return;
87+
return retval;
8688
}
8789

8890
this->h_regex->capture_from(sf).for_each<PCRE2_NO_UTF_CHECK>(
8991
[&](lnav::pcre2pp::match_data& md) {
92+
retval = true;
9093
if (md.get_count() == 1) {
9194
this->annotate_capture(al, to_line_range(md[0].value()));
9295
} else {
@@ -114,4 +117,6 @@ highlighter::annotate(attr_line_t& al, const line_range& lr) const
114117
}
115118
}
116119
});
120+
121+
return retval;
117122
}

src/highlighter.hh

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@
3434

3535
#include <memory>
3636
#include <string>
37+
#include <utility>
3738

3839
#include "base/attr_line.hh"
3940
#include "base/intern_string.hh"
41+
#include "base/line_range.hh"
4042
#include "base/map_util.hh"
4143
#include "base/string_attr_type.hh"
4244
#include "base/text_format_enum.hh"
4345
#include "pcrepp/pcre2pp_fwd.hh"
44-
#include "styling.hh"
4546

4647
struct highlighter {
4748
highlighter() = default;
@@ -53,6 +54,12 @@ struct highlighter {
5354

5455
virtual ~highlighter() = default;
5556

57+
highlighter& with_field(intern_string_t field)
58+
{
59+
this->h_field = field;
60+
return *this;
61+
}
62+
5663
highlighter& with_role(role_t role)
5764
{
5865
this->h_role = role;
@@ -74,13 +81,6 @@ struct highlighter {
7481
return *this;
7582
}
7683

77-
highlighter& with_format_name(intern_string_t name)
78-
{
79-
this->h_format_name = name;
80-
81-
return *this;
82-
}
83-
8484
highlighter& with_name(std::string name)
8585
{
8686
this->h_name = std::move(name);
@@ -93,9 +93,15 @@ struct highlighter {
9393
return *this;
9494
}
9595

96+
highlighter& with_preview(bool val)
97+
{
98+
this->h_preview = val;
99+
return *this;
100+
}
101+
96102
text_attrs get_attrs() const { return this->h_attrs; }
97103

98-
void annotate(attr_line_t& al, const line_range& lr) const;
104+
bool annotate(attr_line_t& al, const line_range& lr) const;
99105

100106
void annotate_capture(attr_line_t& al, const line_range& lr) const;
101107

@@ -106,12 +112,13 @@ struct highlighter {
106112
}
107113

108114
std::string h_name;
115+
intern_string_t h_field;
109116
role_t h_role{role_t::VCR_NONE};
110117
std::shared_ptr<lnav::pcre2pp::code> h_regex;
111118
text_attrs h_attrs;
112119
lnav::set::small<text_format_t> h_text_formats;
113-
intern_string_t h_format_name;
114120
bool h_nestable{true};
121+
bool h_preview{false};
115122
};
116123

117124
#endif

src/internals/cmd-ref.rst

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,29 @@
233233
----
234234

235235

236+
.. _clear_highlight_field:
237+
238+
:clear-highlight-field *field*
239+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
240+
241+
Remove a field highlight
242+
243+
**Parameters**
244+
* **field\*** --- The name of highlighted field
245+
246+
**Examples**
247+
To clear the highlights for the 'sc_status' field:
248+
249+
.. code-block:: lnav
250+
251+
:clear-highlight-field sc_status
252+
253+
**See Also**
254+
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`highlight_field`, :ref:`set_text_view_mode`
255+
256+
----
257+
258+
236259
.. _clear_mark_expr:
237260

238261
:clear-mark-expr
@@ -523,7 +546,7 @@
523546
Disable word-wrapping for the current view
524547

525548
**See Also**
526-
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`highlight`, :ref:`set_text_view_mode`
549+
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`set_text_view_mode`
527550

528551
----
529552

@@ -583,7 +606,7 @@
583606
Enable word-wrapping for the current view
584607

585608
**See Also**
586-
:ref:`disable_word_wrap`, :ref:`hide_fields`, :ref:`highlight`, :ref:`set_text_view_mode`
609+
:ref:`disable_word_wrap`, :ref:`hide_fields`, :ref:`set_text_view_mode`
587610

588611
----
589612

@@ -811,7 +834,7 @@
811834
:hide-fields syslog_log.log_procname
812835
813836
**See Also**
814-
:ref:`enable_word_wrap`, :ref:`highlight`, :ref:`set_text_view_mode`, :ref:`show_fields`
837+
:ref:`enable_word_wrap`, :ref:`set_text_view_mode`, :ref:`show_fields`
815838

816839
----
817840

@@ -924,6 +947,36 @@
924947
----
925948

926949

950+
.. _highlight_field:
951+
952+
:highlight-field *\[--color\]* *\[--bold\]* *\[--underline\]* *\[--italic\]* *\[--strike\]* *\[--blink\]* *field* *pattern*
953+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
954+
955+
Highlight a field that matches the given pattern
956+
957+
**Parameters**
958+
* **--color** --- The foreground color to apply
959+
* **--bold** --- Make the text bold
960+
* **--underline** --- Underline the text
961+
* **--italic** --- Italicize the text
962+
* **--strike** --- Strikethrough the text
963+
* **--blink** --- Make the text blink
964+
* **field\*** --- The name of the field to highlight
965+
* **pattern\*** --- The regular expression to match
966+
967+
**Examples**
968+
To color status values that start with '2' green:
969+
970+
.. code-block:: lnav
971+
972+
:highlight-field --color=green sc_status ^2.*
973+
974+
**See Also**
975+
:ref:`clear_highlight_field`, :ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`set_text_view_mode`
976+
977+
----
978+
979+
927980
.. _load_session:
928981

929982
:load-session
@@ -1401,7 +1454,7 @@
14011454
* **mode\*** --- The display mode
14021455

14031456
**See Also**
1404-
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`highlight`
1457+
:ref:`enable_word_wrap`, :ref:`hide_fields`
14051458

14061459
----
14071460

@@ -1441,7 +1494,7 @@
14411494
:show-fields log_procname
14421495
14431496
**See Also**
1444-
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`highlight`, :ref:`set_text_view_mode`
1497+
:ref:`enable_word_wrap`, :ref:`hide_fields`, :ref:`set_text_view_mode`
14451498

14461499
----
14471500

0 commit comments

Comments
 (0)