Skip to content

refactor: extract logging into log_manager module#3

Merged
kryuchenko merged 1 commit into
mainfrom
refactor/extract-log-manager
Apr 18, 2026
Merged

refactor: extract logging into log_manager module#3
kryuchenko merged 1 commit into
mainfrom
refactor/extract-log-manager

Conversation

@kryuchenko

Copy link
Copy Markdown
Owner

Summary

  • Extract InitLogger, Log, LogSEH, and the g_log_file / g_logPath globals from cli_args_debugger.cpp into new log_manager.{hpp,cpp}.
  • Add CloseLogger() that consolidates the logger shutdown code previously duplicated across both branches of wWinMain (try and catch).
  • cli_args_debugger.cpp: 2101 → 1964 lines (−137).
  • extern FILE* g_log_file and extern std::wstring g_logPath are kept exposed in the header so tests/logging_tests.cpp keeps linking unchanged.
  • Build system updated: CMakeLists.txt, tests/CMakeLists.txt, .github/workflows/build.yml, validate.sh, README.md.

This is step 1 of a larger decomposition; further steps (PathInfo, AudioCapture, Renderer) will follow in separate PRs.

Test plan

  • CI: Windows Build and Test workflow succeeds on this branch.
  • CI: test job (CTest) passes, including logging_tests.cpp.
  • CI: memory-safety-test (ASan) passes.
  • Manual (Windows host, if available): run the exe with arguments and confirm %APPDATA%\CloudStreamingArgsDebugger\debug.log is written with BOM and timestamped lines.

Moves InitLogger/Log/LogSEH and the g_log_file/g_logPath globals
into their own translation unit, plus a new CloseLogger() that
consolidates the duplicated cleanup from both wWinMain branches.

- cli_args_debugger.cpp: 2101 -> 1964 lines (-137)
- extern g_log_file / g_logPath kept for tests/logging_tests.cpp
- CMakeLists, tests/CMakeLists, build.yml, validate.sh, README updated
@kryuchenko
kryuchenko merged commit 3313100 into main Apr 18, 2026
4 checks passed
@kryuchenko
kryuchenko deleted the refactor/extract-log-manager branch April 18, 2026 18:18
kryuchenko pushed a commit that referenced this pull request Apr 18, 2026
Step 3 of the cli_args_debugger.cpp decomposition (steps 1 and 2 were
#3 and #4). Lifts the entire microphone pipeline out of
ArgumentDebuggerWindow into its own class in audio_capture.{hpp,cpp}.

What moves:
- 11 member fields (device_enumerator_, capture_device_, audio_client_,
  capture_client_, mix_format_, audio_event_, audio_thread_, mic_level_,
  mic_available_, audio_thread_running_, mic_name_)
- 4 methods (AudioCaptureThread static entry, AudioCaptureThreadImpl,
  InitializeMicrophone, PollMicrophone)
- The two audio-specific hunks of OnDestroy and Cleanup

What changes for consumers:
- ArgumentDebuggerWindow now holds `AudioCapture audio_capture_` as a
  regular data member. Initialize() brings the pipeline up; Stop() takes
  it down cooperatively; IsAvailable() / Level() / Name() feed the meter
  in RenderFrame.
- seh_wrapper.cpp now casts its LPVOID parameter to AudioCapture* and
  calls ThreadMain() on it. The ArgumentDebuggerWindow forward declaration
  in that file is gone.

PollMicrophone (CCN 50 in the old file) is split: ResolveFormat,
PeakFloat32 / PeakPcm16 / PeakPcm24 / PeakPcm32, PeakForFormat, plus a
thin PollOnce that sequences GetNextPacketSize / GetBuffer / peak /
ReleaseBuffer. PollOnce ends up at CCN 16; the peak helpers are all
single-digit.

cli_args_debugger.cpp: 1846 -> 1382 lines (-464). Only RenderFrame (CCN
21) remains over the static-analysis threshold in the main file.
kryuchenko added a commit that referenced this pull request Apr 18, 2026
Step 3 of the cli_args_debugger.cpp decomposition (steps 1 and 2 were
#3 and #4). Lifts the entire microphone pipeline out of
ArgumentDebuggerWindow into its own class in audio_capture.{hpp,cpp}.

What moves:
- 11 member fields (device_enumerator_, capture_device_, audio_client_,
  capture_client_, mix_format_, audio_event_, audio_thread_, mic_level_,
  mic_available_, audio_thread_running_, mic_name_)
- 4 methods (AudioCaptureThread static entry, AudioCaptureThreadImpl,
  InitializeMicrophone, PollMicrophone)
- The two audio-specific hunks of OnDestroy and Cleanup

What changes for consumers:
- ArgumentDebuggerWindow now holds `AudioCapture audio_capture_` as a
  regular data member. Initialize() brings the pipeline up; Stop() takes
  it down cooperatively; IsAvailable() / Level() / Name() feed the meter
  in RenderFrame.
- seh_wrapper.cpp now casts its LPVOID parameter to AudioCapture* and
  calls ThreadMain() on it. The ArgumentDebuggerWindow forward declaration
  in that file is gone.

PollMicrophone (CCN 50 in the old file) is split: ResolveFormat,
PeakFloat32 / PeakPcm16 / PeakPcm24 / PeakPcm32, PeakForFormat, plus a
thin PollOnce that sequences GetNextPacketSize / GetBuffer / peak /
ReleaseBuffer. PollOnce ends up at CCN 16; the peak helpers are all
single-digit.

cli_args_debugger.cpp: 1846 -> 1382 lines (-464). Only RenderFrame (CCN
21) remains over the static-analysis threshold in the main file.

Co-authored-by: Andrey Kryuchenko <andrey@example.com>
kryuchenko pushed a commit that referenced this pull request Apr 18, 2026
Step 4 (final) of the cli_args_debugger.cpp decomposition (steps 1-3
were #3, #4, #6). RenderFrame was the last function above the static
analysis threshold at CCN 21 / 203 NLOC / 289 lines and touching 37
other class members.

Split into an orchestrator plus ten private section methods:

  UpdateFrameTiming    - tick + FPS + rotation
  RenderCube           - D3D11: clear, viewport, MVP, draw
  RenderTextHud        - description, cli-args header, args, status
  RenderLoadedDataPanel - logs/saved-data panel (show_logs_)
  RenderPathsPanel     - path items (show_paths_)
  RenderInputPrompt    - exit prompt + user_input_
  RenderQrBitmap       - QR code blit
  RenderVolumeMeter    - mic level bars + device name (or no-mic text)
  EndOverlay           - D2D EndDraw + device-lost recreate
  PresentFrame         - FPS log + Present + device-removed recreate

RenderFrame itself is now ~20 lines of sequencing. No behaviour change
intended — each helper receives the same D2D1_SIZE_F and draws into the
same render target, in the same order as before. EndOverlay's bool
return lets the orchestrator skip Present if the D2D device was lost,
mirroring the original early `return`.

Numbers:
- Warnings (CCN > 15 or length > 1000) in cli_args_debugger.cpp:
  was 2 (PollMicrophone=50 already extracted, RenderFrame=21) → now 0.
- cli_args_debugger.cpp stays within a line of the previous total —
  structural split, not a net-line reduction.
- Highest-CCN function in the file drops to WindowProc at CCN 7.
kryuchenko added a commit that referenced this pull request Apr 18, 2026
Step 4 (final) of the cli_args_debugger.cpp decomposition (steps 1-3
were #3, #4, #6). RenderFrame was the last function above the static
analysis threshold at CCN 21 / 203 NLOC / 289 lines and touching 37
other class members.

Split into an orchestrator plus ten private section methods:

  UpdateFrameTiming    - tick + FPS + rotation
  RenderCube           - D3D11: clear, viewport, MVP, draw
  RenderTextHud        - description, cli-args header, args, status
  RenderLoadedDataPanel - logs/saved-data panel (show_logs_)
  RenderPathsPanel     - path items (show_paths_)
  RenderInputPrompt    - exit prompt + user_input_
  RenderQrBitmap       - QR code blit
  RenderVolumeMeter    - mic level bars + device name (or no-mic text)
  EndOverlay           - D2D EndDraw + device-lost recreate
  PresentFrame         - FPS log + Present + device-removed recreate

RenderFrame itself is now ~20 lines of sequencing. No behaviour change
intended — each helper receives the same D2D1_SIZE_F and draws into the
same render target, in the same order as before. EndOverlay's bool
return lets the orchestrator skip Present if the D2D device was lost,
mirroring the original early `return`.

Numbers:
- Warnings (CCN > 15 or length > 1000) in cli_args_debugger.cpp:
  was 2 (PollMicrophone=50 already extracted, RenderFrame=21) → now 0.
- cli_args_debugger.cpp stays within a line of the previous total —
  structural split, not a net-line reduction.
- Highest-CCN function in the file drops to WindowProc at CCN 7.

Co-authored-by: Andrey Kryuchenko <andrey@example.com>
kryuchenko pushed a commit that referenced this pull request Apr 18, 2026
…ests

Splits the 2101-line monolithic cli_args_debugger.cpp into a thin window
class plus four composable modules, and fills the test gap along the way.
End state: cli_args_debugger.cpp down to ~1270 lines, zero functions over
the static-analysis CCN threshold, and 33 new unit tests covering the
extracted pure logic.

Modules extracted
-----------------

log_manager.{hpp,cpp}
  Owns g_log_file / g_logPath, InitLogger / Log / LogSEH / CloseLogger.
  Collapses the duplicated cleanup that was inlined in both branches of
  wWinMain. Keeps the extern globals so tests/logging_tests.cpp links
  unchanged.

path_info.{hpp,cpp}  (namespace path_info)
  Hosts ExecutablePath / CurrentWorkingDirectory / TempDirectory /
  WindowsDirectory / SystemDirectory / OsVersionString /
  WineOrProtonVersion / SaveFilePath / Collect. While moving the code:
    - MAX_PATH truncation fixed in five Win32 helpers via growing-retry
      / queried-size patterns.
    - C-style casts on GetProcAddress → reinterpret_cast.
    - exeDir = exeDir.substr(0, slash) → in-place erase.
    - Wrapped under a namespace so Windows.h macros like
      GetWindowsDirectory don't rewrite the function names.

audio_capture.{hpp,cpp}  (class AudioCapture)
  Pulls the entire WASAPI pipeline out of ArgumentDebuggerWindow: the
  11 audio data members, InitializeMicrophone, PollMicrophone (CCN 50,
  the worst function in the codebase), the capture thread entry, and
  the audio slice of OnDestroy/Cleanup. The seh_wrapper TU now casts
  its LPVOID straight to AudioCapture* and calls ThreadMain, so the
  main class no longer leaks into it. PollMicrophone is split into
  ResolveFormat + four per-format peak helpers + a dispatch; highest
  resulting CCN is 16.

RenderFrame split in place
  The CCN-21, 289-line RenderFrame is replaced by a ~20-line orchestrator
  plus ten private section methods (UpdateFrameTiming, RenderCube,
  RenderTextHud, RenderLoadedDataPanel, RenderPathsPanel,
  RenderInputPrompt, RenderQrBitmap, RenderVolumeMeter, EndOverlay,
  PresentFrame). No behaviour change — each helper draws the same
  region in the same order; EndOverlay's bool return mirrors the
  original device-lost early return.

Build system
------------
CMAKE_CXX_STANDARD 20 (required, extensions off) is set in both
CMakeLists.txt files, aligning the CMake/CTest builds with the
/std:c++20 flag already used by the raw-cl path in build.yml. Prior to
this, CMakeLists.txt left the standard unset (MSVC default ≈ C++14)
and tests/CMakeLists.txt pinned C++17, which is why
std::wstring::data() appeared to work for the main exe but broke
CTest compilation.

Tests
-----
tests/audio_peak_tests.cpp — 22 GoogleTest cases covering PeakFloat32,
PeakPcm16, PeakPcm24, PeakPcm32, PeakForFormat dispatch, ResolveFormat
for plain WAVEFORMATEX and WAVEFORMATEXTENSIBLE unwrapping. Includes
the 24-bit sign-extension edge case that used to be buried in
PollMicrophone, the "unsupported format degrades to 0" contract, and
the zero-channel-count fallback.

tests/path_info_tests.cpp — 11 smoke tests covering every path_info::
helper plus Collect(). Validates the growing-buffer / queried-size
patterns don't truncate, and pins Collect()'s label order so a future
accidental reorder surfaces as a test failure.

To keep these helpers testable without a live microphone, the
anonymous-namespace peak helpers in audio_capture.cpp are promoted
into audio_capture::detail.

Numbers
-------
                         before   after
cli_args_debugger.cpp    2101    ~1270   (-40 %)
functions with CCN > 15     2       0
average CCN (main file)   6.4     3.4
highest CCN (main file)    50       7   (WindowProc)
test suites                12      14

Squash of PRs #3, #4, #5, #6, #7, #8.
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