mirror of
https://github.com/tstack/lnav
synced 2024-11-17 15:29:40 +00:00
202 lines
7.4 KiB
ReStructuredText
202 lines
7.4 KiB
ReStructuredText
|
|
.. _usage:
|
|
|
|
Usage
|
|
=====
|
|
|
|
This chapter contains an overview of how to use **lnav**.
|
|
|
|
|
|
Basic Controls
|
|
--------------
|
|
|
|
Like most file viewers, scrolling through files can be done with the usual
|
|
:ref:`hotkeys<hotkeys>`. For non-trivial operations, you can enter the
|
|
:ref:`command<commands>` prompt by pressing :kbd:`:`. To analyze data in a
|
|
log file, you can enter the :ref:`SQL prompt<sql-ext>` by pressing :kbd:`;`.
|
|
|
|
.. tip::
|
|
|
|
Check the bottom right corner of the screen for tips on hotkeys that might
|
|
be useful in the current context.
|
|
|
|
.. figure:: hotkey-tips.png
|
|
:align: center
|
|
|
|
When **lnav** is first open, it suggests using :kbd:`e` and
|
|
:kbd:`Shift` + :kbd:`e` to jump to error messages.
|
|
|
|
|
|
Viewing Files
|
|
-------------
|
|
|
|
The files to view in **lnav** can be given on the command-line or passed to the
|
|
:ref:`:open<open>` command. A
|
|
`glob pattern <https://en.wikipedia.org/wiki/Glob_(programming)>`_ can be given
|
|
to watch for files with a common name. If the path is a directory, all of the
|
|
files in the directory will be opened and the directory will be monitored for
|
|
files to be added or removed from the view. If the path is an archive or
|
|
compressed file (and lnav was built with libarchive), the archive will be
|
|
extracted to a temporary location and the files within will be loaded. The
|
|
files that are found will be scanned to identify their file format. Files
|
|
that match a log format will be collated by time and displayed in the LOG
|
|
view. Plain text files can be viewed in the TEXT view, which can be accessed
|
|
by pressing :kbd:`t`.
|
|
|
|
|
|
Archive Support
|
|
^^^^^^^^^^^^^^^
|
|
|
|
If **lnav** is compiled with `libarchive <https://www.libarchive.org>`_,
|
|
any files to be opened will be examined to see if they are a supported archive
|
|
type. If so, the contents of the archive will be extracted to the
|
|
:code:`$TMPDIR/lnav-${UID}-archives/` directory. Once extracted, the files
|
|
within will be loaded into lnav. To speed up opening large amounts of files,
|
|
any file that meets the following conditions will be automatically hidden and
|
|
not indexed:
|
|
|
|
* Binary files
|
|
* Plain text files that are larger than 128KB
|
|
* Duplicate log files
|
|
|
|
The unpacked files will be left in the temporary directory after exiting
|
|
**lnav** so that opening the same archive again will be faster. Unpacked
|
|
archives that have not been accessed in the past two days will be automatically
|
|
deleted the next time **lnav** is started.
|
|
|
|
|
|
Searching
|
|
---------
|
|
|
|
Any log messages that are loaded into **lnav** are indexed by time and log
|
|
level (e.g. error, warning) to make searching quick and easy with
|
|
:ref:`hotkeys<hotkeys>`. For example, pressing :kbd:`e` will jump to the
|
|
next error in the file and pressing :kbd:`Shift` + :kbd:`e` will jump to
|
|
the previous error. Plain text searches can be done by pressing :kbd:`/`
|
|
to enter the search prompt. A regular expression can be entered into the
|
|
prompt to start a search through the current view.
|
|
|
|
|
|
.. _filtering:
|
|
|
|
Filtering
|
|
---------
|
|
|
|
To reduce the amount of noise in a log file, **lnav** can hide log messages
|
|
that match certain criteria. The following sub-sections explain ways to go
|
|
about that.
|
|
|
|
|
|
Regular Expression Match
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
If there are log messages that you are not interested in, you can do a
|
|
"filter out" to hide messages that match a pattern. A filter can be created
|
|
using the interactive editor, the :ref:`:filter-out<filter_out>` command, or
|
|
by doing an :code:`INSERT` into the
|
|
:ref:`lnav_view_filters<table_lnav_view_filters>` table.
|
|
|
|
If there are log messages that you are only interested in, you can do a
|
|
"filter in" to only show messages that match a pattern. The filter can be
|
|
created using the interactive editor, the :ref:`:filter-in<filter_in>` command,
|
|
or by doing an :code:`INSERT` into the
|
|
:ref:`lnav_view_filters<table_lnav_view_filters>` table.
|
|
|
|
|
|
SQLite Expression
|
|
^^^^^^^^^^^^^^^^^
|
|
|
|
Complex filtering can be done by passing a SQLite expression to the
|
|
:ref:`:filter-expr<filter_expr>` command. The expression will be executed for
|
|
every log message and if it returns true, the line will be shown in the log
|
|
view.
|
|
|
|
|
|
Time
|
|
^^^^
|
|
|
|
To limit log messages to a given time frame, the
|
|
:ref:`:hide-lines-before<hide_lines_before>` and
|
|
:ref:`:hide-lines-after<hide_lines_after>` commands can be used to specify
|
|
the beginning and end of the time frame.
|
|
|
|
|
|
Log level
|
|
^^^^^^^^^
|
|
|
|
To hide messages below a certain log level, you can use the
|
|
:ref:`:set-min-log-level<set_min_log_level>`.
|
|
|
|
.. _search_tables:
|
|
|
|
Search Tables
|
|
-------------
|
|
|
|
TBD
|
|
|
|
|
|
.. _taking_notes:
|
|
|
|
Taking Notes
|
|
------------
|
|
|
|
A few of the columns in the log tables can be updated on a row-by-row basis to
|
|
allow you to take notes. 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
|
|
also be changed by the :ref:`:partition-name<partition_name>` command.
|
|
* **log_mark** - Indicates whether the line has been bookmarked.
|
|
* **log_comment** - A free-form text field for storing commentary. This
|
|
column can also be changed by the :ref:`:comment<comment>` command.
|
|
* **log_tags** - A JSON list of tags associated with the log message. This
|
|
column can also be changed by the :ref:`:tag<tag>` command.
|
|
|
|
While these columns can be updated by through other means, using the SQL
|
|
interface allows you to make changes automatically and en masse. For example,
|
|
to bookmark all lines that have the text "something interesting" in the log
|
|
message body, you can execute:
|
|
|
|
.. code-block:: custsqlite
|
|
|
|
;UPDATE all_logs SET log_mark = 1 WHERE log_body LIKE '%something interesting%'
|
|
|
|
As a more advanced example of the power afforded by SQL and **lnav**'s virtual
|
|
tables, we will tag log messages where the IP address bound by dhclient has
|
|
changed. For example, if dhclient reports "bound to 10.0.0.1" initially and
|
|
then reports "bound to 10.0.0.2", we want to tag only the messages where the
|
|
IP address was different from the previous message. While this can be done
|
|
with a single SQL statement [#]_, we will break things down into a few steps for
|
|
this example. First, we will use the :ref:`:create-search-table<create_search_table>`
|
|
command to match the dhclient message and extract the IP address:
|
|
|
|
.. code-block:: lnav
|
|
|
|
:create-search-table dhclient_ip bound to (?<ip>[^ ]+)
|
|
|
|
The above command will create a new table named :code:`dhclient_ip` with the
|
|
standard log columns and an :code:`ip` column that contains the IP address.
|
|
Next, we will create a view over the :code:`dhclient_ip` table that returns
|
|
the log message line number, the IP address from the current row and the IP
|
|
address from the previous row:
|
|
|
|
.. code-block:: custsqlite
|
|
|
|
;CREATE VIEW IF NOT EXISTS dhclient_ip_changes AS SELECT log_line, ip, lag(ip) OVER (ORDER BY log_line) AS prev_ip FROM dhclient_ip
|
|
|
|
Finally, the following :code:`UPDATE` statement will concatenate the tag
|
|
"#ipchanged" onto the :code:`log_tags` column for any rows in the view where
|
|
the current IP is different from the previous IP:
|
|
|
|
.. code-block:: custsqlite
|
|
|
|
;UPDATE syslog_log SET log_tags = json_concat(log_tags, '#ipchanged') WHERE log_line IN (SELECT log_line FROM dhclient_ip_changes WHERE ip != prev_ip)
|
|
|
|
Since the above can be a lot to type out interactively, you can put these
|
|
commands into a :ref:`script<scripts>` and execute that script with the
|
|
:kbd:`\|` hotkey.
|
|
|
|
.. [#] The expression :code:`regexp_match('bound to ([^ ]+)', log_body) as ip`
|
|
can be used to extract the IP address from the log message body.
|