summaryrefslogtreecommitdiffstats
path: root/ARCHITECTURE.md
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ARCHITECTURE.md121
1 files changed, 121 insertions, 0 deletions
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 0000000..3ef11cb
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,121 @@
+# Architecture
+
+This document covers the internal architecture of the Logfile Navigator (lnav),
+a terminal-based tool for viewing and analyzing log files.
+
+## Goals
+
+The following goals drive the design and implementation of lnav:
+
+- Don't make the user do something that can be done automatically.
+
+ Example: Automatically detect log formats for files instead of making them
+ specify the format for each file.
+
+- Be performant on low-spec hardware.
+
+ Example: Prefer single-threaded optimizations over trying to parallelize
+
+- Operations should be "live" and not block the user from continuing to work.
+
+ Example: Searches are run in the background.
+
+- Provide context-sensitive help.
+
+ Example: When the cursor is over a SQL keyword/function, the help text for
+ that is shown above.
+
+- Show a preview of operations so the user knows what is going to happen.
+
+ Example: When entering a `:filter-out` command, the matched parts of the
+ lines are highlighted in red.
+
+## Overview
+
+The whole of lnav consists of a
+[log file parser](https://docs.lnav.org/en/latest/formats.html),
+[text UI](https://docs.lnav.org/en/latest/ui.html),
+[integrations with SQLite](https://docs.lnav.org/en/latest/sqlext.html),
+[command-line interface](https://docs.lnav.org/en/latest/cli.html), and
+[commands for operating on logs](https://docs.lnav.org/en/latest/commands.html).
+Since the majority of lnav's operations center around logs, the core
+data-structure is the combined log message index. The message index is populated
+when new messages are read from log files. The text UI displays a subset of
+messages from the index. The SQLite virtual-tables allow for programmatic access
+to the messages and lnav's internal state.
+
+[![lnav architecture](docs/lnav-architecture.png)](https://whimsical.com/lnav-architecture-UM594Qo4G3nt2XWaSZA1mh)
+
+## File Monitoring
+
+Each file being monitored by lnav has an associated [`logfile`](src/logfile.hh)
+object, be they plaintext files or files with a recognized format. These
+objects are periodically polled by the main event loop to check if the file
+was deleted, truncated, or new lines added. While reading new lines, if no
+log format has matched yet, each line will be passed through the log format
+regular expressions to try and find a match. Each line that is read is added
+to an index
+
+#### Why is `mmap()` not used?
+
+Note that file contents are consumed using `pread(2)`/`read(2)` and not
+`mmap(2)` since `mmap(2)` does not react well to files changing out from
+underneath it. For example, a truncated file would likely result in a
+`SIGBUS`.
+
+## Log Messages
+
+As files are being indexed, if a matching format is found, the file is
+"promoted" from a plaintext file to a log file. When the file is promoted,
+it is added to the [logfile_sub_source](src/logfile_sub_source.hh), which
+collates all log messages together into a single index.
+
+### Timestamp Parsing
+
+Since all log messages need to have a timestamp, timestamp parsing needs to be
+very efficient. The standard `strptime()` function is quite expensive, so lnav
+includes an optimized custom parser and code-generator in the
+[ptimec](src/ptimec.hh) component. The code-generator is used at compile-time
+to generate parsers for several [common formats](src/time_formats.am).
+
+## Log Formats
+
+[log_format](src/log_format.hh) instances are used to parse lines from files
+into `logline` objects. The majority of log formats are
+[external_log_format](src/log_format_ext.hh) objects that are create from
+[JSON format definitions](https://docs.lnav.org/en/latest/formats.html). The
+built-in definitions are located in the [formats](src/formats) directory. Log
+formats that cannot be handled through a simple regular expression are
+implemented in the [log_format_impls.cc](src/log_format_impls.cc) file.
+
+## User Interface
+
+The lnav text-user-interface is built on top of
+[ncurses](https://invisible-island.net/ncurses/announce.html).
+However, the higher-level functionality of panels, widgets, and such is not
+used. Instead, the following custom components are built on top of the ncurses
+primitives:
+
+- [view_curses](src/view_curses.hh) - Provides the basics for text roles, which
+ allows for themes to color and style text. The `mvwattrline()` function does
+ all the heavy lifting of drawing ["attributed" lines](src/base/attr_line.hh),
+ which are strings that have attributes associated with a given range of
+ characters.
+- [listview_curses](src/listview_curses.hh) - Displays a list of items that are
+ provided by a source.
+- [textview_curses](src/textview_curses.hh) - Builds on the list view by adding
+ support for searching, filtering, bookmarks, etc... The main panel that
+ displays the logs/plaintext/help is a textview.
+- [statusview_curses](src/state-extension-functions.cc) - Draws the status bars
+ at the top and bottom of the TUI.
+- [vt52_curses](src/vt52_curses.hh) - Adapts vt52 escape codes to the ncurses
+ API.
+- [readline_curses](src/readline_curses.hh) - Provides access to the readline
+ library. The readline code is executed in a child process since readline
+ does not get along with ncurses. The child process and readline is set to
+ use a vt52 terminal and the vt52_curses view is uses to translate those
+ escape codes to ncurses.
+
+The following diagram shows the underlying components that make up the TUI:
+
+[![lnav TUI](docs/lnav-tui.png)](https://whimsical.com/lnav-tui-MQjXc7Vx23BxQTHrnuNp5F)