fix: attach the crashed session's Player.log to native macOS crash reports - #247
fix: attach the crashed session's Player.log to native macOS crash reports#247bobbyg603 wants to merge 2 commits into
Conversation
…ports A macOS crash report uploads at the next launch, and by then Unity has renamed the crashed session's log to Player-prev.log and started a fresh Player.log. The bridge tracked the fixed Application.consoleLogPath, so the log it attached was written after the crash and described nothing about it. _startBugSplat now remembers which tracked path is the player log, and the delegate reads that entry from its Player-prev.log sibling. Every other attachment, and the attach/detach toggling from C#, is unchanged. Unity keeps one rotated log, so a second relaunch before upload attaches a later session's log instead. bugsplat-apple's sessionID would resolve that; this takes the small fix for the common case. Refs #245 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011bapaeRsoZPuK3jjtdk51V
There was a problem hiding this comment.
🟡 Changes recommended
The new Player-prev.log substitution only triggers when _playerLogPath is set at startup, so enabling CapturePlayerLog later can still attach the post-crash Player.log.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes native macOS crash-report attachments so the Player log reflects the crashed Unity session (by reading Player-prev.log at upload time, while still naming the attachment Player.log), and documents the behavior/limitation.
Changes:
- Track the original
Player.logpath passed at native startup and substitute itsPlayer-prev.logsibling when assembling native crash report attachments. - Document the next-launch upload timing and the “only one rotated log” limitation in macOS docs.
- Add a changelog entry describing the fix and its limitation.
File summaries
| File | Description |
|---|---|
| Runtime/Plugins/macOS/BugSplatBridgeMac.mm | Tracks the Player log path and reads Player-prev.log for native crash report attachments. |
| Documentation~/macos.md | Documents next-launch upload behavior and the single-rotated-log limitation. |
| CHANGELOG.md | Notes the macOS native Player log attachment fix and limitation. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (_playerLogPath && [trackedPath isEqualToString:_playerLogPath]) { | ||
| // Read the crashed session's log, not the one this launch is writing. If a relaunch | ||
| // happened between the crash and this upload, Player-prev.log belongs to that later | ||
| // session instead; only bugsplat-apple's sessionID can tell them apart, and this | ||
| // bridge does not use it yet. | ||
| path = PreviousSessionPlayerLogPath(trackedPath); | ||
| } |
Reading Player-prev.log is right whenever the crash is processed at the very next launch, which bugsplat-apple guarantees for every launch that reaches -start: attachments are gathered once, persisted with the report, and retried from disk. The one way it goes wrong is a launch that crashes before BugSplat starts. That session is never processed, and its rotation replaces the file with a log from the wrong session. Each launch now records which file Player.log was - inode and creation date, which Unity's rename-based rotation preserves - keyed by session ID. The delegate implements the sessionID variant bugsplat-apple prefers, and attaches Player-prev.log only when it is the recorded file for the session that crashed. Reports predating the check, or predating session tracking, attach on best effort as before. The changelog and docs previously claimed an offline relaunch attaches the wrong log. It does not; the attachment is captured at the first relaunch and retried from disk. Both now state the narrower, real limitation. Refs #245 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011bapaeRsoZPuK3jjtdk51V
There was a problem hiding this comment.
🟡 Changes recommended
There are a few correctness/quality issues in the new macOS bridge logic/comments (including a potentially fragile fabs usage and a misleading diagnostic message) that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
Runtime/Plugins/macOS/BugSplatBridgeMac.mm:205
- The log message hard-codes a specific cause (“relaunched and crashed again before BugSplat started”), but this branch also triggers for other mismatches (e.g., multiple pending crash reports with different session IDs). Make the message describe the actual condition (identity/session mismatch) to avoid misleading diagnostics.
NSLog(@"BugSplat: Player-prev.log is not the crashed session's log (the app was "
@"relaunched and crashed again before BugSplat started); omitting Player.log "
@"rather than attaching the wrong one.");
Runtime/Plugins/macOS/BugSplatBridgeMac.mm:113
fabs(...)is used without including <math.h>/, which can break compilation depending on toolchain/transitive includes. You can avoid the dependency by using a simple absolute-difference expression here.
double recorded = [record[kRecordCreated] doubleValue];
double actual = [identity[kRecordCreated] doubleValue];
return fabs(recorded - actual) < 1.0;
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
| return [[playerLogPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"Player-prev.log"]; | ||
| } | ||
|
|
||
| // Each launch records which file Player.log was, keyed by session ID, so the delegate can tell |
What
Native macOS crash reports get the crashed session's
Player.log, verified, or none.Why
Three facts combine (#245):
Player.logbecomesPlayer-prev.log.Application.consoleLogPath, a fixed path that always resolves to the current session's log.So the attached
Player.logwas written after the crash and contained nothing about it.How
Read
Player-prev.log._startBugSplatremembers the Player.log path it was given; when the delegate runs, that one entry is read from itsPlayer-prev.logsibling. Everything else is unchanged, and attach/detach from C# still operate on the live path, soCapturePlayerLogtoggling keeps working. It is namedPlayer.logon the report — that is what it is.Verify it is the crashed session's file. Each launch records Player.log's inode and creation date keyed by session ID (Unity rotates by renaming, which preserves both — visible in any Unity log directory:
Player-prev.log's creation date predates its last write). The delegate implementsattachmentsForBugSplat:sessionID:, the variant bugsplat-apple prefers, and attachesPlayer-prev.logonly when it is the recorded file for the session that crashed. Reports predating session tracking, or launches predating this check, attach on best effort as before.Why this is enough
bugsplat-apple gathers attachments once, at the first launch after a crash, persists them beside the report, and retries from disk without asking the delegate again (
persistAttachments:forCrashFilename:/loadPersistedAttachmentsForCrashFilename:). So at the only moment we are asked,Player-prev.logis the crashed session's log — including when that launch is offline, and across crash loops, since each report is processed at the launch that immediately follows it.The remaining case: the app crashes again before BugSplat starts. That session is never processed, and its rotation replaces the file. The identity check turns that from "attach the wrong log" into "attach no log", with an explanation in the player log. No in-process design can recover the file itself; #248 proposes a crash-time-bound log tail as the complement.
iOS is untouched — whether Unity writes a
Player.logfile on iOS at all is unconfirmed.Verification
clang++ -fsyntax-onlypasses with-fobjc-arcand-fno-objc-arc(the file supports both).Player.logends with the crash stack (#36 PlayerMain) rather than starting withInitialize engine version.Player.logand the player log should containPlayer-prev.log is not the crashed session's log.CapturePlayerLog = false: noPlayer.logon the report.Refs #245
🤖 Generated with Claude Code
https://claude.ai/code/session_011bapaeRsoZPuK3jjtdk51V