Skip to content

Log unhandled exceptions to %LOCALAPPDATA%\Snipdeck\logs\unhandled.log#13

Merged
StuartMeeks merged 1 commit into
masterfrom
fix/log-unhandled-exceptions
May 30, 2026
Merged

Log unhandled exceptions to %LOCALAPPDATA%\Snipdeck\logs\unhandled.log#13
StuartMeeks merged 1 commit into
masterfrom
fix/log-unhandled-exceptions

Conversation

@StuartMeeks

@StuartMeeks StuartMeeks commented May 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • The Continue? dialog you hit is WinUI's default UnhandledException plumbing — it shows the dialog but doesn't log anywhere, so the exception detail vanishes the moment you click through. Outside the debugger the same exception kills the process silently.
  • Wires three handlers in App: Application.UnhandledException, TaskScheduler.UnobservedTaskException, and AppDomain.CurrentDomain.UnhandledException. Each writes a formatted record (type, HRESULT for COMException, message, source, stack, recursive inner exceptions) to %LOCALAPPDATA%\Snipdeck\logs\unhandled.log and marks the exception handled so the app keeps running.
  • New helper CrashLog.Write is best-effort: cannot throw, locks on a static for concurrent writes, rotates the file at 5 MB to a .1 sibling so it can't grow unbounded.
  • IPathProvider gains LogsDirectory; WindowsPathProvider implements it under %LOCALAPPDATA%\Snipdeck\logs\; FakePathProvider mirrors the addition for tests.

Test plan

  • Core unit tests still pass (106/106).
  • Manual: launch on Windows, reproduce the original exception, confirm unhandled.log is populated with a usable stack trace.
  • Manual: deliberately throw from inside a RelayCommand handler, confirm the log captures it and the app continues running.

🤖 Generated with Claude Code

Stuart hit a "Continue?" debugger dialog on launch and the exception
detail evaporated — WinUI's default handler shows the dialog but doesn't
log anywhere. Outside the debugger that same exception kills the
process silently.

Wire three handlers:
- Application.UnhandledException (XAML-thread)
- TaskScheduler.UnobservedTaskException
- AppDomain.UnhandledException (for completeness; rarely fires in
  managed code but free to add)

Each writes a formatted record — type, HRESULT for COMExceptions, the
full message, source, stack, and recursively all inner exceptions — to
%LOCALAPPDATA%\Snipdeck\logs\unhandled.log. Sets Handled=true so the
app keeps running rather than dying; this matches the user's experience
of clicking Continue.

CrashLog.Write is best-effort: it cannot throw, even if DI isn't built,
the path is locked, or disk is full. The log rotates at 5 MB to a .1
sibling so it can't grow unbounded.

IPathProvider gains LogsDirectory; WindowsPathProvider implements it
under %LOCALAPPDATA%\Snipdeck\logs\; FakePathProvider mirrors the
addition for tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@StuartMeeks StuartMeeks merged commit 14b72e1 into master May 30, 2026
2 of 4 checks passed
@StuartMeeks StuartMeeks deleted the fix/log-unhandled-exceptions branch May 30, 2026 00:59
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