Skip to content

Commit 60b7b14

Browse files
committed
[formats] add a script to highlight postgres statement errors
1 parent b848e3f commit 60b7b14

24 files changed

Lines changed: 304 additions & 88 deletions

NEWS.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ Features:
88
* Removed dependency on ncurses during the build. The terminfo
99
files are still used during runtime, but fallback terminfo
1010
files for common terminals are included in the binary.
11-
* Added the postgres_log format.
11+
* Added the postgres_log format. In addition, you can use
12+
`:annotate` on a statement error line (e.g. syntax error
13+
at or near "null" at character 522) to attach an annotation
14+
with the statement and a pointer to the location of the error.
15+
* Annotation handlers can now be lnav scripts if the "handler"
16+
field starts with a pipe ("|").
1217

1318
Interface changes:
1419
* If all the log messages in the LOG view are hidden, a notice

src/all_logs_vtab.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,19 @@ all_logs_vtab::get_columns(std::vector<vtab_column>& cols) const
7575
void
7676
all_logs_vtab::extract(logfile* lf,
7777
uint64_t line_number,
78+
string_attrs_t& sa,
7879
logline_value_vector& values)
7980
{
8081
auto& line = values.lvv_sbr;
8182
auto* format = lf->get_format_ptr();
8283

8384
logline_value_vector sub_values;
8485

85-
this->vi_attrs.clear();
86+
sa.clear();
8687
sub_values.lvv_sbr = line.clone();
87-
format->annotate(lf, line_number, this->vi_attrs, sub_values, false);
88+
format->annotate(lf, line_number, sa, sub_values, false);
8889

89-
auto body = find_string_attr_range(this->vi_attrs, &SA_BODY);
90+
auto body = find_string_attr_range(sa, &SA_BODY);
9091
if (body.lr_start == -1) {
9192
body.lr_start = 0;
9293
body.lr_end = line.length();

src/all_logs_vtab.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public:
5050

5151
void extract(logfile* lf,
5252
uint64_t line_number,
53+
string_attrs_t& sa,
5354
logline_value_vector& values) override;
5455

5556
bool next(log_cursor& lc, logfile_sub_source& lss) override;

src/log.annotate.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,36 @@ apply(vis_line_t vl, std::vector<intern_string_t> annos)
228228
continue;
229229
}
230230

231+
if (startswith(iter->second.a_handler.pp_value, "|")) {
232+
intern_string_t handler_path = intern_string::lookup(
233+
fmt::format(FMT_STRING("/log/annotations/{}/handler"), anno));
234+
logline_value_vector values;
235+
exec_context ec(&values, internal_sql_callback, pipe_callback);
236+
db_label_source anno_label_source;
237+
238+
ec.with_perms(exec_context::perm_t::READ_ONLY);
239+
ec.ec_local_vars.push(std::map<std::string, scoped_value_t>());
240+
ec.ec_top_line = vl;
241+
auto src_guard = ec.enter_db_source(&anno_label_source);
242+
auto src_loc = source_location{handler_path};
243+
244+
auto exec_res
245+
= ec.execute(src_loc, iter->second.a_handler.pp_value);
246+
if (exec_res.isErr()) {
247+
auto err_msg = exec_res.unwrapErr();
248+
249+
la.la_pairs[anno.to_string()]
250+
= err_msg.to_attr_line().al_string;
251+
} else {
252+
auto content = exec_res.unwrap();
253+
la.la_pairs[anno.to_string()] = content;
254+
}
255+
256+
lnav_data.ld_views[LNV_LOG].reload_data();
257+
lnav_data.ld_views[LNV_LOG].set_needs_update();
258+
continue;
259+
}
260+
231261
la.la_pairs[anno.to_string()] = "Loading...";
232262
auto child_fds_res = auto_pipe::for_child_fds(
233263
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);

src/log_data_table.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,13 @@ log_data_table::next(log_cursor& lc, logfile_sub_source& lss)
169169
void
170170
log_data_table::extract(logfile* lf,
171171
uint64_t line_number,
172+
string_attrs_t& sa,
172173
logline_value_vector& values)
173174
{
174175
auto& line = values.lvv_sbr;
175176
auto meta_iter = this->ldt_value_metas.begin();
176177

177-
this->ldt_format_impl->extract(lf, line_number, values);
178+
this->ldt_format_impl->extract(lf, line_number, sa, values);
178179
for (const auto& ldt_pair : this->ldt_pairs) {
179180
const auto& pvalue = ldt_pair.get_pair_value();
180181
auto lr = line_range{

src/log_data_table.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public:
6363

6464
void extract(logfile* lf,
6565
uint64_t line_number,
66+
string_attrs_t& sa,
6667
logline_value_vector& values) override;
6768

6869
private:

src/log_format.cc

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4304,33 +4304,33 @@ class external_log_table : public log_format_vtab_impl {
43044304
this->elt_module_format.mf_mod_format = nullptr;
43054305
if (lf->get_format_name() == this->lfvi_format.get_name()) {
43064306
return true;
4307-
} else if (mod_id && mod_id == this->lfvi_format.lf_mod_index) {
4307+
}
4308+
if (mod_id && mod_id == this->lfvi_format.lf_mod_index) {
43084309
auto format = lf->get_format();
43094310

43104311
return lf->read_line(lf_iter)
43114312
.map([this, format, cl, lf](auto line) {
4313+
string_attrs_t sa;
43124314
logline_value_vector values;
43134315
line_range mod_name_range;
43144316
intern_string_t mod_name;
43154317

4316-
this->vi_attrs.clear();
43174318
values.lvv_sbr = line.clone();
4318-
format->annotate(lf, cl, this->vi_attrs, values, false);
4319+
format->annotate(lf, cl, sa, values, false);
43194320
this->elt_container_body
4320-
= find_string_attr_range(this->vi_attrs, &SA_BODY);
4321+
= find_string_attr_range(sa, &SA_BODY);
43214322
if (!this->elt_container_body.is_valid()) {
43224323
return false;
43234324
}
43244325
this->elt_container_body.ltrim(line.get_data());
43254326
mod_name_range
4326-
= find_string_attr_range(this->vi_attrs, &L_MODULE);
4327+
= find_string_attr_range(sa, &L_MODULE);
43274328
if (!mod_name_range.is_valid()) {
43284329
return false;
43294330
}
43304331
mod_name = intern_string::lookup(
43314332
&line.get_data()[mod_name_range.lr_start],
43324333
mod_name_range.length());
4333-
this->vi_attrs.clear();
43344334
this->elt_module_format
43354335
= external_log_format::MODULE_FORMATS[mod_name];
43364336
if (!this->elt_module_format.mf_mod_format) {
@@ -4347,6 +4347,7 @@ class external_log_table : public log_format_vtab_impl {
43474347

43484348
void extract(logfile* lf,
43494349
uint64_t line_number,
4350+
string_attrs_t& sa,
43504351
logline_value_vector& values) override
43514352
{
43524353
auto& line = values.lvv_sbr;
@@ -4358,17 +4359,17 @@ class external_log_table : public log_format_vtab_impl {
43584359
body_ref.subset(line,
43594360
this->elt_container_body.lr_start,
43604361
this->elt_container_body.length());
4361-
this->vi_attrs.clear();
4362+
sa.clear();
43624363
auto narrow_res
43634364
= values.lvv_sbr.narrow(this->elt_container_body.lr_start,
43644365
this->elt_container_body.length());
43654366
values.lvv_values.clear();
43664367
this->elt_module_format.mf_mod_format->annotate(
4367-
lf, line_number, this->vi_attrs, values, false);
4368+
lf, line_number, sa, values, false);
43684369
values.lvv_sbr.widen(narrow_res);
43694370
} else {
4370-
this->vi_attrs.clear();
4371-
format->annotate(lf, line_number, this->vi_attrs, values, false);
4371+
sa.clear();
4372+
format->annotate(lf, line_number, sa, values, false);
43724373
}
43734374
}
43744375

src/log_search_table.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ log_search_table::get_foreign_keys(
138138
bool
139139
log_search_table::next(log_cursor& lc, logfile_sub_source& lss)
140140
{
141-
this->vi_attrs.clear();
141+
this->lst_attrs_cache.clear();
142142
this->lst_line_values_cache.lvv_values.clear();
143143

144144
if (this->lst_match_index >= 0) {
@@ -193,7 +193,7 @@ log_search_table::next(log_cursor& lc, logfile_sub_source& lss)
193193
lf->read_full_message(lf_iter, sbr);
194194
sbr.erase_ansi();
195195
lf->get_format()->annotate(
196-
lf, cl, this->vi_attrs, this->lst_line_values_cache, false);
196+
lf, cl, this->lst_attrs_cache, this->lst_line_values_cache, false);
197197
this->lst_content
198198
= this->lst_line_values_cache.lvv_sbr.to_string_fragment();
199199

@@ -217,6 +217,7 @@ log_search_table::next(log_cursor& lc, logfile_sub_source& lss)
217217
void
218218
log_search_table::extract(logfile* lf,
219219
uint64_t line_number,
220+
string_attrs_t& sa,
220221
logline_value_vector& values)
221222
{
222223
auto& line = values.lvv_sbr;
@@ -242,6 +243,7 @@ log_search_table::extract(logfile* lf,
242243
values.lvv_values.emplace_back(this->lst_column_metas[curr_col]);
243244
}
244245
}
246+
sa = this->lst_attrs_cache;
245247
}
246248

247249
void

src/log_search_table.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public:
6464

6565
void extract(logfile* lf,
6666
uint64_t line_number,
67+
string_attrs_t& sa,
6768
logline_value_vector& values) override;
6869

6970
std::shared_ptr<lnav::pcre2pp::code> lst_regex;
@@ -77,6 +78,7 @@ public:
7778
mutable std::vector<logline_value_meta> lst_column_metas;
7879
int64_t lst_match_index{-1};
7980
mutable std::vector<vtab_column> lst_cols;
81+
string_attrs_t lst_attrs_cache;
8082
logline_value_vector lst_line_values_cache;
8183
auto_buffer lst_mismatch_bitmap{auto_buffer::alloc_bitmap(0)};
8284
uint32_t lst_index_generation{0};

src/log_vtab_impl.cc

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,12 @@ log_vtab_impl::get_foreign_keys(
243243
void
244244
log_vtab_impl::extract(logfile* lf,
245245
uint64_t line_number,
246+
string_attrs_t& sa,
246247
logline_value_vector& values)
247248
{
248-
auto format = lf->get_format_ptr();
249+
const auto* format = lf->get_format_ptr();
249250

250-
this->vi_attrs.clear();
251-
format->annotate(lf, line_number, this->vi_attrs, values, false);
251+
format->annotate(lf, line_number, sa, values, false);
252252
}
253253

254254
bool
@@ -353,13 +353,15 @@ struct vtab_cursor {
353353

354354
void invalidate()
355355
{
356+
this->attrs.clear();
356357
this->line_values.clear();
357358
this->log_msg_line = -1_vl;
358359
}
359360

360361
sqlite3_vtab_cursor base;
361362
struct log_cursor log_cursor;
362363
vis_line_t log_msg_line{-1_vl};
364+
string_attrs_t attrs;
363365
logline_value_vector line_values;
364366
};
365367

@@ -517,7 +519,7 @@ populate_indexed_columns(vtab_cursor* vc, log_vtab* vt)
517519

518520
vc->cache_msg(lf, ll);
519521
require(vc->line_values.lvv_sbr.get_data() != nullptr);
520-
vt->vi->extract(lf, line_number, vc->line_values);
522+
vt->vi->extract(lf, line_number, vc->attrs, vc->line_values);
521523
}
522524

523525
auto sub_col = logline_value_meta::table_column{
@@ -792,14 +794,16 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
792794
vc->cache_msg(lf, ll);
793795
require(vc->line_values.lvv_sbr.get_data()
794796
!= nullptr);
795-
vt->vi->extract(
796-
lf, line_number, vc->line_values);
797+
vt->vi->extract(lf,
798+
line_number,
799+
vc->attrs,
800+
vc->line_values);
797801
}
798802

799803
struct line_range time_range;
800804

801-
time_range = find_string_attr_range(
802-
vt->vi->vi_attrs, &L_TIMESTAMP);
805+
time_range = find_string_attr_range(vc->attrs,
806+
&L_TIMESTAMP);
803807

804808
const auto* time_src
805809
= vc->line_values.lvv_sbr.get_data()
@@ -953,7 +957,8 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
953957
vc->cache_msg(lf, ll);
954958
require(vc->line_values.lvv_sbr.get_data()
955959
!= nullptr);
956-
vt->vi->extract(lf, line_number, vc->line_values);
960+
vt->vi->extract(
961+
lf, line_number, vc->attrs, vc->line_values);
957962
}
958963

959964
if (vc->line_values.lvv_opid_value) {
@@ -969,7 +974,8 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
969974
vc->cache_msg(lf, ll);
970975
require(vc->line_values.lvv_sbr.get_data()
971976
!= nullptr);
972-
vt->vi->extract(lf, line_number, vc->line_values);
977+
vt->vi->extract(
978+
lf, line_number, vc->attrs, vc->line_values);
973979
}
974980

975981
if (vc->line_values.lvv_opid_value
@@ -1040,13 +1046,14 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
10401046
vc->cache_msg(lf, ll);
10411047
require(vc->line_values.lvv_sbr.get_data()
10421048
!= nullptr);
1043-
vt->vi->extract(lf, line_number, vc->line_values);
1049+
vt->vi->extract(
1050+
lf, line_number, vc->attrs, vc->line_values);
10441051
}
10451052

10461053
struct line_range body_range;
10471054

1048-
body_range = find_string_attr_range(vt->vi->vi_attrs,
1049-
&SA_BODY);
1055+
body_range
1056+
= find_string_attr_range(vc->attrs, &SA_BODY);
10501057
if (!body_range.is_valid()) {
10511058
sqlite3_result_null(ctx);
10521059
} else {
@@ -1113,7 +1120,8 @@ vt_column(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int col)
11131120
if (vc->line_values.lvv_values.empty()) {
11141121
vc->cache_msg(lf, ll);
11151122
require(vc->line_values.lvv_sbr.get_data() != nullptr);
1116-
vt->vi->extract(lf, line_number, vc->line_values);
1123+
vt->vi->extract(
1124+
lf, line_number, vc->attrs, vc->line_values);
11171125
}
11181126

11191127
auto sub_col = logline_value_meta::table_column{

0 commit comments

Comments
 (0)