docs: describe SQLite logging (logs.db), drop stale log-file docs

Logging moved to a logs.db SQLite store, but MANUAL.md, MANUAL.html and
SPEC.md still documented info_*.log / error_*.log / structured.json and a
midnight-rollover limitation that no longer exist. Replace those sections with
the logs.db reality: levels (info/error to db+stdout/stderr, debug db-only),
progress-to-stdout-only, retention via log_retention_days, and that recent
events are viewable in the dashboard / GET /status.

Closes #6
This commit is contained in:
Esa Kataja
2026-06-21 20:51:34 +03:00
parent dfbd74b0d2
commit 31e22bd4a7
3 changed files with 22 additions and 19 deletions
+10 -8
View File
@@ -225,17 +225,19 @@ A few things worth knowing:
## 8. Logs
Three log files are written to the **current working directory** (not the config paths):
All logs are written to a **SQLite database, `logs.db`**, in the current working directory (not the config paths). Run the program from the directory where you want it to land — in Docker that's the mounted `/data`.
- `info_YYYY-MM-DD.log` — INFO messages, dated.
- `error_YYYY-MM-DD.log` — ERROR messages, dated.
- `structured.json` — one JSON object per line, every entry (info + error), with `timestamp`, `level`, `message`, optional `error` and `file` fields.
The `logs` table has columns `id`, `ts`, `level`, `message`, `file`, `extra`. Three levels are recorded:
Run the program from the directory where you want the logs to land.
- `info` — INFO messages; also printed to stdout.
- `error` — ERROR messages; also printed to stderr, with the source `file` recorded.
- `debug` — verbose diagnostics (ffprobe output, calculated zscale width, the full ffmpeg/opusenc command, OMDb/TVmaze responses with the API key redacted) in the `extra` column. **Database only** — not printed.
Note: a number of `DEBUG` lines are printed to stdout/stderr (ffprobe output, calculated zscale width, the full ffmpeg command, etc.). These are intentional but not written to the log files.
Live encode progress (`encoding … · 47% · 3.2fps · …`) prints to **stdout only** and is deliberately *not* stored, so it can't flood the database.
**Known limitation:** the date in `info_*.log` / `error_*.log` filenames is computed when the daemon starts and does not roll over at midnight. If the daemon is left running across days, all writes continue into the start-day's file. Restart the daemon to rotate. `structured.json` does not rotate at all.
**Retention:** rows older than `log_retention_days` (default `7`) are purged on startup and on shutdown. The value is editable live from the settings page (`/settings`) and applies at the next purge.
Recent non-debug events are also viewable in the web dashboard and via `GET /status` (when `http_addr` is set).
---
@@ -245,7 +247,7 @@ If any step from probing through encoding through renaming fails:
- The source `.mkv` is moved to `paths.failed` (the move itself is `os.Stat`-guarded — if the source is already gone, the move is skipped and logged; if the move itself errors, that error is logged too). This guarantees the source leaves `paths.input` on every failure path, so the watcher doesn't retry the same file on the next tick.
- The per-job work directory under `paths.work` (containing partial wav/opus/output.mkv) is deleted unconditionally.
- The error is logged to `error_*.log` and `structured.json` with the source file path.
- The error is logged to `logs.db` (level `error`) with the source file path, and printed to stderr.
The watcher continues with the next file; one bad rip won't stop the daemon.