External Access (v0.14.0+)¶
The “External Access” feature opens a local HTTP port that can be used to interact with an lnav instance outside of the TUI. The server is started automatically when lnav runs with the TUI (but not in headless or secure mode) on a port picked by the OS and with a random API key. The :external-access [–name] [port] [api-key] command can be used to pick the port, API key, or instance name instead. Once the port is open, HTTP requests can be sent to access static files, execute commands, or poll for changes. When the external port is open, a globe icon (🌐) is displayed in the top-right corner. Clicking that icon will open a URL in a browser and log you into the server. The :external-access-login [app] command can also be used to login.
Clients that poll the server for changes, like a browser page or an editor
plugin, are counted next to the globe (e.g. 🌐 2), and a message is shown when
a new one connects. A browser is identified by its login session, an editor
plugin by its client_id, and anything else by its User-Agent.
Since the requests do not keep a connection open, a client stops being counted
when it has not polled for 15 seconds. Requests that do not poll, like a
script sending a command, are not counted.
Note
The server only binds to localhost, so it will not
be accessible over the network. If you need to access lnav
remotely, consider using SSH forwarding.
Discovery¶
So that clients, like editor plugins, can find a running lnav without being
configured with a port and key, each instance with an open port writes a
discovery file to external-access/<pid>.json in lnav’s
configuration directory (usually ~/.lnav). The directory
is only accessible by the user and the file is removed when lnav exits. Files
left behind by instances that did not exit cleanly are removed the next time
an instance starts. The file contains the paths given on lnav’s
command-line, along with its name and current directory, to make it easier to
tell instances apart. The contents are described by the following schema:
When there are multiple instances, a client can pick the one to talk to by
matching the name or cwd against its own project. The
instances list subcommand of the
management CLI does this matching and skips files
whose process has exited. For example, to get the URL of the instance
started in the current directory, or the closest one beneath it:
lnav -m instances list --cwd . -o url | head -1
The GET /api/version response also includes the name and
cwd so a client can check that it reached the instance it expected.
Authentication¶
All requests to lnav’s external access server are authenticated. A request must have one of the following:
An
X-Api-Keyheader with the Base64-encoded value of the API-key that was passed to the:external-accesscommand or that was written to the discovery file. This header should be used for automations.An
lnav_session_idcookie. This cookie will be set through the flow initiated by the :external-access-login [app] command that opens the/loginURL using the configured external-opener. The/loginURL accepts a one-time-password query parameter and, if it matches, the session cookie will be created. A single one-time-password is possible at any time and sessions are only valid for the current invocation of lnav.
Endpoints¶
The following routes are available:
GET /api/versionGet the version, process ID, name, and current working directory of the lnav instance.
POST /api/execContent-Type: text/x-lnav-scriptExecute an lnav script and receive the resulting output. Values can be passed to the script in headers instead of being quoted into its text: a
X-Lnav-Var-<name>header whose value is the Base64-encoded value sets the variable$<name>. The prefix is matched without regard to case; the rest of the header name is the variable name as sent. In SQL statements, the variable is a bound parameter, and in commands it expands to a single argument.The results of SQL statements in the script go to a DB view of the request’s own, so a client’s queries don’t replace what the user has in the DB view. To put them in the regular DB view instead, for example to show them with
:spectrogram, send anX-Lnav-Db-View: sharedheader.POST /api/pollContent-Type: application/jsonPerform a long-poll of lnav’s TUI state. The first request to this API should be a
nullto get the current state. The response contains the following fields:next_input- Subsequent calls should send this object so the server knows when there has been a state-change with respect to this client. Currently, theview_states/log_selectionfield is the only stable field and refers to the focused message in the LOG view. Thelog_index_seqfield is thelog_index.seqfrom the previous response.background_tasks- A list of background task progress updates.log_index- What changed in the LOG view’s index since thelog_index_seqthat was sent, so a client can re-query only the rows that changed (e.g. withlog_line >= from_rowagainstall_logs). It contains:seq- The current change sequence number. A script can read it in the same snapshot as its queries withjget(view_details, '/index-seq')from thelogrow oflnav_views, so it can send that instead and skip changes its query already saw.row_count- The number of rows in the LOG view.reset- True when the changes since the given sequence number are not available (the first poll, or too many changes since then); treat every row as changed.changes- A list of changes, oldest first. Each has aseq, the indexgeneration,from_row, androw_count: every row fromfrom_rowonward was added or replaced, leavingrow_countrows. Newly appended lines have afrom_rowequal to the previous row count. A rebuild or filter change starts earlier, possibly at zero.
open_requests- Files for an editor client to open; see below.
An editor, like an IDE plugin, can ask to open the files that lnav would otherwise pass to an external editor command, which can be much faster for IDEs that are slow to launch. To do so, it adds these fields to the object it sends:
client_id- A string that identifies the client across polls.editor_roots- The directories, as lnav sees them, that the client can open files under.
When lnav needs to open a file under one of those directories, it adds an entry to the
open_requestsof the client with the closest root. Each entry has anid, thepath, and thelineandcolto go to, which are one-based. Thelast_event_idinnext_inputis the highestidsent; a request is sent again until a poll comes back with thatlast_event_id. If no client has a matching root, the external editor command is used instead. If the client does not receive the request within two seconds, the request is dropped.GET /assets/css/theme.cssGet the CSS rules for the classes used in the
'html'output of thelnav_view_lines()SQL function. The rules are generated from the current theme, so the HTML looks like the lines on the screen. The pages rendered from Markdown, including apps, already link to this stylesheet. The same rules are returned by thelnav_theme_css()SQL function.
Apps¶
To support custom user-interfaces on top of lnav, “apps” can be installed
that are reachable via the external access server. These browser-based apps
can provide a rich interface for executing queries and presenting
their results. For example, a dashboard for access_log
files can display multiple charts for interesting request statistics.
Apps are reachable from the landing page for the external access server
or you can open one directly by passing its ID to the
:external-access-login [app] command. An app ID has the form
<publisher>/<app-name> (e.g. lnav/api-test).
Creating an app can be done using the management CLI, like so:
lnav -m apps create mydash
This command creates a directory in the configs directory and
populates it with the necessary configuration file and a sample
index.md file.
Test Harness¶
The lnav/api-test app is included by default as a demonstration of the
external access server APIs.
Reference¶
The following are the configuration properties necessary to define an app:
/apps¶
Application definitions |
||||
type |
object |
|||
patternProperties |
||||
|
/apps/<publisher> |
|||
The publisher of the application |
||||
type |
object |
|||
patternProperties |
||||
|
/apps/<publisher>/<app_name> |
|||
The application definition |
||||
type |
object |
|||
properties |
||||
|
/apps/<publisher>/<app_name>/root |
|||
The path to use as the root for files that are a part of this application. The path is relative to the location of the file containing this property. |
||||
type |
string |
|||
pattern |
[\w\-\.]+ |
|||
|
/apps/<publisher>/<app_name>/description |
|||
A description of this application |
||||
type |
string |
|||
additionalProperties |
False |
|||
additionalProperties |
False |
|||
additionalProperties |
False |
|||