Skip to content

feat(diagnostics): always-on local error log for Release builds - #243

Merged
arzafran merged 2 commits into
mainfrom
feat/release-diagnostics-log
Aug 4, 2026
Merged

feat(diagnostics): always-on local error log for Release builds#243
arzafran merged 2 commits into
mainfrom
feat/release-diagnostics-log

Conversation

@arzafran

@arzafran arzafran commented Aug 4, 2026

Copy link
Copy Markdown
Member

What this does

Gives Release builds a way to leave evidence when something breaks. Until now every log line in the app was #if DEBUG, so reports like 'sockets are unstable losing connection constantly' arrive with zero data. This adds a small always-on diagnostics log and instruments the socket subsystem first, since that is the open bug we cannot see.

Not telemetry: plain file on the user's machine, nothing ever leaves it. No settings toggle either, it is just on (error-level metadata only).

  • New DiagnosticsLog / dilog() in vendor/bonsplit (next to its Debug-only sibling DebugEventLog). Appends to ~/Library/Logs/Programa/diagnostics.log, PROGRAMA_DIAGNOSTICS_LOG overrides the path, rotates to .1 at 2 MB. Callers never block: I/O runs on a dedicated utility serial queue.
  • Socket instrumentation: connection open/close with reason (eof, read_error errno, access_denied, listener_stopped) and duration, accept-loop error classification and listener rearms, subscription teardown reasons (write_failure, unsubscribed, replaced, connection_closed). Metadata only, no payloads.
  • docs/diagnostics.md with the path, override, rotation, and a tail example.

Review order

  1. vendor/bonsplit/Sources/Bonsplit/Public/DiagnosticsLog.swift (the facility)
  2. Sources/TerminalController.swift + TerminalController+Subscriptions.swift (call sites; check none change control flow)
  3. Tests + docs

Test plan

  • CI green
  • Bonsplit SPM tests: DiagnosticsLogTests 2/2 (append lands lines at a custom path; exceeding the cap rotates)
  • Release-config build compiles the non-DEBUG code (verified locally on arm64)
  • Manual: run a Release build, connect/disconnect a programa CLI call, tail ~/Library/Logs/Programa/diagnostics.log and see the open/close pair

Adds DiagnosticsLog (vendor/bonsplit), an always-on (not #if DEBUG),
local-only file log, so socket disconnects and listener errors leave
evidence in Release builds instead of only in the Debug-only
DebugEventLog. No network calls, no settings toggle.

Instruments TerminalController's socket accept loop, listener
start/stop, per-connection open/close (with a close reason), and
event-subscription teardown with dilog() calls.
- sanitize newlines in logged values so nothing (e.g. a hostile path in an
  env override) can forge log records; one record per line, always
- create the log file 0600
- replace the tests' 200ms sleep drain with a real flush() seam that syncs
  the write queue; also useful before collecting the log for a bug report

Rejected from the same review, for the record: an autoclosure API (no
level filtering exists, so nothing would ever skip evaluation; all call
sites are low-frequency socket lifecycle events) and cross-process file
locking (two instances sharing the default path can interleave an error
log's lines; that is acceptable, and tagged builds can point
PROGRAMA_DIAGNOSTICS_LOG elsewhere).
@arzafran
arzafran merged commit 694544c into main Aug 4, 2026
10 checks passed
@arzafran
arzafran deleted the feat/release-diagnostics-log branch August 4, 2026 14:55
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