• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tstack / lnav / 17589970077-2502

09 Sep 2025 05:00PM UTC coverage: 65.196% (-5.0%) from 70.225%
17589970077-2502

push

github

tstack
[format] add fields for source file/line

Knowing the source file/line context in a log
message can help find log messages when using
log2src.

56 of 70 new or added lines in 2 files covered. (80.0%)

13954 existing lines in 210 files now uncovered.

45516 of 69814 relevant lines covered (65.2%)

404154.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.72
/src/logfile_sub_source.hh
1
/**
2
 * Copyright (c) 2007-2012, Timothy Stack
3
 *
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * * Redistributions of source code must retain the above copyright notice, this
10
 * list of conditions and the following disclaimer.
11
 * * Redistributions in binary form must reproduce the above copyright notice,
12
 * this list of conditions and the following disclaimer in the documentation
13
 * and/or other materials provided with the distribution.
14
 * * Neither the name of Timothy Stack nor the names of its contributors
15
 * may be used to endorse or promote products derived from this software
16
 * without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * @file logfile_sub_source.hh
30
 */
31

32
#ifndef logfile_sub_source_hh
33
#define logfile_sub_source_hh
34

35
#include <array>
36
#include <utility>
37
#include <vector>
38

39
#include <limits.h>
40

41
#include "base/time_util.hh"
42
#include "big_array.hh"
43
#include "bookmarks.hh"
44
#include "document.sections.hh"
45
#include "filter_observer.hh"
46
#include "log_format.hh"
47
#include "logfile.hh"
48
#include "strong_int.hh"
49
#include "textview_curses.hh"
50

51
STRONG_INT_TYPE(uint64_t, content_line);
52

53
struct sqlite3_stmt;
54
extern "C"
55
{
56
int sqlite3_finalize(sqlite3_stmt* pStmt);
57
}
58

59
class logfile_sub_source;
60

61
class index_delegate {
62
public:
63
    virtual ~index_delegate() = default;
×
64

65
    virtual void index_start(logfile_sub_source& lss) {}
×
66

67
    virtual void index_line(logfile_sub_source& lss,
×
68
                            logfile* lf,
69
                            logfile::iterator ll)
70
    {
71
    }
72

UNCOV
73
    virtual void index_complete(logfile_sub_source& lss) {}
×
74
};
75

76
class sql_filter : public text_filter {
77
public:
78
    sql_filter(logfile_sub_source& lss,
5✔
79
               std::string stmt_str,
80
               sqlite3_stmt* stmt)
81
        : text_filter(EXCLUDE, filter_lang_t::SQL, std::move(stmt_str), 0),
5✔
82
          sf_log_source(lss)
5✔
83
    {
84
        this->sf_filter_stmt = stmt;
5✔
85
    }
5✔
86

87
    bool matches(std::optional<line_source> ls,
88
                 const shared_buffer_ref& line) override;
89

90
    std::string to_command() const override;
91

92
    auto_mem<sqlite3_stmt> sf_filter_stmt{sqlite3_finalize};
93
    logfile_sub_source& sf_log_source;
94
};
95

96
class log_location_history : public location_history {
97
public:
98
    explicit log_location_history(logfile_sub_source& lss)
1,091✔
99
        : llh_history(std::begin(this->llh_backing),
2,182✔
100
                      std::end(this->llh_backing)),
1,091✔
101
          llh_log_source(lss)
1,091✔
102
    {
103
    }
1,091✔
104

105
    ~log_location_history() override = default;
693✔
106

107
    void loc_history_append(vis_line_t top) override;
108

109
    std::optional<vis_line_t> loc_history_back(vis_line_t current_top) override;
110

111
    std::optional<vis_line_t> loc_history_forward(
112
        vis_line_t current_top) override;
113

114
private:
115
    nonstd::ring_span<content_line_t> llh_history;
116
    logfile_sub_source& llh_log_source;
117
    content_line_t llh_backing[MAX_SIZE];
118
};
119

120
class logline_window {
121
public:
122
    logline_window(logfile_sub_source& lss,
160✔
123
                   vis_line_t start_vl,
124
                   vis_line_t end_vl)
125
        : lw_source(lss), lw_start_line(start_vl), lw_end_line(end_vl)
160✔
126
    {
127
    }
160✔
128

129
    class iterator;
130

131
    class logmsg_info {
132
    public:
133
        logmsg_info(logfile_sub_source& lss, vis_line_t vl);
134

135
        vis_line_t get_vis_line() const { return this->li_line; }
643✔
136

137
        size_t get_line_count() const;
138

139
        uint32_t get_file_line_number() const { return this->li_line_number; }
121✔
140

141
        logfile* get_file_ptr() const { return this->li_file; }
9✔
142

143
        logline& get_logline() const { return *this->li_logline; }
261✔
144

145
        const string_attrs_t& get_attrs() const
146
        {
147
            this->load_msg();
148
            return this->li_string_attrs;
149
        }
150

151
        const logline_value_vector& get_values() const
261✔
152
        {
153
            this->load_msg();
261✔
154
            return this->li_line_values;
261✔
155
        }
156

157
        std::optional<bookmark_metadata*> get_metadata() const;
158

159
        Result<auto_buffer, std::string> get_line_hash() const;
160

161
        struct metadata_edit_guard {
162
            ~metadata_edit_guard();
163

164
            bookmark_metadata& operator*();
165

166
        private:
167
            friend logmsg_info;
168

169
            metadata_edit_guard(logmsg_info& li) : meg_logmsg_info(li) {}
170
            logmsg_info& meg_logmsg_info;
171
        };
172

173
        metadata_edit_guard edit_metadata()
174
        {
175
            return metadata_edit_guard(*this);
176
        }
177

178
        std::string to_string(const struct line_range& lr) const;
179

180
    private:
181
        friend iterator;
182
        friend metadata_edit_guard;
183
        friend logline_window;
184

185
        void next_msg();
186
        void prev_msg();
187
        void load_msg() const;
188
        bool is_valid() const;
189

190
        logfile_sub_source& li_source;
191
        vis_line_t li_line;
192
        uint32_t li_line_number;
193
        logfile* li_file{nullptr};
194
        logfile::iterator li_logline;
195
        mutable string_attrs_t li_string_attrs;
196
        mutable logline_value_vector li_line_values;
197
    };
198

199
    class iterator {
200
    public:
201
        iterator(logfile_sub_source& lss, vis_line_t vl) : i_info(lss, vl) {}
277✔
202

203
        iterator& operator++();
204
        iterator& operator--();
205

206
        bool operator!=(const iterator& rhs) const
318✔
207
        {
208
            return this->i_info.get_vis_line() != rhs.i_info.get_vis_line();
318✔
209
        }
210

UNCOV
211
        bool operator==(const iterator& rhs) const
×
212
        {
UNCOV
213
            return this->i_info.get_vis_line() == rhs.i_info.get_vis_line();
×
214
        }
215

216
        const logmsg_info& operator*() const { return this->i_info; }
357✔
217

218
        const logmsg_info* operator->() const { return &this->i_info; }
160✔
219

220
    private:
221
        logmsg_info i_info;
222
    };
223

224
    iterator begin();
225

226
    iterator end();
227

228
private:
229
    logfile_sub_source& lw_source;
230
    vis_line_t lw_start_line;
231
    vis_line_t lw_end_line;
232
};
233

234
/**
235
 * Delegate class that merges the contents of multiple log files into a single
236
 * source of data for a text view.
237
 */
238
class logfile_sub_source
239
    : public text_sub_source
240
    , public text_time_translator
241
    , public text_accel_source
242
    , public list_input_delegate
243
    , public text_anchors
244
    , public text_delegate
245
    , public text_detail_provider
246
    , public lnav_config_listener {
247
public:
248
    const static bookmark_type_t BM_FILES;
249

250
    virtual void text_filters_changed();
251

252
    logfile_sub_source();
253

254
    ~logfile_sub_source() = default;
693✔
255

256
    enum class line_context_t : uint8_t {
257
        filename,
258
        basename,
259
        none,
260
        time_column,
261
    };
262

263
    void increase_line_context();
264

265
    bool decrease_line_context();
266

267
    size_t get_filename_offset() const;
268

269
    line_context_t get_line_context() const { return this->lss_line_context; }
270

271
    log_level_t get_min_log_level() const { return this->lss_min_log_level; }
5✔
272

273
    void set_force_rebuild() { this->lss_force_rebuild = true; }
11✔
274

UNCOV
275
    bool is_rebuild_forced() const { return this->lss_force_rebuild; }
×
276

277
    void set_min_log_level(log_level_t level)
9✔
278
    {
279
        if (this->lss_min_log_level != level) {
9✔
280
            this->lss_min_log_level = level;
3✔
281
            this->text_filters_changed();
3✔
282
        }
283
    }
9✔
284

285
    bool list_input_handle_key(listview_curses& lv, const ncinput& ch);
286

287
    void set_marked_only(bool val)
8✔
288
    {
289
        if (this->lss_marked_only != val) {
8✔
290
            this->lss_marked_only = val;
2✔
291
            this->text_filters_changed();
2✔
292
        }
293
    }
8✔
294

295
    void update_filter_hash_state(hasher& h) const;
296

UNCOV
297
    bool get_marked_only() { return this->lss_marked_only; }
×
298

299
    size_t text_line_count() { return this->lss_filtered_index.size(); }
28,029✔
300

301
    size_t text_line_width(textview_curses& curses)
7,763✔
302
    {
303
        return this->lss_longest_line;
7,763✔
304
    }
305

306
    size_t file_count() const;
307

UNCOV
308
    bool empty() const { return this->lss_filtered_index.empty(); }
×
309

310
    line_info text_value_for_line(textview_curses& tc,
311
                                  int row,
312
                                  std::string& value_out,
313
                                  line_flags_t flags);
314

315
    void text_attrs_for_line(textview_curses& tc,
316
                             int row,
317
                             string_attrs_t& value_out);
318

319
    size_t text_size_for_line(textview_curses& tc, int row, line_flags_t flags);
320

321
    void text_mark(const bookmark_type_t* bm, vis_line_t line, bool added);
322

323
    void text_clear_marks(const bookmark_type_t* bm);
324

325
    bool insert_file(const std::shared_ptr<logfile>& lf);
326

327
    void remove_file(std::shared_ptr<logfile> lf);
328

329
    enum class rebuild_result {
330
        rr_no_change,
331
        rr_appended_lines,
332
        rr_partial_rebuild,
333
        rr_full_rebuild,
334
    };
335

336
    rebuild_result rebuild_index(std::optional<ui_clock::time_point> deadline
337
                                 = std::nullopt);
338

339
    void text_update_marks(vis_bookmarks& bm);
340

341
    void set_user_mark(const bookmark_type_t* bm, content_line_t cl)
29✔
342
    {
343
        this->lss_user_marks[bm].insert_once(cl);
29✔
344
    }
29✔
345

346
    bookmarks<content_line_t>::type& get_user_bookmarks()
19✔
347
    {
348
        return this->lss_user_marks;
19✔
349
    }
350

351
    bookmark_metadata& get_bookmark_metadata(content_line_t cl);
352

353
    bookmark_metadata& get_bookmark_metadata(vis_line_t vl)
25✔
354
    {
355
        return this->get_bookmark_metadata(this->at(vl));
25✔
356
    }
357

358
    struct bookmark_metadata_context {
359
        std::optional<vis_line_t> bmc_current;
360
        std::optional<bookmark_metadata*> bmc_current_metadata;
361
        std::optional<vis_line_t> bmc_next_line;
362
    };
363

364
    bookmark_metadata_context get_bookmark_metadata_context(
365
        vis_line_t vl,
366
        bookmark_metadata::categories desired
367
        = bookmark_metadata::categories::any) const;
368

369
    std::optional<bookmark_metadata*> find_bookmark_metadata(
370
        content_line_t cl) const;
371

372
    std::optional<bookmark_metadata*> find_bookmark_metadata(
22,106✔
373
        vis_line_t vl) const
374
    {
375
        if (vl >= this->lss_filtered_index.size()) {
22,106✔
UNCOV
376
            return std::nullopt;
×
377
        }
378
        return this->find_bookmark_metadata(this->at(vl));
22,106✔
379
    }
380

381
    void erase_bookmark_metadata(content_line_t cl);
382

383
    void erase_bookmark_metadata(vis_line_t vl)
26✔
384
    {
385
        this->erase_bookmark_metadata(this->at(vl));
26✔
386
    }
26✔
387

388
    void clear_bookmark_metadata();
389

390
    int get_filtered_count() const
2,016✔
391
    {
392
        return this->lss_index.size() - this->lss_filtered_index.size();
2,016✔
393
    }
394

395
    int get_filtered_count_for(size_t filter_index) const;
396

397
    Result<void, lnav::console::user_message> set_sql_filter(
398
        std::string stmt_str, sqlite3_stmt* stmt);
399

400
    Result<void, lnav::console::user_message> set_sql_marker(
401
        std::string stmt_str, sqlite3_stmt* stmt);
402

403
    Result<void, lnav::console::user_message> set_preview_sql_filter(
404
        sqlite3_stmt* stmt);
405

406
    std::string get_sql_filter_text()
4✔
407
    {
408
        auto filt = this->get_sql_filter();
4✔
409

410
        if (filt) {
4✔
411
            return filt.value()->get_id();
1✔
412
        }
413
        return "";
6✔
414
    }
4✔
415

416
    std::optional<std::shared_ptr<text_filter>> get_sql_filter();
417

418
    std::string get_sql_marker_text() const
19✔
419
    {
420
        return this->lss_marker_stmt_text;
19✔
421
    }
422

423
    std::shared_ptr<logfile> find(const char* fn, content_line_t& line_base);
424

425
    std::shared_ptr<logfile> find(content_line_t& line) const
26,433✔
426
    {
427
        std::shared_ptr<logfile> retval;
26,433✔
428

429
        retval = this->lss_files[line / MAX_LINES_PER_FILE]->get_file();
26,433✔
430
        line = content_line_t(line % MAX_LINES_PER_FILE);
26,433✔
431

432
        return retval;
26,433✔
433
    }
434

435
    logfile* find_file_ptr(content_line_t& line) const
315,754✔
436
    {
437
        auto* retval
438
            = this->lss_files[line / MAX_LINES_PER_FILE]->get_file_ptr();
315,754✔
439
        line = content_line_t(line % MAX_LINES_PER_FILE);
315,754✔
440

441
        return retval;
315,754✔
442
    }
443

444
    logline* find_line(content_line_t line) const
192,766✔
445
    {
446
        logline* retval = nullptr;
192,766✔
447
        auto lf = this->find_file_ptr(line);
192,766✔
448

449
        if (lf != nullptr) {
192,766✔
450
            auto ll_iter = lf->begin() + line;
192,766✔
451

452
            retval = &(*ll_iter);
192,766✔
453
        }
454

455
        return retval;
192,766✔
456
    }
457

458
    std::optional<std::pair<std::shared_ptr<logfile>, logfile::iterator>>
459
    find_line_with_file(content_line_t line) const
23,309✔
460
    {
461
        std::shared_ptr<logfile> lf = this->find(line);
23,309✔
462

463
        if (lf != nullptr) {
23,309✔
464
            auto ll_iter = lf->begin() + line;
23,309✔
465

466
            return std::make_pair(lf, ll_iter);
23,309✔
467
        }
468

UNCOV
469
        return std::nullopt;
×
470
    }
23,309✔
471

472
    std::optional<std::pair<std::shared_ptr<logfile>, logfile::iterator>>
473
    find_line_with_file(std::optional<vis_line_t> vl) const
757✔
474
    {
475
        if (vl && vl.value() >= 0_vl
1,514✔
476
            && vl.value() < vis_line_t(this->lss_filtered_index.size()))
1,514✔
477
        {
478
            return this->find_line_with_file(this->at(vl.value()));
757✔
479
        }
480

UNCOV
481
        return std::nullopt;
×
482
    }
483

484
    std::optional<vis_line_t> find_from_time(const timeval& start) const;
485

UNCOV
486
    std::optional<vis_line_t> find_from_time(time_t start) const
×
487
    {
UNCOV
488
        const auto tv = timeval{start, 0};
×
489

UNCOV
490
        return this->find_from_time(tv);
×
491
    }
492

UNCOV
493
    std::optional<vis_line_t> find_from_time(const exttm& etm) const
×
494
    {
495
        return this->find_from_time(etm.to_timeval());
×
496
    }
497

498
    std::optional<vis_line_t> find_from_content(content_line_t cl);
499

500
    std::optional<row_info> time_for_row(vis_line_t row)
919✔
501
    {
502
        if (row >= 0_vl && row < (ssize_t) this->lss_filtered_index.size()) {
919✔
503
            auto cl = this->at(row);
919✔
504
            return row_info{
1,838✔
505
                this->find_line(cl)->get_timeval(),
919✔
506
                (int64_t) cl,
919✔
507
            };
919✔
508
        }
509
        return std::nullopt;
×
510
    }
511

512
    std::optional<vis_line_t> row_for(const row_info& ri);
513

514
    std::optional<vis_line_t> row_for_time(struct timeval time_bucket)
18✔
515
    {
516
        return this->find_from_time(time_bucket);
18✔
517
    }
518

519
    content_line_t at(vis_line_t vl) const
229,456✔
520
    {
521
        return this->lss_index[this->lss_filtered_index[vl]].value();
229,456✔
522
    }
523

524
    content_line_t at_base(vis_line_t vl)
397✔
525
    {
526
        while (vl > 0_vl
397✔
527
               && this->find_line(this->at(vl))->get_sub_offset() != 0)
397✔
528
        {
UNCOV
529
            --vl;
×
530
        }
531

532
        return this->at(vl);
397✔
533
    }
534

535
    logline_window window_at(vis_line_t start_vl, vis_line_t end_vl)
8✔
536
    {
537
        return logline_window(*this, start_vl, end_vl);
8✔
538
    }
539

540
    logline_window window_at(vis_line_t start_vl)
152✔
541
    {
542
        return logline_window(*this, start_vl, start_vl + 1_vl);
152✔
543
    }
544

UNCOV
545
    logline_window window_to_end(vis_line_t start_vl)
×
546
    {
547
        return logline_window(
×
548
            *this, start_vl, vis_line_t(this->text_line_count()));
×
549
    }
550

551
    /**
552
     * Container for logfile references that keeps of how many lines in the
553
     * logfile have been indexed.
554
     */
555
    struct logfile_data {
556
        logfile_data(size_t index,
482✔
557
                     filter_stack& fs,
558
                     const std::shared_ptr<logfile>& lf)
559
            : ld_file_index(index), ld_filter_state(fs, lf),
482✔
560
              ld_visible(lf->is_indexing())
482✔
561
        {
562
            lf->set_logline_observer(&this->ld_filter_state);
482✔
563
            this->ld_file_ptr = lf.get();
482✔
564
        }
482✔
565

566
        void clear()
482✔
567
        {
568
            this->ld_filter_state.lfo_filter_state.clear();
482✔
569
            this->ld_file_ptr = nullptr;
482✔
570
        }
482✔
571

UNCOV
572
        void set_file(const std::shared_ptr<logfile>& lf)
×
573
        {
574
            this->ld_filter_state.lfo_filter_state.tfs_logfile = lf;
×
UNCOV
575
            this->ld_file_ptr = lf.get();
×
UNCOV
576
            lf->set_logline_observer(&this->ld_filter_state);
×
577
        }
578

579
        std::shared_ptr<logfile> get_file() const
30,177✔
580
        {
581
            return this->ld_filter_state.lfo_filter_state.tfs_logfile;
30,177✔
582
        }
583

584
        logfile* get_file_ptr() const { return this->ld_file_ptr; }
445,454✔
585

586
        bool is_visible() const
12,854✔
587
        {
588
            return this->get_file_ptr() != nullptr && this->ld_visible;
12,854✔
589
        }
590

591
        void set_visibility(bool vis) { this->ld_visible = vis; }
488✔
592

593
        size_t ld_file_index;
594
        line_filter_observer ld_filter_state;
595
        size_t ld_lines_indexed{0};
596
        size_t ld_lines_watched{0};
597
        logfile* ld_file_ptr{nullptr};
598
        bool ld_visible;
599
    };
600

601
    using iterator = std::vector<std::unique_ptr<logfile_data>>::iterator;
602
    using const_iterator
603
        = std::vector<std::unique_ptr<logfile_data>>::const_iterator;
604

605
    size_t size() const { return this->lss_files.size(); }
×
606

607
    iterator begin() { return this->lss_files.begin(); }
1,382✔
608

609
    iterator end() { return this->lss_files.end(); }
1,454✔
610

611
    const_iterator cbegin() const { return this->lss_files.begin(); }
×
612

UNCOV
613
    const_iterator cend() const { return this->lss_files.end(); }
×
614

615
    iterator find_data(content_line_t& line)
2,771✔
616
    {
617
        auto retval = this->lss_files.begin();
2,771✔
618
        std::advance(retval, line / MAX_LINES_PER_FILE);
2,771✔
619
        line = content_line_t(line % MAX_LINES_PER_FILE);
2,771✔
620

621
        return retval;
2,771✔
622
    }
623

624
    iterator find_data(content_line_t line, uint64_t& offset_out)
98,570✔
625
    {
626
        auto retval = this->lss_files.begin();
98,570✔
627
        std::advance(retval, line / MAX_LINES_PER_FILE);
98,570✔
628
        offset_out = line % MAX_LINES_PER_FILE;
98,570✔
629

630
        return retval;
98,570✔
631
    }
632

633
    std::optional<logfile_data*> find_data(const std::shared_ptr<logfile>& lf)
46✔
634
    {
635
        for (auto& ld : *this) {
51✔
636
            if (ld->ld_filter_state.lfo_filter_state.tfs_logfile == lf) {
51✔
637
                return ld.get();
46✔
638
            }
639
        }
UNCOV
640
        return std::nullopt;
×
641
    }
642

643
    iterator find_data_i(const std::shared_ptr<const logfile>& lf)
18✔
644
    {
645
        for (auto iter = this->begin(); iter != this->end(); ++iter) {
19✔
646
            if ((*iter)->ld_filter_state.lfo_filter_state.tfs_logfile == lf) {
19✔
647
                return iter;
18✔
648
            }
649
        }
650

UNCOV
651
        return this->end();
×
652
    }
653

654
    content_line_t get_file_base_content_line(iterator iter)
43✔
655
    {
656
        ssize_t index = std::distance(this->begin(), iter);
43✔
657

658
        return content_line_t(index * MAX_LINES_PER_FILE);
43✔
659
    }
660

661
    void set_index_delegate(index_delegate* id)
579✔
662
    {
663
        if (id != this->lss_index_delegate) {
579✔
664
            this->lss_index_delegate = id;
579✔
665
            this->reload_index_delegate();
579✔
666
        }
667
    }
579✔
668

669
    index_delegate* get_index_delegate() const
670
    {
671
        return this->lss_index_delegate;
672
    }
673

674
    void reload_index_delegate();
675

676
    class meta_grepper
677
        : public grep_proc_source<vis_line_t>
678
        , public grep_proc_sink<vis_line_t> {
679
    public:
680
        meta_grepper(logfile_sub_source& source) : lmg_source(source) {}
1,091✔
681

682
        std::optional<line_info> grep_value_for_line(
683
            vis_line_t line, std::string& value_out) override;
684

685
        vis_line_t grep_initial_line(vis_line_t start,
686
                                     vis_line_t highest) override;
687

688
        void grep_next_line(vis_line_t& line) override;
689

690
        void grep_begin(grep_proc<vis_line_t>& gp,
691
                        vis_line_t start,
692
                        vis_line_t stop) override;
693

694
        void grep_end(grep_proc<vis_line_t>& gp) override;
695

696
        void grep_match(grep_proc<vis_line_t>& gp, vis_line_t line) override;
697

698
        logfile_sub_source& lmg_source;
699
        bool lmg_done{false};
700
    };
701

702
    std::optional<
703
        std::pair<grep_proc_source<vis_line_t>*, grep_proc_sink<vis_line_t>*>>
704
    get_grepper();
705

706
    std::optional<location_history*> get_location_history()
91✔
707
    {
708
        return &this->lss_location_history;
91✔
709
    }
710

711
    void text_crumbs_for_line(int line, std::vector<breadcrumb::crumb>& crumbs);
712

713
    bool text_handle_mouse(textview_curses& tc,
714
                           const listview_curses::display_line_content_t&,
715
                           mouse_event& me);
716

717
    Result<bool, lnav::console::user_message> eval_sql_filter(
718
        sqlite3_stmt* stmt, iterator ld, logfile::const_iterator ll);
719

720
    void invalidate_sql_filter();
721

722
    void set_line_meta_changed() { this->lss_line_meta_changed = true; }
26✔
723

724
    bool is_line_meta_changed() const { return this->lss_line_meta_changed; }
1,563✔
725

726
    void set_exec_context(exec_context* ec) { this->lss_exec_context = ec; }
579✔
727

728
    exec_context* get_exec_context() const { return this->lss_exec_context; }
729

730
    static constexpr uint64_t MAX_CONTENT_LINES = 1ULL << 40;
731
    static constexpr uint64_t MAX_LINES_PER_FILE = 1ULL << 27;
732
    static constexpr uint64_t MAX_FILES
733
        = (MAX_CONTENT_LINES / MAX_LINES_PER_FILE);
734

735
    std::function<void(logfile_sub_source&, file_off_t, file_size_t)>
736
        lss_sorting_observer;
737

738
    uint32_t lss_index_generation{0};
739

740
    void quiesce();
741

742
    struct __attribute__((__packed__)) indexed_content {
743
        enum class level_t : uint8_t {
744
            normal,
745
            warning,
746
            error,
747
        };
748

749
        static level_t level_from_log(const logfile::iterator iter)
11,984✔
750
        {
751
            if (!iter->is_message()) {
11,984✔
752
                return level_t::normal;
2,324✔
753
            }
754
            switch (iter->get_msg_level()) {
9,660✔
755
                case log_level_t::LEVEL_WARNING:
50✔
756
                    return level_t::warning;
50✔
757
                case log_level_t::LEVEL_ERROR:
825✔
758
                case log_level_t::LEVEL_FATAL:
759
                case log_level_t::LEVEL_CRITICAL:
760
                    return level_t::error;
825✔
761
                default:
8,785✔
762
                    return level_t::normal;
8,785✔
763
            }
764
        }
765

766
        indexed_content() = default;
767

768
        indexed_content(content_line_t cl, const logfile::iterator iter)
11,984✔
769
            : ic_value(cl),
11,984✔
770
              ic_level(lnav::enums::to_underlying(level_from_log(iter)))
11,984✔
771
        {
772
        }
11,984✔
773

774
        content_line_t value() const { return content_line_t(this->ic_value); }
444,528✔
775

776
        level_t level() const { return static_cast<level_t>(this->ic_level); }
13,775✔
777

778
        uint64_t ic_value : 38;
779
        uint8_t ic_level : 2;
780
    };
781

782
    big_array<indexed_content> lss_index;
783

784
    std::optional<vis_line_t> row_for_anchor(const std::string& id);
785

786
    std::optional<vis_line_t> adjacent_anchor(vis_line_t vl, direction dir);
787

788
    std::optional<std::string> anchor_for_row(vis_line_t vl);
789

790
    std::unordered_set<std::string> get_anchors();
791

792
    std::optional<json_string> text_row_details(const textview_curses& tc);
793

794
    void reload_config(error_reporter& reporter);
795

UNCOV
796
    bool is_indexing_in_progress() const
×
797
    {
UNCOV
798
        return this->lss_indexing_in_progress;
×
799
    }
800

801
protected:
802
    void text_accel_display_changed() { this->clear_line_size_cache(); }
1✔
803

804
    logline* text_accel_get_line(vis_line_t vl)
2,274✔
805
    {
806
        return this->find_line(this->at(vl));
2,274✔
807
    }
808

809
private:
810
    static const size_t LINE_SIZE_CACHE_SIZE = 512;
811

812
    void clear_line_size_cache()
1,092✔
813
    {
814
        this->lss_line_size_cache.fill(std::make_pair(0, 0));
1,092✔
815
        this->lss_line_size_cache[0].first = -1;
1,092✔
816
    }
1,092✔
817

818
    bool check_extra_filters(iterator ld, logfile::iterator ll);
819

820
    size_t lss_basename_width = 0;
821
    size_t lss_filename_width = 0;
822
    line_context_t lss_line_context{line_context_t::none};
823
    bool lss_force_rebuild{false};
824
    std::vector<std::unique_ptr<logfile_data>> lss_files;
825
    unsigned int lss_all_timestamp_flags{0};
826

827
    std::vector<uint32_t> lss_filtered_index;
828
    auto_mem<sqlite3_stmt> lss_preview_filter_stmt{sqlite3_finalize};
829

830
    bookmarks<content_line_t>::type lss_user_marks{
831
        bookmarks<content_line_t>::create_array()};
832
    auto_mem<sqlite3_stmt> lss_marker_stmt{sqlite3_finalize};
833
    std::string lss_marker_stmt_text;
834

835
    line_flags_t lss_token_flags{0};
836
    iterator lss_token_file_data;
837
    std::shared_ptr<logfile> lss_token_file;
838
    std::string lss_token_value;
839
    string_attrs_t lss_token_attrs;
840
    lnav::document::metadata lss_token_meta;
841
    int lss_token_meta_line{-1};
842
    int lss_token_meta_size{0};
843
    size_t lss_time_column_size{0};
844
    size_t lss_time_column_padding{0};
845
    logline_value_vector lss_token_values;
846
    int lss_token_shift_start{0};
847
    int lss_token_shift_size{0};
848
    shared_buffer lss_share_manager;
849
    logfile::iterator lss_token_line;
850
    std::array<std::pair<int, size_t>, LINE_SIZE_CACHE_SIZE>
851
        lss_line_size_cache;
852
    log_level_t lss_min_log_level{LEVEL_UNKNOWN};
853
    bool lss_marked_only{false};
854
    index_delegate* lss_index_delegate{nullptr};
855
    size_t lss_longest_line{0};
856
    meta_grepper lss_meta_grepper;
857
    log_location_history lss_location_history;
858
    exec_context* lss_exec_context{nullptr};
859

860
    bool lss_in_value_for_line{false};
861
    bool lss_line_meta_changed{false};
862

863
    bool lss_indexing_in_progress{false};
864
};
865

866
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc