Commit 292e221
authored
feat: persist rolling backend logs and capture frontend console into diagnostics (#167)
## The bug
The installed app writes **no log files at all**. `lib.rs` called
`tracing_subscriber::fmt::init()`, which is stdout-only, and an
installed
Windows/macOS build has no console attached - so every `tracing::` line
was
discarded. `<config_dir>/app.driven/logs/` has been empty since install,
the
SPEC s18 diagnostic bundle shipped with no `logs/`, and field bugs (like
the
current `drive.unreachable` loop) are undiagnosable from a user's
bundle.
Separately, the webview's own `console.*` output, uncaught errors, and
unhandled
promise rejections were captured nowhere.
## What this does
**Rolling backend logs** (`src-tauri/src/logging.rs`, new). A layered
subscriber: the original stdout `fmt` layer, unchanged, plus a
`tracing-appender` DAILY rolling file layer writing
`driven.YYYY-MM-DD.log`.
Non-blocking writer, with the `WorkerGuard` deliberately parked in a
process-lifetime `OnceLock` static (dropping it shuts the writer thread
down and
would reproduce the empty-`logs/` bug). Honors `RUST_LOG`, else `info`.
The file
layer writes no ANSI escapes, and includes target, level, and timestamp.
**Retention.** At startup, best-effort, never fatal: delete rolling logs
older
than 14 days, then oldest-first until the total fits 25 MB. `plan_prune`
is a
pure function over `(name, size, age)` so the policy is exhaustively
unit-tested.
`crash-*.txt` dumps and any foreign file in the directory are never
touched, and
the newest log survives a size cap it alone exceeds (it is the file the
appender
is about to write to).
**A second, independent bug fixed.** `add_logs_and_crashes` resolved
`app_config_dir()/driven/logs` (i.e. `%APPDATA%/app.driven/driven/logs`)
while
the panic hook wrote crash dumps to `app_config_dir()/logs`. Only the
latter
exists on disk, so the bundle was collecting **nothing** - not even
crash dumps
that were already sitting there. Both now call the shared
`logging::log_dir()`,
which is the single place that path is resolved.
**Frontend console capture.** New `report_frontend_logs` IPC command
re-emits
webview entries through `tracing` under the `driven::frontend` target,
so
frontend and backend lines interleave in one timeline in one file.
Hardened
against an untrusted webview: batches over 200 entries are rejected,
each text is
truncated at 2000 chars, control characters are scrubbed (a crafted
`console.log` must not be able to forge extra log lines or inject
terminal
escapes into a file that later leaves the machine), and traffic beyond
50
calls/minute is shed with exactly one warn per window.
`ui/src/frontendLog.ts` wraps `console.log/info/warn/error` - always
calling
through to the original first - plus `window.onerror` and
`unhandledrejection`,
into a bounded 500-entry ring that reports its own overflow rather than
dropping
silently. It flushes every 5s, eagerly when large, and re-queues a
failed batch
**at most once** before dropping, so an unavailable backend can never
grow a
backlog or spin. Installed in `main.ts` before mount; no-op outside
Tauri.
**Bundle freshness.** The export awaits a frontend flush first, and the
backend
yields briefly before collecting `logs/` so the non-blocking writer's
queue
drains - otherwise the freshest and most relevant lines are exactly the
ones
missing from the bundle.
## Testing
- Rust: 287 lib tests pass, including 11 new pruning tests (age rule,
size rule,
both composing, crash dumps spared, real-directory prune with a
backdated
mtime) and 12 new command tests (oversize batch rejected, oversize entry
truncated, char-based truncation that cannot split a surrogate pair,
control
characters neutralised, rate-limit shed and window rollover).
- UI: 515 vitest tests pass, including 25 new ones covering the ring,
truncation,
batch splitting at the backend's cap, requeue-once-then-drop, timer and
eager
flush with fake timers, and console passthrough still calling the
original.
- `cargo fmt --check`, `cargo clippy -p driven-app --all-targets -D
warnings`,
and `npx prettier --check src` all clean. Merged `origin/main` (toast +
warning-box PRs) and re-ran every gate green afterwards.1 parent 4b6070b commit 292e221
18 files changed
Lines changed: 1742 additions & 74 deletions
File tree
- design
- src-tauri
- src
- commands
- ui/src
- __tests__
- ipc
- views
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
42 | 48 | | |
43 | 49 | | |
44 | 50 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1412 | 1412 | | |
1413 | 1413 | | |
1414 | 1414 | | |
1415 | | - | |
1416 | | - | |
| 1415 | + | |
| 1416 | + | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + | |
| 1420 | + | |
1417 | 1421 | | |
1418 | 1422 | | |
1419 | 1423 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
53 | 57 | | |
54 | 58 | | |
55 | 59 | | |
| |||
0 commit comments