Skip to content

feat(desktop): in-app Diagnostics — bounded log capture, verbose toggle, scrubbed export (#180) - #274

Merged
badbread merged 3 commits into
mainfrom
feat/desktop-diagnostics
Jul 20, 2026
Merged

feat(desktop): in-app Diagnostics — bounded log capture, verbose toggle, scrubbed export (#180)#274
badbread merged 3 commits into
mainfrom
feat/desktop-diagnostics

Conversation

@badbread

Copy link
Copy Markdown
Owner

Desktop half of #180. Context that motivated doing this now: today's LPR black-screen mystery died unexplained precisely because the client keeps no logs — recon confirmed the desktop app had zero logging: no seam, no FlutterError.onError, empty catch (_) {} everywhere. This turns "something broke, no idea why" into an attachable file.

What

  • DiagnosticsService (new): app-scoped bounded ring buffer (4k lines, capped message length, memory-only until export — nothing written to disk unasked). Warnings/errors/lifecycle always captured; a persisted verbose toggle (off by default) adds HTTP traces + mpv player logs. Bounded by construction, so it's safe to leave on while reproducing.
  • Scrubbing at capture time (the issue's hard constraint): JWT shapes, Bearer values, token/password/secret/api_key query params and JSON fields are redacted before storage — nothing token-shaped ever even sits in the buffer — plus a second pass over the assembled export. Server identity is recorded as host:port only. Every redaction shape is pinned by unit tests (test/diagnostics_scrub_test.dart, 5/5 green on the build box).
  • Global error funnels in main(): FlutterError.onError (chained to the default) + PlatformDispatcher.onError.
  • HTTP trace at the single choke point (TimeoutClient.send): method + bare path + status + duration only — never query strings (?token=), headers, or bodies. Failures always; routine traffic verbose-only.
  • Player hooks (live tile, maximized pane, playback panes): stream.error always; mpv's own log stream verbose-only. This is exactly the evidence that was missing for the LPR incident.
  • Settings → Diagnostics pane: verbose toggle, Export logs… (native save dialog via the fullscreen picker guard), Copy to clipboard, live line count. Export header carries app version (package_info), OS, server host, verbose state.

Scope

Desktop only. The Android share-sheet export and the server-side admin diagnostics bundle from #180 are follow-ups — the issue stays open to track them.

Verify

  • flutter analyze clean; flutter test test/diagnostics_scrub_test.dart 5/5.
  • On the wall: Settings → Diagnostics → flip verbose, browse a bit, Export — the file opens with the header + scrubbed lines; grep it for eyJ/Bearer /token= and find only [REDACTED].

Part of #180 (leave open for Android + server bundle).

badbread added 3 commits July 19, 2026 21:42
…le, scrubbed export (#180)

The client had NO logging at all (no seam, no error handlers, empty catches) —
when something broke in the field there was nothing to attach to a bug report.

- DiagnosticsService: app-scoped bounded ring buffer (4k lines, capped
  messages, in-memory only until export). Warnings/errors/lifecycle always
  captured; an opt-in persisted VERBOSE toggle (off by default) adds HTTP
  request traces and media_kit/mpv player logs. Safe to leave on — bounded by
  construction.
- Capture-time scrubbing: JWT shapes, Bearer values, token/password/secret
  query params and JSON fields are redacted BEFORE storage (nothing
  token-shaped ever sits in the buffer), plus a second pass over the
  assembled export. Server identity recorded as host:port only.
- Global error funnels in main(): FlutterError.onError (chained) +
  PlatformDispatcher.onError.
- HTTP: TimeoutClient.send is the single choke point — logs method + bare
  path + status + duration only (never query strings, headers, or bodies);
  failures always, routine traffic verbose-only.
- Player hooks at the live tile, maximized pane, and playback panes: error
  stream always, mpv log stream verbose-only.
- Settings -> Diagnostics pane: verbose toggle, 'Export logs…' (native save
  dialog via the picker guard), 'Copy to clipboard', line count.

Scope: desktop client only — the Android share-sheet export and the server-
side admin diagnostics bundle from #180 are follow-ups.

Part of #180

Signed-off-by: badbread <badbread@users.noreply.github.com>
Signed-off-by: badbread <badbread@users.noreply.github.com>
Signed-off-by: badbread <badbread@users.noreply.github.com>
@badbread
badbread merged commit 5123b4f into main Jul 20, 2026
6 checks passed
@badbread
badbread deleted the feat/desktop-diagnostics branch July 20, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant