From 13059412cec64f9eac4df2ba515e48c2b873f0da Mon Sep 17 00:00:00 2001 From: DanS Date: Tue, 13 Oct 2026 18:16:50 -0500 Subject: [PATCH] fix(log): share one handle between stdout and stderr on Windows On Windows stdout and stderr were reopened onto the same log path with two separate freopen() calls. Each stream then had its own file handle and its own write offset into the one file, so the two writers overwrote each other and interleaved into a garbled log. - stdout is reopened (truncating the file per run), stderr is pointed at the same underlying handle via _dup2 so both share one offset and append in order. - stderr is first given a valid descriptor, since a GUI-subsystem process may start with no fd 2, and is left unbuffered so crash diagnostics are not lost. Also corrects a stale comment that named the old log file. Co-Authored-By: Claude Opus 4.8 --- src/main.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 45a5eaf..eb723a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,7 @@ #ifdef _WIN32 #include "platform/windows_backdrop.h" #include +#include #include #include #include @@ -553,7 +554,7 @@ static void drawWindowBackdrop(dragonx::App& app, ImDrawList* bgDL, ImVec2 p0, I } // ── Window-dimension diagnostic tracer ────────────────────────────────────────────────────── -// Always-on (writes to stderr → dragonx-debug.log on Windows) so it's visible in release builds, +// Always-on (writes to stderr → dragonx-stdout.log on Windows) so it's visible in release builds, // unlike DRAGONX_DEBUG-gated DEBUG_LOGF. Grep the log for "[WINLOG]" to trace how the window size // changes when dragging between monitors of different DPI. Low volume — only fires on window // resize / move / DPI-scale events. TODO: remove once the multi-monitor sizing bug is resolved. @@ -919,8 +920,10 @@ int main(int argc, char* argv[]) // above so the two writers don't interleave/contend on one file. { std::string logPath = (std::filesystem::path(dragonx::util::Platform::getObsidianDragonDir()) / "dragonx-stdout.log").string(); - freopen(logPath.c_str(), "w", stdout); - freopen(logPath.c_str(), "a", stderr); + freopen(logPath.c_str(), "w", stdout); // per-run truncation + freopen("NUL", "w", stderr); // GUI subsystem may have no valid fd 2 — give it one first + _dup2(_fileno(stdout), _fileno(stderr)); // stderr now shares stdout's handle + file offset + setvbuf(stderr, nullptr, _IONBF, 0); // keep stderr unbuffered (crash diagnostics) } // Install crash handler for diagnostics SetUnhandledExceptionFilter(CrashHandler);