refactor(log): route all engine output through EngineLog#13
Merged
superuser404notfound merged 1 commit intoMay 23, 2026
Merged
Conversation
- Drop stdio fallback in EngineLog.emit; OSLog + optional handler only. Fixes the duplicate-line rendering in Xcode's debug console that occurred because OSLog and print both surfaced through it. - Convert 23 #if DEBUG print() calls (AVIOReader, Demuxer, AudioDecoder, AudioOutput, SoftwareVideoDecoder, SampleBufferRenderer) to categorised EngineLog.emit. - Add sw.playback category; move SoftwarePlaybackHost, SW + HW video decoders, SampleBufferRenderer, AudioDecoder and AudioOutput out of the .engine catch-all so the custom playback subsystem is filterable on its own. - Remove vestigial memprobe print duplicate in AetherEngine.swift. - aetherctl probe installs its own EngineLog.handler so the CLI keeps its inline stdout diagnostics. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
superuser404notfound
approved these changes
May 23, 2026
Owner
superuser404notfound
left a comment
There was a problem hiding this comment.
LGTM. Verified:
- Engine module is now 100%
print-free (grep acrossSources/AetherEngine/returns nothing); every diagnostic line flows throughEngineLog.emit. - Root cause of the Xcode duplicates was indeed
OSLog + printfiring in parallel, not theprintfallback alone. Removing the stdio fallback inEngineLog.emitis the right fix. aetherctl probenow installs its own handler, which it needs because the previous behaviour relied on the now-removed stdio fallback. Behaviour matrix in the PR description matches what I see inSources/aetherctl/main.swift(serve/validate/probe all install a handler now).- New
.swPlaybackcategory cleanly carves the SoftwarePlaybackHost subsystem (HardwareVideoDecoder,SoftwareVideoDecoder,SampleBufferRenderer,AudioDecoder,AudioOutput) out of the.enginecatch-all.HardwareVideoDecoderlives underswPlaybackbecause it runs insideSoftwarePlaybackHost, not under the AVPlayer-driven path, so the name is accurate even though "Hardware" sounds like it might belong elsewhere. - Public API unchanged:
handlersignature,emitsignature, newCategorycase is non-breaking.swift buildis green on this branch.
One follow-up I'll handle on the Sodalite side post-merge: SodaliteApp.swift:18-19 has a stale comment ("App Store builds leave the handler nil so the engine emits to print() only") that no longer reflects reality after this change. Behaviour-wise the new world is better (stdout in App Store builds with no debugger attached was always wasted), but the comment will mislead future readers. Will fix in a separate commit once this lands.
Thanks for the cleanup.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every diagnostic line the engine emits now goes through one path (
EngineLog.emit) with one sink contract: OSLog always, optional host handler. The stdio fallback that previously caused duplicate lines in Xcode is gone, and the SW playback subsystem gets its own log category (sw.playback) so it can be isolated from the rest of the engine inlog stream/ Console.app filters.Motivation
Two distinct problems with the old logging layout:
Duplicate lines in Xcode.
EngineLog.emitwrote to OSLog unconditionally, then also calledprint(line)whenever no host handler was installed. Xcode renders both OSLog activity and the process's stdout in the same debug-area console, so every emit surfaced twice. The old doc comment claimed gating handler vs. stdout solved this — it did not, because OSLog still fired in parallel. Aisatty(STDOUT_FILENO)gate was tried as an intermediate fix; Xcode wires GUI-app stdout to a pty, so the gate let duplicates through anyway. The fallback was removed entirely.23 raw
print(...)calls scattered acrossAVIOReader,Demuxer,AudioDecoder,AudioOutput,SoftwareVideoDecoder,SampleBufferRenderer, plus a vestigial duplicate inAetherEngineitself. These bypassed OSLog entirely, so they weren't filterable by category, didn't reach Console.app, and contributed to the Xcode duplication when their host also emitted throughEngineLog.The new
swPlaybackcategory carves the custom playback subsystem (SoftwarePlaybackHost+ its decoders +SampleBufferRenderer+AudioDecoder+AudioOutput) out of the.enginecatch-all, so.enginenow genuinely means "cross-subsystem / lifecycle" and the SW route is filterable on its own.Behaviour matrix
log stream, no stdio noiseaetherctl serve/validate(tty / piped / redirected)aetherctl probe(tty / piped / redirected)