Run logs
RunWisp saves the stdout and stderr of every run to a file on disk. You can watch a running task’s output live, scroll through old runs, download a log, or search every run of a task. The database keeps the run details (exit code, duration, start time); the output itself stays in the log files.
Where logs live
Section titled “Where logs live”<data dir>/logs/<task-name>/<YYYYMMDD>_<HHMMSS>_<run-id>.logThe data directory is set with --data (default .runwisp); see
global options. Each run gets its own file,
named after the run’s time (in UTC) and its run ID, so files sort by time. Characters other than letters, digits, _, and - in the task name
become _.
stdout and stderr are written to the same file, in the order they arrived. Next
to each .log there is a hidden .<name>.log.meta file with the indexes that
make scrolling fast. RunWisp manages it; don’t delete it while the run is still
going.
Limiting log size
Section titled “Limiting log size”One runaway script shouldn’t fill the disk, so each run’s log has a size limit:
[tasks.bulky-job]cron = "0 4 * * *"run = "/usr/local/bin/bulky.sh"log_max_size = "50mb"log_on_full = "drop_old"log_max_size is the limit.
log_on_full decides what happens when a
run reaches it: keep the newest output (drop_old, the default), keep the
first output (drop_new), or stop the run as log_overflow (kill). In every
case RunWisp writes a line into the log where it cut, so you can see that
output is missing.
For limits across all tasks (total log size and free disk space), see
[storage]. When free space runs low during a run,
log_on_full decides what happens there too.
Retention
Section titled “Retention”Old runs and their logs are deleted by a cleanup that runs every hour. Set a count, an age, or both:
[tasks.metrics]cron = "* * * * *"run = "/usr/local/bin/metrics.sh"keep_runs = 500keep_for = "7d"keep_runs keeps the newest N runs;
keep_for deletes runs older than the age.
With both, whichever deletes more wins. Each task uses its own settings, or the
ones in [defaults].
Only finished runs are deleted; a run that is still going is never touched.
Because the cleanup runs on a timer, you may briefly see a few more runs than
keep_runs. The database row and the log files are deleted together.
Following a run live
Section titled “Following a run live”The Web UI and the TUI show a running task’s output as it’s printed. When you open a run, they first show what’s already on disk, then switch to live, so you never miss the first lines. A finished run opens at the end of its log; scroll up to load earlier lines.
From a shell, runwisp logs -f does the same, and keeps following new runs:
runwisp logs -f backuprunwisp logs -f 'web*'See runwisp logs for the flags.
Progress bars
Section titled “Progress bars”Many tools redraw a line in place, like a download bar that rewrites itself with
\r, or docker pull redrawing a stack of bars. RunWisp handles these so the
log stays readable:
- On disk, a redraw is saved as its final frame:
build: 100%, not every percentage it passed through. - Live, the Web UI and TUI animate the bar in place. A partial line (like
echo -noutput) shows up right away. - Afterwards, you can look at earlier frames of a redraw. In the Web UI, click the marked line. In the TUI, move between marked lines with [ and ] and press enter. The frames are sampled a few times per second, so very fast changes may not all be kept.
RunWisp doesn’t give the task a terminal (no PTY). Many tools notice that and print plain lines instead of a progress bar, which is fine. A redraw on stdout can’t move lines on stderr, and the other way round.
Downloading
Section titled “Downloading”Click the download button in the run header.
Press d in the run view. On a desktop your browser starts the download. Over SSH, the URL is copied to your clipboard or shown in a dialog.
runwisp logs <run-id> > run.log saves the whole log. Add 2>&1 to include
stderr.
GET /api/runs/{runId}/log/raw returns the whole log.
If the log was cut by drop_old during the run, the download includes both the
earlier part that’s still on disk and the current part, as one file.
Searching
Section titled “Searching”Search looks through the log files of a task’s runs, newest run first. There’s no index to build or wait for; a bigger search just takes longer, so results come in pages.
On the task page, type into Search output across runs…. The buttons next to it turn on case sensitivity and regular expressions. Click a result to jump to that line in the log.
Press / with a task selected. Press enter on a result to jump to that line.
GET /api/tasks/{taskName}/log/search?q=.... Optional: regex=true (RE2
syntax), case=true, runId=<id> for one run, limit (1 to 1000,
default 200), and cursor with the nextCursor from the previous page.
A bad query (an empty q, a broken regular expression) is rejected with a
400 before any searching starts.
After a crash
Section titled “After a crash”If the daemon dies while a run is writing (power loss, kill -9), the log is
not truncated: everything that reached the disk stays, and the viewer handles a
half-written last line. On the next start the run is marked crashed (see
After a crash) and its log is left as it
was. The last lines are often the best clue to what went wrong.