Skip to content

refactor: give every component a named logger over one shared sink - #24

Merged
ResurrectedTrader merged 1 commit into
split/x64-platformfrom
split/logging
Sep 16, 2026
Merged

ResurrectedTrader merged 1 commit into
split/x64-platformfrom
split/logging

Conversation

@ResurrectedTrader

Copy link
Copy Markdown
Owner

Stacked on #23 — review that first; this PR's diff is only its own changes.

Log sites reached spdlog directly, so each one wrote wherever the default logger happened to point at the time. Worse, a logger built before the host installed its sinks stayed attached to whatever was there when it was created, which meant the backend's bring-up logging (created at DLL attach) was orphaned from the sinks the host installs later.

What changed

utils::GetLogger(name) hands out one logger per component, all sharing a single fan-out sink. Where output goes is decided once, by AddLogSink, and applies to loggers that already exist as well as ones created afterwards — so bring-up loggers and late loggers write to the same places. Names are dotted and follow the source tree (hooks.manager, core.proxy, script.cache, …).

The host adds a rotating file sink next to the ini, named per profile so concurrent instances don't share a file, and flushes every second.

On flushing

Loggers flush themselves from warn, not from every record. Forcing a flush per record puts an fflush inside the shared sink's lock, so a script logging in a loop would stall everything else that logs — including the game thread. The one-second periodic flush bounds what a crash can lose instead.

The trade-off is explicit: an info line can now be lost for up to a second across a hard crash, where previously it was already on disk.

What did not change

Default volume. The framework's own logger stays at debug, everything else at spdlog's default (info). This layer does not raise the volume of anything on its own — there's a test for exactly that.

Raw spdlog:: calls are gone from src/.

Verification

clang-format clean; clang-tidy clean (114 files, full no-cache run). Two tests cover logger identity and the default level. The test suite itself has not been run by me.

🤖 Generated with Claude Code

Log sites reached spdlog directly, so each one wrote wherever the default
logger happened to point, and a logger built before the host installed its
sinks stayed attached to whatever was there at the time.

utils::GetLogger(name) hands out a logger per component over a single
fan-out sink. Where output goes is decided once, by AddLogSink, and applies
to loggers that already exist as well as ones created later - so the
bring-up loggers the backend creates at DLL attach write to the same places
as everything else. Names are dotted and follow the source tree.

The host adds a rotating file sink next to the ini, named per profile so
concurrent instances do not share a file, and flushes every second. Loggers
flush themselves from warn: forcing one per record would put an fflush on
every line inside the shared sink lock, which a script logging in a loop
would make everyone else pay.

Default volume is unchanged - the framework logger at debug, everything else
at spdlog default. Raw spdlog:: calls are gone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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