32 KiB
Command Line Interface
lw [options] [< input]
lw -c|--config FILE [options]
lw -p|--preset NAME[:KEY=VALUE,...] [options]
lw -t|--check [options]
lw --dump [options]
lw -T|--tui [options]
lw auth COMMAND [flags]
lw tls COMMAND [flags]
lw preset NAME [flags]
lw config init [--out FILE]
lw help | -h | --help
lw -V | --version | --schema
Without a configuration file or pipeline options, lw is a filter: stdin to stdout, line for line, until the end of input (Built-in Defaults). With a file it runs the file's pipelines as a service.
A preset builds a common pipeline from a few keys. lw auth
manages SCRAM credentials and logs in to scram listeners
(below); lw tls makes a certificate authority and certificates
(below); lw config init writes the annotated default
configuration (below). A command is recognized only as the
first argument.
Options
- lw's own options have a long form (
--config), and the frequent ones a one-letter short form that stands for it in every command that has it:-c--config,-p--preset,-q--quiet,-t--check,-T--tui,-V--version,-h--help-u--userinlw authand inlw preset serve,edgeandaggregator
- A value follows as the next argument or after
=(-c FILE,-c=FILE,--config FILE,--config=FILE); a value that starts with-follows=, and--ends the options. --check,--dump,--tui,--versionand--schematake no value (--check=falseis a usage error); a boolean key takes one only after=:--quiet=false, not--quiet false.- Short options do not combine (
-q -t, not-qt) or take an attached value (-cFILE). - lw takes options only. An unknown option and a word no option takes (
lw tail,lw -t FILE) are usage errors, named on stderr. - lw's multiword options join words with
-(--rate-limit,--password-file); configuration keys, spec keys and preset keys keep TOML's_and.(--status_reporter,--sink http:tls.cert_file=F,lw preset edge --password_file F). - The commands also take a long option after one dash (
-user NAME).
Any scalar configuration key is settable as a flag using its TOML path; pipelines have their own flags:
--<path>=<value> e.g. --logging.level=debug
--<path> <value> e.g. --logging.level debug
--<path> a switch: true, for a boolean path only
Common
-c FILE,--config FILE: the configuration file; unnamed,~/.config/logwisp/logwisp.tomlif it exists, else./logwisp.toml(Configuration)-t,--check: build every pipeline and plugin, bind nothing, report and exit; see Usage Patterns--dump: print the effective configuration, flags, environment and presets resolved into it, as TOML that-creads back, and exit-T,--tui: compose the pipelines on screen, then run or print them (below)--schema: print every setting, pipeline flag, flow stage, plugin option, preset and output form as one JSON document, and exit; tools build their option lists from it:- a key: its kind, default, rules and help; a table (
tls,auth,acl) holds its own keys, those of the plugin's side (listener or dialer), HTTP's only on a plugin that speaks HTTP. Every listener listsauth.node_binding, which only chain sources use, and every HTTP listenerauth.trusted_proxies, which only thehttpsink admits - a flow stage: its keys, and
on, the values that turn it on - a preset key: its default and help, and the choices (
enum) andhintof the option it sets forms:command,environmentandfile, each with its hint
- a key: its kind, default, rules and help; a table (
--color [WHEN], WHENauto,alwaysornever: level names in color on console sinks, defaultauto(a terminal,NO_COLORunset,TERMnotdumb); bare,always. A console sink's owncolorwins (console sink)-q,--quiet: silence lw's own log and notices, defaultfalse; pipeline output still flows--status_reporter=BOOL: periodic status logging, defaulttruewith a configuration file,falsewithout--auto_reload=BOOL: reload when the configuration file changes, defaultfalse-V,--version: print the version and exit-h,--help,help: print every option, pointing toman lwfor the full reference, and exit
The last -c wins; a missing or empty path is an error.
Logging
--logging.output:file,stdout,stderr,split,allornone, defaultstderr, so stdout carries only data--logging.level:debug,info,warnorerror, defaultinfowith a configuration file,warnwithout--logging.format:raw,txtorjson--logging.sanitization:raw,json,txtorshell--logging.file.directory: a path--logging.file.name: a string--logging.file.max_size_mb,--logging.file.max_total_size_mb: integers--logging.file.retention_hours: a float
--logging.console.target is accepted but has no effect; the console
destination is derived from --logging.output.
Pipelines
Pipeline flags define whole pipelines. They replace the configuration file's pipelines and the built-in default, and a reload keeps them; every other key keeps its precedence.
--pipeline NAMEstarts a pipeline named NAME; specs before the first one go to one pipeline, named after its preset, elsecli-p SPEC,--preset SPECbegins the pipeline with a preset, as its first spec; a second preset needs its own--pipeline NAME. Later flags add sources, sinks and filters, set a rate limit and heartbeat, or replace its format--source SPEC,--sink SPECand--filter SPECadd a stage, repeatable--format SPEC,--rate-limit SPECand--heartbeat SPEC, once per pipeline- a pipeline without
--sourcereads stdin (console sourcestdin), one without--sinkwrites stdout (console sinkstdout) - stdin has one reader, so the whole configuration holds at most one console
source:
pipelines[1].plugin_sources[stdin]: one console source may run, and pipeline "a" has it
A SPEC is TYPE:key=value,..., or key=value,... without a TYPE:
- source, sink, filter and format specs start with a TYPE, which ends at the
first
:; a TYPE alone (--sink null,--format txt) takes the defaults- the plugin type: Sources, Sinks
includeorexclude: Filtersjson,txtorraw: Formatters
- rate-limit and heartbeat specs have no TYPE
- the pairs are comma-separated, with the TOML keys of the plugin's
configtable or of the flow stage- a dotted key reaches a nested table:
tls.cert_file=...,auth.type=scram - a repeated key makes a list:
patterns=ERROR,patterns=WARN - each value is one list entry, commas included:
auth.allow_patterns=^a{1\,3}$is one regex,auth.allow=a,auth.allow=btwo entries - values convert to the option's type:
port=8080,raw=true
- a dotted key reaches a nested table:
\escapes,,=and\in a value; any other backslash stays, so regex escapes such as\dpass unchanged; a:in a value needs no escape (host=::1,listen=127.0.0.1:8080)id=NAMEnames a source or sink; the default is its TYPE, thenTYPE_2,TYPE_3, ...- naming a stage turns it on:
--rate-limitdefaultspolicytodrop,--heartbeatdefaultsenabledtotrue
Errors name the flag and the offending part, and nothing starts:
--sink http:port: missing "="
--rate-limit entries_per_second=100,polcy=drop: unknown key "polcy"
--source file,directory=/x: TYPE ends at ':', as in file:directory=/x
A misspelled plugin key fails validation, before anything is built or opened:
pipelines[0].plugin_sinks[http].config: unknown key "tls.enabeld".
# tail a directory, serve it over SSE on every interface; a browser at
# http://HOST:8080/ shows it
lw --source 'file:directory=/var/log/app,pattern=*.log' \
--sink http:host=0.0.0.0,port=8080
# errors and warnings as JSON, over TLS with SCRAM logins
lw --source file:directory=/var/log/app \
--filter include:patterns=ERROR,patterns=WARN --format json \
--sink "http:port=8443,auth.type=scram,auth.credentials_file=/etc/logwisp/users.toml,\
tls.enabled=true,tls.cert_file=/etc/logwisp/server.crt,tls.key_file=/etc/logwisp/server.key"
# two pipelines: app writes stdout, relay a file
lw --pipeline app --source file:directory=/var/log/app \
--pipeline relay --source tcp_chain:port=9000 \
--sink file:directory=/var/log/relay,name=relay
Pipelines over stdin and stdout are under Usage Patterns.
Presets
--preset NAME:key=value,... takes the SPEC syntax. A list
key (hosts, proxy, allow, deny) takes several values: repeated
(hosts=a,hosts=b) or \,-separated in a SPEC, ,-separated in lw preset
flags (a repeated flag keeps only its last value) and the TUI; any other key
takes one. lw preset NAME [--key value ...] prints the pipeline a preset
expands to, ready for a configuration file; its flags are the keys, spelled as
in the SPEC (--password_file). lw preset NAME -h lists its keys and
defaults, lw preset -h the presets. An unknown key fails and lists the valid
ones.
path: a file, a directory (its files) or a glob, and this host decides which: an existing directory is followed whole, any other path is a file name or glob in its directory; for a directory not here, as in a--dumpfor another host, writeDIR/*. Without one,serveandedgeread stdinfrom(end, orstart): where reading a file startsuser: one SCRAM user, an edge's login or a listener's only user in place ofusers;password_fileholds its password and defaults to/dev/tty, which asks (password sources)
The presets, each with its keys:
pipe: stdin to stdout, the built-in defaultformat(raw)
tail: follow files to stdout, liketail -Fpath(required),from,format(raw)
serve: a live stream, an http sink: a browser atlistengets the viewer,/streamis SSE, each stream starting with the last 1000 entriespath,from,format(json),listen(127.0.0.1:8080)tls:off(default),self(a self-signed certificate made at startup),issuer(one signed byissuer_certandissuer_key), orfiles(certandkey);hostsadds names to a made certificate- without
userorusersthe viewer needs no login, over plain http too allowanddeny: addresses or CIDRs, the sink's aclusers(a credentials file) oruser: readers then log in with SCRAM, which needstlsorproxy; browsers needproxyandviewer=true: the login page and viewer behind the TLS-terminating proxiesproxynames, since a browser cannot bind its login to the TLS channel
edge: forward to an aggregator over TLS (tcp_chain, orhttp_chainwithtransport=http)to(required),path,from,transport(tcp),node- verify the aggregator by
ca(a CA file; default: system roots) orpin(itstls.pin_sha256), andserver_name - authenticate by
user(SCRAM), or a clientcertandkey(mTLS): without either the preset refuses to run
aggregator: receive from edges over TLS, to stdout or fileslisten(0.0.0.0:9000),transport(tcp),format(json)tls:self(default),issuerorfiles, as forserve; neveroff- authenticate by
usersoruser(SCRAM), orclient_ca(mTLS): one is required allowanddeny, as forserveout: a directory foraggregate*.logfiles; default stdout
# follow a directory, level names in color on a terminal
lw --preset tail:path=/var/log/app
# serve it to a browser at http://127.0.0.1:8080/
lw --preset serve:path=/var/log/app
# serve it over HTTPS, self-signed, to SCRAM users; keep the result as a file
lw --preset 'serve:path=/var/log/app/*,tls=self,users=/etc/logwisp/users.toml' --dump > serve.toml
# an aggregator with a certificate made at startup, and an edge pinning it
lw --preset aggregator:users=/etc/logwisp/users.toml,out=/var/log/edges
lw --preset edge:path=/var/log/app,to=agg.example.org:9000,pin=sha256//BASE64,\
user=edge-01,password_file=/etc/logwisp/edge-01.pass
# a temporary pipe, nothing on disk: Enter at the receiver's prompt draws the
# password, typed at the sender's; or both read it from a descriptor
lw -p aggregator:listen=0.0.0.0:9000,user=pipe,format=raw,allow=SENDER/32
cmd | lw -p edge:to=RECEIVER:9000,pin=sha256//BASE64,user=pipe
cmd | lw -p edge:to=RECEIVER:9000,pin=sha256//BASE64,user=pipe,\
password_file=/dev/fd/3 3< <(pass show lw/pipe)
A self-signed aggregator logs its pin at startup (pin_sha256, a warning, so
it shows without a configuration file too). The pin holds across reloads and
changes when lw restarts; a fleet signs with an issuer instead, and edges set
ca. See Security.
Environment Variables
Every setting is also a variable: its path with . as _, uppercased, after
LOGWISP_. An empty variable, a setting's or a pipeline's, counts as unset.
They rank below flags and above the file
(precedence).
export LOGWISP_QUIET=true
export LOGWISP_LOGGING_LEVEL=debug
export LOGWISP_LOGGING_FILE_DIRECTORY=/var/log/logwisp
The path resolver reads two more:
LOGWISP_CONFIG_FILE: the configuration file path, joined ontoLOGWISP_CONFIG_DIRwhen both are setLOGWISP_CONFIG_DIR: the configuration directory; alone, it implies<dir>/logwisp.toml
Pipeline Variables
One pipeline can come from the environment, with the SPEC syntax. Any pipeline flag on the command line makes LogWisp ignore all of them.
LOGWISP_PIPELINE: the pipeline's name, default theLOGWISP_PRESETname, elsecliLOGWISP_PRESET: the preset that begins itLOGWISP_SOURCE,LOGWISP_SINK,LOGWISP_FILTER: one stage eachLOGWISP_SOURCE_1..LOGWISP_SOURCE_Nadd more, after the unnumbered one in numeric order; likewiseLOGWISP_SINK_NandLOGWISP_FILTER_N
LOGWISP_FORMAT,LOGWISP_RATE_LIMIT,LOGWISP_HEARTBEAT
A container needs no configuration file. Without one lw logs less
(Built-in Defaults), so pass LOGWISP_LOGGING_LEVEL=info
and LOGWISP_STATUS_REPORTER=true; the image sets neither, as a variable would
override a mounted file's value:
docker run --rm -p 8080:8080 -v /var/log/app:/logs:ro \
-e LOGWISP_PIPELINE=app \
-e LOGWISP_SOURCE='file:directory=/logs,pattern=*.log' \
-e LOGWISP_FILTER='exclude:patterns=DEBUG' \
-e LOGWISP_SINK='http:host=0.0.0.0,port=8080' \
-e LOGWISP_SINK_1=console \
-e LOGWISP_LOGGING_LEVEL=info -e LOGWISP_STATUS_REPORTER=true \
logwisp:dev
Signals
SIGINT,SIGTERM: graceful shutdownSIGHUP,SIGUSR1: reload: the file is reread and the whole service rebuilt; a configuration error leaves the running service untouched (Hot Reload)SIGHUPbefore the signal handler is installed is ignored, so LogWisp survives a terminal hang-up likenohup- On the
lw --tuiscreen,SIGTERMandSIGHUPclose it, stopping whattruns, and lw exits 0
Exit Codes
0: the end of input, a clean shutdown (SIGINT,SIGTERM),--version/--help,--dump, or a valid--check1: general error: a configuration load or validation failure (--checkincluded, and a bad value on the command line), a logger init failure, a service bootstrap failure2: a usage error (an unknown option, a word no option takes, a missing value or-cpath), or a configuration file named by-c,--config=or aLOGWISP_CONFIG_*variable that does not exist (File Location)- killed by
SIGPIPE(shell status141): the reader of stdout went away, as inlw | head;catends the same way
Built-in Defaults
Without a configuration file and without pipeline flags or variables, lw runs
one built-in pipeline, pipe: console source stdin, raw format, console
sink stdout, no filter, no rate limit. lw is then a Unix filter, like cat:
lw < app.log > copy.log
- Each line of stdin is one entry and one line of stdout.
- The terminator (
\nor\r\n) is written back as\n; an unterminated last line is kept and terminated. - Blank lines are skipped.
- A line over 1 MiB continues in the next entry; no byte is lost.
- The terminator (
- Nothing is dropped: a slow reader slows the reading of stdin.
- On a terminal, control characters are written as
<hex>(ESCbecomes<1b>) and level names are in color; pipes and files get the bytes unchanged (console sink). - When a console source reads a terminal, lw says so once on stderr, unless
--quiet:lw: reading standard input; Ctrl-D ends it (lw --help for usage).
A file that defines no [[pipelines]] still runs pipe. The file's
[[pipelines]], or pipeline flags or variables, replace it whole.
Without a file lw also logs less: logging.level defaults to warn and
status_reporter to false, against info and true with one. Explicit
values from the file, the environment or flags win.
End of input. When stdin ends, the console source ends. A pipeline
finishes when all its sources have ended, and once every pipeline has
finished lw shuts down gracefully and exits 0. Only a console source ends on
its own: file and network sources run until a signal, and so does a pipeline
holding one. Every sink writes what is queued before the exit; a network
sink gives its clients or its downstream its write_timeout_ms
(request_timeout_ms for http_chain), at most 2 s, to take it.
Usage Patterns
Filter
# copy, line for line; exits 0 at the end of input
lw < app.log > copy.log
# errors and warnings only
tail -F app.log | lw --filter include:patterns=ERROR,patterns=WARN
# stdin as a live SSE stream; the http and tcp sinks bind 0.0.0.0 by default
journalctl -f | lw --sink http:host=127.0.0.1,port=8080
# a directory's files to one file, through stdout
lw --source file:directory=/var/log/app,pattern='*.log' > all.log
Development
# a file's pipelines, verbose
lw -c dev.toml --logging.level=debug
Configuration check
lw --check validates without running: it builds every pipeline and plugin as
a start would (options, TLS files, credentials files, startup warnings), but
binds no port, reads no stdin, and opens, reads or creates no log file; it
prints configuration ok: N pipeline(s) and exits 0. Otherwise it prints the
first problem of each setting, flow stage, source, sink and pipeline, a line
each named by its key's path, or else the first file that fails to open, and
exits 1 (2 when a named file is missing, see Exit Codes):
lw --check -c /etc/logwisp/logwisp.toml
lw --check --source file --sink tcp:port=70000
Error: Failed to load config: invalid configuration:
pipelines[0].plugin_sources[file].config.directory: must be set
pipelines[0].plugin_sinks[tcp].config.port: must be from 1 to 65535, got 70000
Production
lw -c /etc/logwisp/logwisp.toml --logging.output=file
Run it in the foreground under a supervisor (systemd, rc.d, a container
runtime); there is no --background flag. A supervisor's stdin is usually
/dev/null, where a console source ends at once, so a service's file defines
its pipelines. See Operations and
Installation.
Reload
kill -HUP $(pidof lw)
kill -USR1 $(pidof lw)
lw --tui
lw --tui (-T) composes pipelines on a full-screen terminal, drawn as the
website's configurator draws them, with the engine the website runs as
WebAssembly; t runs them under the screen and shows what flows.
- Start: the pipelines
lwwould run with the same options (-c FILE, pipeline flags,LOGWISP_SOURCE, a discovered file); with none but the built-in pipe, the preset menu (orempty). A pastedlwcommand line replaces the pipelines, in the preset menu too. - Screen: the pipeline bar on top; SOURCES, FLOW and SINKS side by side from 64 columns, stacked below; each source and sink a tinted bar with its type, whether it listens or dials, and a summary; the four flow stages in their order in a dashed box, the ones off dimmed. The inspector, the chosen part's options with radio buttons for few choices, sits below the canvas, and beside it from 110 columns, where each part also lists up to four options it sets; wide screens size the columns to their content and centre them. Narrow panes stack labels, wrap text and scroll dialogs; the status line wraps to three rows.
- Keys: arrows or
hjklmove; Enter inspects a part, opening on its first required key, then edits a value (empty returns it to its default), opens a list's choices or adds on an add row; in a value, Enter sets it, and Tab or Up/Down set it and move. Left/Right step a choice or set a switch; Space flips it; Esc goes back; Tab moves to the next column.aadds a source, sink or filter;cchanges a source's or sink's type in its place, and moves to a filter's (in the inspector) or the format'styperow;ddeletes, or returns a value to its default; Space turns a flow stage on or off;J/Kmove a filter;[]switch pipelines;ppresets;!shows every problem, moving to the first;rruns;ttaps;ooutput;?keys;qor Ctrl-C quits. - Pipelines: Up from a column's top row reaches the bar, where
[]or Left/Right switch,aadds one (empty or from a preset), Enter renames andddeletes, asking first when it has parts. - Output,
o, each picked by its letter:rruns the pipelines with the other options given (so--checkand--dumpapply to them, and reloads keep them),ttaps them, orc,eandfprint the command line, the environment variables (one pipeline) or the file's pipelines on standard output once the screen closes. - Tap,
t: runs the pipelines in this process asrwould, without the status reporter, and opens the live view. It runs for real: listeners bind, dialers connect and log in, file sinks write.- The terminal stays the screen's: a console sink writing to it runs as a
null sink with its id, and the view shows what it would print; a console
source needs piped input (
cmd | lw -T); lw's own log, when it writes to the terminal, shows in the view as sourcelw; a password the terminal would be asked for is asked in a masked dialog. - Leaving the view keeps the pipelines running.
tafter an edit reruns them as a reload does: when the new ones do not build, the earlier ones keep running and the error chooses the part it names.qasks before it stops them,rando's choices stop them first, andSIGTERMorSIGHUP(an ssh session's end) stops them and closes the screen. - The bar counts the shown pipeline's entries in, filtered by the flow, dropped by sinks, and missed by the screen: the view never slows a pipeline.
- The terminal stays the screen's: a console sink writing to it runs as a
null sink with its id, and the view shows what it would print; a console
source needs piped input (
- Live view: from 40 rows it sits under the diagram; shorter, it takes the
screen while it has the keys.
tor Esc gives them back to the diagram (Esc first closes an open detail).- The canvas cursor picks its point, so the view opens on the first
source: a source shows its entries, a flow stage (or the filter the
inspector is on) what reaches it, the heartbeat its own, the sinks (or
no part) what they got.
vswitches between all, what passed and what was dropped there, with no restart. lw's own log shows from info up at every point;salso offers it alone, debug too. - A row is the entry's time, level, tag, message and fields, read from any line shape: LogWisp's json, lw's own log, vif records, pino, zap, slog, docker, journald, ECS, GCP, or text after an RFC3339 stamp. A narrow screen drops columns; a dropped entry is marked; a rune a terminal would act on or draw wider than a cell shows as a placeholder.
- Keys: arrows or
jkmove (up pauses, down onto the newest follows), PgUp/PgDn;gor Home the oldest,G, End orfthe newest; Enter the row's detail,J/Kscroll it;/only rows matching a pattern, ignoring case when it is all lower case (clearing it, or a level, keeps the focused row in place, paused there unless it is the newest);1-5trace to error and up,0all;schooses the point;iinspects the stage that dropped the row;cclears;q, Ctrl-C,?,r,o,[and]act as on the diagram. - The detail, beside the rows from 160 columns and under them otherwise: time and the stamp as written, level, origin, the verdict with a filter's patterns, the layout read, message, fields, and the payload as the sinks receive it, with escapes for what a cell cannot show.
- It keeps 32 MiB of rows, each entry's message, fields and payload cut to 16 KiB, and redraws at most every 100 ms while entries flow, at once on a key, never when idle. A closed standard output or error fails the write (logged) rather than end lw with the terminal raw.
- The canvas cursor picks its point, so the view opens on the first
source: a source shows its entries, a flow stage (or the filter the
inspector is on) what reaches it, the heartbeat its own, the sinks (or
no part) what they got.
- The screen draws on the controlling terminal:
lw -T > pipelines.tomlandcmd | lw -Tkeep standard input and output as data. lw never writes the file it starts from, but the shell empties a redirect's target before lw reads it: redirect to a file lw does not load. - Color follows the
colorsetting:autothe terminal andNO_COLOR,alwaysthe terminal,nevernone. True color and 256 colors paint the website's dark theme; 16 colors a console look on the terminal's own background (bright white text, its grey for hints, a blue cursor bar that keeps each tint); none the terminal's own colors, the cursor row one reverse bar. A text console draws with CP437 glyphs, and a terminal outside UTF-8 with ASCII.
lw auth
Manages the credentials files of auth.type = "scram" listeners and logs in to
them as a viewer. See
Password Authentication.
lw auth add-user --credentials FILE -u NAME [--password-file FILE] [--generate]
lw auth remove-user --credentials FILE -u NAME
lw auth token --url https://HOST:PORT[/PATH] -u NAME [--password-file FILE]
[--unbound] [TLS flags]
lw auth stream --addr HOST:PORT -u NAME [--password-file FILE] [TLS flags]
add-user: adds a user, or replaces its passwordremove-user: removes a user; refuses the last onetoken: logs in to anhttpsink orhttp_chainsource and prints a bearer tokenstream: logs in to atcpsink and copies its stream to stdout until interrupted
lw auth COMMAND -h lists a command's flags. The exit status is 0 on
success, 1 on failure and 2 on a usage error.
add-user creates the credentials file, with a fresh decoy_key, when it
does not exist or is empty (create it empty first to choose its owner). The
password comes from --password-file when that file exists (at least 8 bytes;
one trailing line break is trimmed; /dev/tty asks). Otherwise a random
26-character password (130 bits) is generated and written to --password-file,
or printed once to stdout when there is none. Replacing an existing user's
password needs an existing --password-file or --generate, so a mistyped path
cannot replace a working password; --generate always generates, overwriting
--password-file. New users take the file's existing Argon2 profile.
Both file commands rewrite atomically (a temporary file in the same directory
as the file, or a symlink's target, then a rename), create files 0600, keep an
existing file's mode and owner, and refuse to write anything the daemon would
not load. A change that cannot keep the owner fails: run it as root or as the
owner. A symlink to a missing file is refused: create the target first.
Neither touches a running LogWisp: send SIGHUP, since auto_reload does not
watch the credentials file.
token and stream build the same TLS and SCRAM client as a chain
sink. --password-file defaults to /dev/tty: the password is asked without
echo; a file, /dev/fd/N or a pipe is read as by a
plugin. TLS flags:
--ca-file (default: system roots) or --pin-sha256 (the tls.pin_sha256 a
self-signed listener logs), --server-name (default: the host), and
--cert-file / --key-file for a listener with tls.client_auth. There is no
flag to skip verification: an unverified server could relay the login.
Redirects are not followed. --unbound logs in to an http sink behind a
TLS-terminating proxy (auth.trusted_proxies), still pinning the proxy's
certificate across the two requests; only then may --url carry the path the
proxy mounts LogWisp at. stream exits 0 on SIGINT or SIGTERM, and 1
when the server ends the stream (a reload or shutdown).
Addresses, as for the plugins (Networking):
- An IPv6 address goes in brackets:
--addr [::1]:PORT,--url https://[::1]:PORT; in a URL a link-local zone is escaped,https://[fe80::1%25eth0]:PORT. - The dial keeps to the address's family; a hostname resolves.
--server-namedefaults to the host; an address, without brackets or zone, must then be among the certificate's IP SANs.
# listener host: a file the service user can read, users, then apply
install -m 0640 -o root -g logwisp /dev/null /etc/logwisp/users.toml
lw auth add-user --credentials /etc/logwisp/users.toml --user edge-01 \
--password-file /etc/logwisp/edge-01.pass
lw auth add-user --credentials /etc/logwisp/users.toml --user viewer \
--password-file viewer.pass
kill -HUP $(pidof lw)
# rotate: new password into the file; SIGHUP, deploy the file, SIGHUP the edge
lw auth add-user --credentials /etc/logwisp/users.toml --user edge-01 \
--password-file /etc/logwisp/edge-01.pass --generate
# http sink status, with the token kept out of curl's argv
curl --cacert ca.crt -H @<(printf 'Authorization: Bearer %s\n' \
"$(lw auth token --url https://HOST:PORT --user viewer \
--password-file viewer.pass --ca-file ca.crt)") https://HOST:PORT/status
# follow a tcp sink, asked for the password
lw auth stream --addr HOST:PORT --user viewer --pin-sha256 sha256//BASE64
lw tls
Makes ECDSA P-256 certificates for tls blocks. It never replaces a file
(remove one to replace it) and writes keys 0600, certificates 0644.
lw tls ca --dir DIR [--name NAME] [--days 3650]
lw tls cert --ca-dir DIR --name NAME [--hosts NAME,...] [--server] [--client]
[--days 397] [--out DIR]
ca:DIR/ca.crtandDIR/ca.key, a CA that signs leaves only (path length 0).ca.crtis what dialers set astls.ca_fileand listeners astls.client_ca_file; withca.keyit is a listener'stls.issuer_cert_fileandtls.issuer_key_file.cert:NAME.crtandNAME.key, in--out(default:--ca-dir).--serverfor a listener:--hostslists the DNS names and IP addresses it carries, defaultNAME;--hostis an alias.--clientfor a dialer presenting a certificate; one of the two is required, both may be given.NAMEis the subject CN, the identityauth.type = "mtls"matches.- Valid 397 days (the longest browsers accept), never past the CA. It prints
the certificate's
pin_sha256.
lw tls ca --dir /etc/logwisp/pki
lw tls cert --ca-dir /etc/logwisp/pki --name agg.example.org --server
lw tls cert --ca-dir /etc/logwisp/pki --name edge-01 --client
lw config
lw config init [--out FILE]
init writes the annotated configuration that ships as
config/logwisp.toml, every option with its default, to edit and run. It
never replaces a file (remove one to replace it). Without --out it writes
~/.config/logwisp/logwisp.toml, the file lw reads without -c unless a
LOGWISP_CONFIG_* variable names another; any other path is run with
-c FILE, and lw prints which applies. As shipped the file defines no
pipeline, so lw still filters stdin, though its own log on stderr is at the
file's default info rather than warn; once it defines [[pipelines]], lw
without pipeline options runs them instead. lw --dump prints the effective
configuration, flags and environment included.
lw config init
sudo lw config init --out /usr/local/etc/logwisp/logwisp.toml