v0.35.1 make and doc update
Package / arch (push) Canceled after 0s
Package / user (push) Canceled after 0s
Package / deb (push) Canceled after 0s
Package / freebsd (push) Canceled after 0s
Package / image (push) Canceled after 0s
Test / test (push) Canceled after 0s
Test / e2e (push) Canceled after 0s

This commit is contained in:
lixen committed 2026-10-12 17:17:33 -04:00
1 parent f4f8cc0986
commit 0b8701ec13
6 files changed
+128 -52

No files matched your search

+11 -7
View File
@@ -47,8 +47,10 @@ jobs:
pacman -R --noconfirm logwisp
test ! -e /usr/bin/lw
test -f /etc/logwisp/logwisp.toml.pacsave
# make install SERVICE=no into a home, twice, then lw config init places the
# configuration lw reads without -c, and never replaces it
# make release install as a user without root installs into the home,
# twice, without the service; lw config init then places the configuration
# lw reads without -c, and never replaces it. An explicit PREFIX the user
# cannot write fails before writing.
user:
runs-on: ubuntu-latest
timeout-minutes: 10
@@ -57,18 +59,20 @@ jobs:
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
- run: make release
- run: |
make install SERVICE=no PREFIX="$HOME/.local"
make install SERVICE=no PREFIX="$HOME/.local"
make release install
make install
export PATH="$HOME/.local/bin:$PATH"
test ! -e /usr/bin/lw
test ! -e "$HOME/.local/lib/systemd/system/logwisp.service"
test ! -e /etc/logwisp/logwisp.toml
test ! -e "$HOME/.config/logwisp/logwisp.toml"
if make install PREFIX=/usr SERVICE=no; then exit 1; fi
test ! -e /usr/bin/lw
lw config init
lw --check
lw --dump | grep -q '^status_reporter = true'
if lw config init; then exit 1; fi
make uninstall PREFIX="$HOME/.local"
make uninstall
test ! -e "$HOME/.local/bin/lw"
test -f "$HOME/.config/logwisp/logwisp.toml"
# make deb on a host with systemd: the service runs once the package's
+43 -16
View File
@@ -46,16 +46,22 @@ IMAGE_RUN = $(CONTAINER_ENGINE) run --read-only --user 65532:65532 \
--network none --cap-drop ALL --security-opt no-new-privileges
DESTDIR ?=
# SERVICE=no leaves out the service files and the system configuration,
# which lw config init then places where the user wants it.
SERVICE ?= yes
INSTALL_OS_DEFAULT != uname -s
INSTALL_OS ?= $(INSTALL_OS_DEFAULT)
# FreeBSD keeps everything outside the base system under /usr/local.
PREFIX_DEFAULT != [ '$(INSTALL_OS)' = FreeBSD ] && echo /usr/local || echo /usr
SYSTEM_PREFIX != [ '$(INSTALL_OS)' = FreeBSD ] && echo /usr/local || echo /usr
# Unstaged, a user who cannot write the system's bin directory installs for
# itself: under ~/.local, without the service. sudo make install is system-wide.
USER_INSTALL != [ -z '$(DESTDIR)' ] && [ "$$(id -u)" != 0 ] && [ ! -w '$(SYSTEM_PREFIX)/bin' ] && echo yes || echo no
PREFIX_DEFAULT != [ '$(USER_INSTALL)' = yes ] && echo "$$HOME/.local" || echo '$(SYSTEM_PREFIX)'
PREFIX ?= $(PREFIX_DEFAULT)
SYSCONFDIR_DEFAULT != [ '$(INSTALL_OS)' = FreeBSD ] && echo /usr/local/etc || echo /etc
SYSCONFDIR_DEFAULT != if [ '$(USER_INSTALL)' = yes ]; then echo "$$HOME/.config"; \
elif [ '$(INSTALL_OS)' = FreeBSD ]; then echo /usr/local/etc; else echo /etc; fi
SYSCONFDIR ?= $(SYSCONFDIR_DEFAULT)
# SERVICE=no leaves out the service files and the configuration, which lw
# config init then places where the user wants it.
SERVICE_DEFAULT != [ '$(USER_INSTALL)' = yes ] && echo no || echo yes
SERVICE ?= $(SERVICE_DEFAULT)
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man
DOCDIR ?= $(PREFIX)/share/doc/logwisp
@@ -69,6 +75,8 @@ FISHCOMPDIR ?= $(PREFIX)/share/fish/vendor_completions.d
DEB_MAINTAINER ?= Maintainer <maintainer@example.org>
.DEFAULT_GOAL := help
# Goals run in the order given, so make release install installs what it built.
.NOTPARALLEL:
.PHONY: help check-go build release dev wasm test verify e2e image image-check install uninstall deb arch completion clean version
@@ -92,9 +100,10 @@ help:
@echo " image Build $(IMAGE):$(IMAGE_TAG) with $(CONTAINER_ENGINE) (scratch, static, UID 65532)"
@echo " image-check Run it read-only, offline, without capabilities: --version, then"
@echo " --check on $(IMAGE_CHECK_CONFIG)"
@echo "Install (build or release first):"
@echo " install Binary, manual, shell completion, licence and docs; unless SERVICE=no,"
@echo " the service files and $(SYSCONFDIR)/logwisp/logwisp.toml (kept if present)"
@echo "Install (build or release first, as in make release install):"
@echo " install Binary, manual, shell completion, licence and docs under $(PREFIX); unless"
@echo " SERVICE=no, the service files and $(SYSCONFDIR)/logwisp/logwisp.toml (kept"
@echo " if present). A user who cannot write $(SYSTEM_PREFIX)/bin gets ~/.local and no service"
@echo " uninstall Remove them, keeping $(SYSCONFDIR)/logwisp"
@echo " deb Package a release build as $(BIN_DIR)/logwisp_VERSION_ARCH.deb (dpkg-deb)"
@echo " arch Build the Arch package from this working tree in $(BIN_DIR)/arch (makepkg)"
@@ -108,6 +117,7 @@ help:
check-go:
@command -v $(GO) >/dev/null 2>&1 || { \
echo "Go toolchain '$(GO)' not found; go.mod requires go $$(sed -n 's/^go //p' go.mod)."; \
[ -z "$${SUDO_USER:-}" ] || echo " sudo may reset PATH: make release as $$SUDO_USER, then sudo make install"; \
if [ "$$(uname -s)" = FreeBSD ]; then echo " FreeBSD: pkg install $(GO_DEFAULT)"; \
elif [ -f /etc/arch-release ]; then echo " Arch Linux: pacman -S go"; \
else echo " Elsewhere: https://go.dev/dl/ (distribution packages often lag)"; fi; \
@@ -216,18 +226,30 @@ image-check:
'$(IMAGE):$(IMAGE_TAG)' --check -c /etc/logwisp/logwisp.toml
# install stages what a package ships and compiles nothing, so a packager owns
# the build flags. The service files get the installed paths substituted; a
# configuration already in place is kept, on every system alike.
# the build flags. It writes nothing until every directory it needs is
# writable, and leaves existing directories as they are. The service files get
# the installed paths substituted; a configuration already in place is kept.
install:
@set -eu; \
[ -x $(BIN_DIR)/$(BINARY) ] || { echo "no $(BIN_DIR)/$(BINARY): run make build or make release first" >&2; exit 1; }; \
[ -x $(BIN_DIR)/$(BINARY) ] || { echo "no $(BIN_DIR)/$(BINARY): make build or make release first, as in make release install" >&2; exit 1; }; \
case '$(SERVICE)' in yes|no) ;; *) echo "SERVICE is yes or no, not '$(SERVICE)'" >&2; exit 2 ;; esac; \
put() { install -d -m 0755 "$${3%/*}"; install -m "$$1" "$$2" "$$3"; echo "install $$3"; }; \
sub() { install -d -m 0755 "$${3%/*}"; \
root='$(DESTDIR)'; etc="$$root$(SYSCONFDIR)/logwisp"; \
dirs='$(BINDIR) $(MANDIR) $(BASHCOMPDIR) $(ZSHCOMPDIR) $(FISHCOMPDIR) $(LICENSEDIR) $(DOCDIR)'; \
[ '$(SERVICE)' = no ] || case '$(INSTALL_OS)' in \
FreeBSD) dirs="$$dirs $(SYSCONFDIR)/logwisp $(PREFIX)/etc/rc.d" ;; \
*) dirs="$$dirs $(SYSCONFDIR)/logwisp $(PREFIX)/lib/systemd/system $(PREFIX)/lib/sysusers.d $(PREFIX)/lib/tmpfiles.d" ;; \
esac; \
for d in $$dirs; do d="$$root$$d"; while [ ! -e "$$d" ]; do d=$$(dirname "$$d"); done; \
[ -w "$$d" ] || { echo "no write access to $$d: sudo make install, or set PREFIX, SYSCONFDIR or SERVICE=no" >&2; exit 1; }; \
done; \
if [ '$(USER_INSTALL)' = yes ] && [ '$(PREFIX)' = '$(PREFIX_DEFAULT)' ]; then \
echo "$(SYSTEM_PREFIX)/bin is not writable: installing for $$(id -un) under $(PREFIX) (sudo make install: system-wide)"; fi; \
dir() { [ -d "$$1" ] || install -d -m 0755 "$$1"; }; \
put() { dir "$${3%/*}"; install -m "$$1" "$$2" "$$3"; echo "install $$3"; }; \
sub() { dir "$${3%/*}"; \
sed -e 's|@BINDIR@|$(BINDIR)|g' -e 's|@SYSCONFDIR@|$(SYSCONFDIR)|g' -e 's|%%BINDIR%%|$(BINDIR)|g' \
-e 's|%%PREFIX%%/etc|$(SYSCONFDIR)|g' -e 's|%%PREFIX%%|$(PREFIX)|g' "$$2" > "$$3"; \
chmod "$$1" "$$3"; echo "install $$3"; }; \
root='$(DESTDIR)'; etc="$$root$(SYSCONFDIR)/logwisp"; \
put 0755 $(BIN_DIR)/$(BINARY) "$$root$(BINDIR)/$(BINARY)"; \
put 0644 doc/lw.1 "$$root$(MANDIR)/man1/lw.1"; \
put 0644 $(PKG_DIR)/completion/lw.bash "$$root$(BASHCOMPDIR)/lw"; \
@@ -235,7 +257,8 @@ install:
put 0644 $(PKG_DIR)/completion/lw.fish "$$root$(FISHCOMPDIR)/lw.fish"; \
put 0644 LICENSE "$$root$(LICENSEDIR)/LICENSE"; \
for src in README.md logwisp-logo.svg doc/*.md doc/lw.1 config/logwisp.toml; do put 0644 "$$src" "$$root$(DOCDIR)/$$src"; done; \
if [ '$(SERVICE)' = no ]; then echo "skip the service and $$etc (SERVICE=no): lw config init writes a configuration"; exit 0; fi; \
if [ '$(SERVICE)' = no ]; then echo "skip the service and $$etc (SERVICE=no): lw config init writes a configuration"; \
else \
if [ -e "$$etc/logwisp.toml" ]; then echo "keep $$etc/logwisp.toml"; \
else put 0644 config/logwisp.toml "$$etc/logwisp.toml"; fi; \
case '$(INSTALL_OS)' in \
@@ -245,10 +268,14 @@ install:
sub 0644 $(PKG_DIR)/logwisp.service "$$root$(PREFIX)/lib/systemd/system/logwisp.service"; \
sub 0644 $(PKG_DIR)/logwisp.sysusers "$$root$(PREFIX)/lib/sysusers.d/logwisp.conf"; \
sub 0644 $(PKG_DIR)/logwisp.tmpfiles "$$root$(PREFIX)/lib/tmpfiles.d/logwisp.conf" ;; \
esac
esac; \
fi; \
[ -n "$$root" ] || case ":$$PATH:" in *':$(BINDIR):'*) ;; *) echo "note: $(BINDIR) is not on PATH" ;; esac
uninstall:
@set -eu; root='$(DESTDIR)'; \
if [ '$(USER_INSTALL)' = yes ] && [ '$(PREFIX)' = '$(PREFIX_DEFAULT)' ]; then \
echo "$(SYSTEM_PREFIX)/bin is not writable: uninstalling under $(PREFIX) (sudo make uninstall: system-wide)"; fi; \
for f in "$$root$(BINDIR)/$(BINARY)" "$$root$(MANDIR)/man1/lw.1" \
"$$root$(BASHCOMPDIR)/lw" "$$root$(ZSHCOMPDIR)/_lw" "$$root$(FISHCOMPDIR)/lw.fish" \
"$$root$(PREFIX)/lib/systemd/system/logwisp.service" \
+42 -10
View File
@@ -25,9 +25,6 @@ streams, or downstream LogWisp nodes.
- **Presets**: `tail`, `serve`, `edge` and `aggregator` build the common
pipelines from a few keys (`lw --preset tail:path=/var/log/app`);
`lw --dump` turns any command line into a configuration file
- **On screen**: `lw --tui` composes pipelines on a terminal and runs or
prints them; `t` runs them under the screen, where a live view shows each
entry with its fate: passed, or the stage or filter that dropped it
- **Independent pipelines**, each `sources → flow → sinks`, running concurrently
in one process
- **Fan-in and fan-out**: many sources and many sinks per pipeline
@@ -37,9 +34,38 @@ streams, or downstream LogWisp nodes.
- **Hot reload** via `SIGHUP`/`SIGUSR1` or a config file watch, with the new
configuration validated before the old service is torn down
### On screen
`lw --tui` (`-T`) composes pipelines on a full-screen terminal, with the
configuration engine the website's configurator runs as WebAssembly:
- **Start anywhere**: from the pipelines `lw` would run with the same options
(`-c FILE`, pipeline flags, a discovered file), from a preset, or from a
pasted `lw` command line
- **Edit with the schema**: sources, flow stages and sinks side by side; the
inspector edits each part's options from their defaults, every edit is
checked, and `!` lists the problems
- **Run or print**: `r` runs the pipelines; `o` also prints them as a command
line, environment variables or a TOML file once the screen closes
(`lw -T > pipelines.toml`)
- **Tap**: `t` runs them in place and opens a live view of every entry with its
fate, passed or the stage or filter that dropped it; `e` edits that stage,
and `t` again reruns as a reload, keeping the running pipelines when the new
ones do not build. Listeners bind, dialers connect and files are written for
real; a password is asked in a masked dialog
- **Read any log**: the view parses LogWisp's JSON, lw's own log, pino, zap,
slog, docker, journald, ECS, GCP, logfmt and stamped text into time, level,
message and fields, filters them by level or pattern, and shows the payload
as the sinks receive it. It never slows a pipeline: what it misses is
counted
- **Any terminal**: `cmd | lw -T` taps piped input, since the screen draws on
the controlling terminal; colors range from true color to none, and a text
console gets CP437 glyphs
### Inputs
`file` (directory tail with rotation detection and JSON line parsing),
`file` (a directory's files tailed through rotation, a missing directory
waited for, JSON lines parsed),
`console` (stdin, one reader per process), `random` (generated entries, to
check a deployment before real logs), `null` (nothing; holds a source's place
until one is chosen), and the chain ingest listeners `tcp_chain` and
@@ -152,6 +178,12 @@ journalctl -f | ./bin/lw --sink http:host=127.0.0.1,port=8080
# the same with a preset; on a terminal the level names are in color
./bin/lw --preset tail:path=/var/log/myapp
# compose on screen from a preset menu; r runs, t taps, o prints
./bin/lw -T
# tap a stream: t shows each line parsed, and its fate
journalctl -f -o json | ./bin/lw -T --preset pipe
```
As a service, a configuration file holds the pipelines:
@@ -193,12 +225,12 @@ docker run --rm --read-only --cap-drop ALL --security-opt no-new-privileges \
-v /etc/logwisp:/etc/logwisp:ro logwisp:dev -c /etc/logwisp/logwisp.toml
```
`sudo make install` installs the binary, the manual, shell completion, a
systemd unit or FreeBSD rc.d script and its configuration; `make deb` and
`make arch` package them for Debian, Ubuntu and Arch.
`make install SERVICE=no PREFIX="$HOME/.local"` installs `lw`, its manual,
completion and documentation, and no service; `lw config init` writes the
annotated configuration it reads. See [Installation](doc/installation.md).
`make release && sudo make install` installs the binary, the manual, shell
completion, a systemd unit or FreeBSD rc.d script and its configuration.
Without root, `make release install` installs `lw`, its manual, completion and
documentation under `~/.local`, and no service; `lw config init` writes the
annotated configuration it reads. `make deb` and `make arch` package them for
Debian, Ubuntu and Arch. See [Installation](doc/installation.md).
## System Requirements
+26 -13
View File
@@ -76,15 +76,23 @@ checkout.
## Installing
`make install` copies what a package ships and compiles nothing, so build
first. It honours `DESTDIR`, `PREFIX`, `SYSCONFDIR`, `BINDIR` (default
`$PREFIX/bin`, the path the systemd unit and the rc.d script run `lw` from),
`MANDIR`, `DOCDIR` and `LICENSEDIR` (under `$PREFIX/share` by default) and
`SERVICE`:
first, or in one command: `make release install`. It honours `DESTDIR`,
`PREFIX`, `SYSCONFDIR`, `BINDIR` (default `$PREFIX/bin`, the path the systemd
unit and the rc.d script run `lw` from), `MANDIR`, `DOCDIR` and `LICENSEDIR`
(under `$PREFIX/share` by default) and `SERVICE`; `make help` prints the
values in effect:
- Linux defaults: `PREFIX=/usr`, `SYSCONFDIR=/etc`. Outside a package
manager, prefer `PREFIX=/usr/local`; systemd reads units, sysusers and
tmpfiles from there too.
- FreeBSD defaults: `PREFIX=/usr/local`, `SYSCONFDIR=/usr/local/etc`.
- A user who cannot write that layout's `bin` directory, unstaged, gets a
per-user install instead: `PREFIX=~/.local`, `SYSCONFDIR=~/.config`,
`SERVICE=no` ([Without a Service](#without-a-service)). `sudo make install`
installs system-wide.
- Before writing anything, `install` checks that it can write every
directory it needs, and stops naming the first it cannot. It creates the
missing ones and leaves the mode of existing ones alone.
- `INSTALL_OS` (default: `uname -s`) picks the layout, so
`INSTALL_OS=FreeBSD DESTDIR=...` stages the FreeBSD one on another system.
- `SERVICE`: `yes` (default) adds the service and its configuration; `no`
@@ -100,6 +108,9 @@ make release
sudo make install PREFIX=/usr/local
```
Build as yourself and install with `sudo`: under `sudo` the build would run
with root's `PATH` and Go cache and leave a `bin/` only root can replace.
Every install gets:
- `$BINDIR/lw` and the manual `$MANDIR/man1/lw.1`
@@ -241,19 +252,20 @@ d=$(mktemp -d); lw config init --out "$d/logwisp.toml"; diff "$d/logwisp.toml" /
### Without a Service
`SERVICE=no` installs `lw`, its manual, completion and documentation, and
nothing else: no service files, account or configuration. For one user,
without root:
nothing else: no service files, account or configuration. A user without
root gets it under `~/.local` by default:
```bash
make release
make install SERVICE=no PREFIX="$HOME/.local"
make release install
lw config init
```
- `~/.local/bin` goes on `PATH`. `man lw` then finds the manual, and bash
and fish the completion; zsh needs
- `~/.local/bin` goes on `PATH` (`make install` notes when it is not).
`man lw` then finds the manual, and bash and fish the completion; zsh needs
`fpath=(~/.local/share/zsh/site-functions $fpath)` before `compinit`.
- `make uninstall PREFIX="$HOME/.local"` removes it.
- `make uninstall`, as the same user, removes it.
- Where that user can write the system's `bin` directory, name the layout:
`make install SERVICE=no PREFIX="$HOME/.local" SYSCONFDIR="$HOME/.config"`.
For every user: `sudo make install SERVICE=no PREFIX=/usr/local`.
@@ -374,8 +386,9 @@ In place:
reinstalled keeping it, removed
- Ubuntu: the `.deb` installed, started, reinstalled keeping an edited
configuration, removed and purged
- Ubuntu, without a service: `make install SERVICE=no` into a home twice,
then `lw config init` writing the file `lw` reads, once
- Ubuntu, as a user without root: `make release install` into the home
twice, without a service, then `lw config init` writing the file `lw`
reads, once; an explicit `PREFIX` it cannot write fails
- FreeBSD: BSD make building, installing twice keeping an edited
configuration, and running the rc.d service
- `make image image-check`
+2 -2
View File
@@ -6,8 +6,8 @@ require (
github.com/lixenwraith/auth v0.5.1
github.com/lixenwraith/color v0.1.3
github.com/lixenwraith/config v0.2.2
github.com/lixenwraith/log v0.1.12-0.20261011001400-86d4fe10bd5e
github.com/lixenwraith/terminal v0.2.2-0.20261010220430-c657af606d34
github.com/lixenwraith/log v0.1.12
github.com/lixenwraith/terminal v0.2.2
github.com/lixenwraith/toml v0.1.3
golang.org/x/term v0.47.0
)
+4 -4
View File
@@ -6,10 +6,10 @@ github.com/lixenwraith/color v0.1.3 h1:vSuvtU4zh1mIZS/7UGHmMdsTr+a7eCjUYGbou7kzF
github.com/lixenwraith/color v0.1.3/go.mod h1:L/I3Vxp6pqslAIzWyZGgKCm2lyStHCA4vKaUoMUm7bU=
github.com/lixenwraith/config v0.2.2 h1:X+l3Tf8Rbk49cipYBJU7/pfdw5wDwD4hRxtFH7rZgOc=
github.com/lixenwraith/config v0.2.2/go.mod h1:yfJQwKS+/6Dg70GIoHeYc0eYztOPETpqe6nUIbakcyg=
github.com/lixenwraith/log v0.1.12-0.20261011001400-86d4fe10bd5e h1:5ocB2Wsd4nQbpX+lkA3LSuHf23GQ46BPejNy3oCZZbU=
github.com/lixenwraith/log v0.1.12-0.20261011001400-86d4fe10bd5e/go.mod h1:EE8i5nSAW2yZBTytKuhdgehmgzrby6kW1k5DyH1SvBg=
github.com/lixenwraith/terminal v0.2.2-0.20261010220430-c657af606d34 h1:GasarGRKYbAXzEz1utbcf9n4+N7WXPKyTbUtQZj8v74=
github.com/lixenwraith/terminal v0.2.2-0.20261010220430-c657af606d34/go.mod h1:V0P/FDpY+UeSvx1VIVuTG7llo0RbK3XrSJLDA7GqHqY=
github.com/lixenwraith/log v0.1.12 h1:0poqOWKPTvxiyv83czKMkBrc4ZShaywq3G/dSb34Jpw=
github.com/lixenwraith/log v0.1.12/go.mod h1:EE8i5nSAW2yZBTytKuhdgehmgzrby6kW1k5DyH1SvBg=
github.com/lixenwraith/terminal v0.2.2 h1:ZyAGE+QV10sFyNoEThEkba+ozfEZyns1A6PO84bsbV4=
github.com/lixenwraith/terminal v0.2.2/go.mod h1:V0P/FDpY+UeSvx1VIVuTG7llo0RbK3XrSJLDA7GqHqY=
github.com/lixenwraith/toml v0.1.3 h1:mhnNVLNogdaqjGd3eC4rV9ZqY3j1Sv+DK1erZ+SPFeI=
github.com/lixenwraith/toml v0.1.3/go.mod h1:itcT/Vt5mwmX9KVGCMsWZr6vbU/JgZ24wV/I0J5cMt0=
golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54=