Add the logging system#36
Conversation
|
Warning Review limit reached
Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughA new Changescore.logging Runtime Logging Feature
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
Engine/cpp/runtime/core/logging/logging.test.cpp (1)
247-265: ⚡ Quick winMake
fatal_hookrestoration exception-safe.This test mutates global process state and restores it manually; if control exits unexpectedly before Line 264, later tests inherit the wrong hook.
Suggested fix
- draco::core::logging::internal::fatal_hook = [] { throw FatalTestException{}; }; + auto previous_fatal_hook = draco::core::logging::internal::fatal_hook; + struct FatalHookRestore final + { + void (**slot)(); + void (*old_value)(); + ~FatalHookRestore() { *slot = old_value; } + } fatal_hook_restore{&draco::core::logging::internal::fatal_hook, previous_fatal_hook}; + + draco::core::logging::internal::fatal_hook = [] { throw FatalTestException{}; }; @@ - draco::core::logging::internal::fatal_hook = [] { std::abort(); }; shutdown();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Engine/cpp/runtime/core/logging/logging.test.cpp` around lines 247 - 265, The fatal_hook is manually restored after the test logic, but if an exception is thrown before reaching the restoration line at the end, the global state remains corrupted for subsequent tests. Wrap the fatal_hook assignment at the beginning of the test in a RAII pattern or scope guard that guarantees the hook is restored to its original state (std::abort) even if exceptions occur during the LOG_FATAL call or any other operation within the test scope. Ensure the restoration happens automatically when exiting the test scope, rather than relying on manual restoration at a specific line.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Engine/cpp/runtime/core/logging/logging.cpp`:
- Around line 444-451: The timestamp format at line 444 uses second-level
precision which causes filename collisions when multiple log rolls occur within
the same second, causing the std::ios::trunc flag at line 451 to overwrite
previously rotated logs. Add higher precision to the timestamp (such as
milliseconds or microseconds) or implement a counter-based collision avoidance
mechanism in the new_path construction at line 450 to ensure each rolled log
file gets a unique filename even when rolls happen within the same second.
- Around line 195-219: The init() function creates a new worker thread and
assigns it to g_worker_thread without checking if a thread is already running.
To prevent std::terminate errors from repeated init() calls, add a guard before
the thread creation line that checks if g_worker_thread is joinable; if it is,
return early from the init() function to prevent reassigning an active thread.
The check should happen before g_worker_thread is assigned the new
std::thread(worker_loop).
- Around line 162-169: The worker thread loop (where sink->write(msg) is called
around line 166-169), the flush() function (lines 258-260), and the fatal()
function (lines 368-369) all invoke sink I/O operations without synchronization,
creating a data race when using std::ofstream-backed sinks. Add a new mutex
(separate from the existing g_sink_update_mutex which only protects sink list
modifications) to serialize all sink I/O operations. Lock this mutex around the
sink->write() call in the worker thread dequeue loop, around the flush
operations in the flush() function, and around the sink operations in the
fatal() function to ensure thread-safe access to the sink objects across all
three call sites.
In `@Engine/cpp/runtime/core/logging/logging.test.cpp`:
- Around line 288-306: The test has two issues: the ifstream object infile
opened at the file validation section is never closed before attempting to
remove the file at the end of the test, which causes cross-platform failures on
Windows where open files cannot be deleted; additionally, the hardcoded
test_output.log path can cause collisions when tests run in parallel. Fix this
by ensuring the infile stream is closed before file removal (either by wrapping
the file reading operations in a separate scope or explicitly calling
infile.close()) and by replacing the hardcoded test_path string with a unique
temporary file path using std::filesystem mechanisms to generate a unique name
per test run.
In `@Engine/cpp/runtime/core/logging/macros.h`:
- Around line 3-12: The SET_CATEGORY_VERBOSITY macro uses
std::memory_order_relaxed which is declared in the <atomic> header, but the
header file does not include it. Add `#include` <atomic> at the top of the file
near the existing `#include` <format> to ensure the header is self-sufficient and
all dependencies are properly declared, preventing potential compilation issues
for callers that may not have included <atomic> before using these macros.
---
Nitpick comments:
In `@Engine/cpp/runtime/core/logging/logging.test.cpp`:
- Around line 247-265: The fatal_hook is manually restored after the test logic,
but if an exception is thrown before reaching the restoration line at the end,
the global state remains corrupted for subsequent tests. Wrap the fatal_hook
assignment at the beginning of the test in a RAII pattern or scope guard that
guarantees the hook is restored to its original state (std::abort) even if
exceptions occur during the LOG_FATAL call or any other operation within the
test scope. Ensure the restoration happens automatically when exiting the test
scope, rather than relying on manual restoration at a specific line.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2530ce9c-7b86-4ae8-8d00-4f2021e58a00
📒 Files selected for processing (8)
Engine/cpp/runtime/CMakeLists.txtEngine/cpp/runtime/core/CMakeLists.txtEngine/cpp/runtime/core/core.cppmEngine/cpp/runtime/core/io/image_loader.cppEngine/cpp/runtime/core/logging/logging.cppEngine/cpp/runtime/core/logging/logging.cppmEngine/cpp/runtime/core/logging/logging.test.cppEngine/cpp/runtime/core/logging/macros.h
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Engine/cpp/runtime/core/logging/logging.cpp (1)
198-226:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winConcurrent
init()calls can triggerstd::terminate.The
joinable()guard at line 200 is not thread-safe. If two threads callinit()simultaneously, both may pass the guard before either assigns tog_worker_thread. When the second thread assigns a newstd::threadtog_worker_thread, the destructor of the first thread (which is joinable) is invoked, causingstd::terminate.If concurrent
init()is not a supported usage pattern, document this clearly. Otherwise, protect with a mutex or usestd::call_once.🛡️ Suggested fix using std::call_once
+static std::once_flag g_init_flag; + +static void init_impl() +{ + g_start_time = std::chrono::steady_clock::now(); + // ... rest of initialization + g_worker_thread = std::thread(worker_loop); +} + void init() { - if (g_worker_thread.joinable()) { - return; - } - // ... initialization code ... - g_worker_thread = std::thread(worker_loop); + std::call_once(g_init_flag, init_impl); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Engine/cpp/runtime/core/logging/logging.cpp` around lines 198 - 226, The joinable() check in the init() function is not thread-safe and can result in multiple threads passing the guard and attempting to initialize g_worker_thread simultaneously, causing std::terminate when the second thread's assignment destroys the first thread object. Replace the joinable() guard with a static std::once_flag and wrap the entire initialization logic (from g_start_time assignment through g_worker_thread assignment) inside a std::call_once block to ensure thread-safe one-time initialization of the logging system regardless of concurrent init() calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Engine/cpp/runtime/core/logging/logging.cpp`:
- Around line 362-363: In the execute_fatal function where strncpy is called to
copy text into msg.text, the length parameter should be limited to not exceed
the actual size of the source string. Replace the strncpy call to use
std::min(text.size(), MaxLogMessageLength - 1) as the length parameter instead
of just MaxLogMessageLength - 1. This ensures we never attempt to read past the
bounds of the text string, matching the fix applied to enqueue_log.
- Around line 344-345: The std::strncpy call in the logging message construction
reads from text.data() which is a std::string_view and is not guaranteed to be
null-terminated, risking out-of-bounds reads past the view's actual size.
Replace the strncpy call with memcpy, passing the explicit size from text.size()
and calculating the length to copy as the minimum of text.size() and
(MaxLogMessageLength - 1) to ensure you only copy the actual contents of the
string_view without reading past its boundaries, then explicitly set the null
terminator at the end as currently done.
In `@Engine/cpp/runtime/core/logging/logging.cppm`:
- Around line 98-103: The fatal hook declarations fatal_hook and execute_fatal
are currently exported as part of the public module API within the export
namespace, which unintentionally exposes them for runtime override and weakens
fail-fast guarantees. Move the internal namespace block containing fatal_hook
and execute_fatal declarations out of the export namespace section so they are
no longer part of the exported module surface, or alternatively gate these
declarations behind a test-only API macro to restrict their visibility to
testing code only.
- Around line 4-7: Add explicit includes for symbols that are directly used in
the logging module interface but currently missing from the header section.
Include the `<concepts>` header to support the use of `std::constructible_from`
and include the `<utility>` header to support the use of `std::forward`
throughout the module. These symbols are used in the interface definitions but
relying on transitive includes from other headers like `<format>` is
non-portable and can cause compilation failures across different toolchain
combinations.
---
Outside diff comments:
In `@Engine/cpp/runtime/core/logging/logging.cpp`:
- Around line 198-226: The joinable() check in the init() function is not
thread-safe and can result in multiple threads passing the guard and attempting
to initialize g_worker_thread simultaneously, causing std::terminate when the
second thread's assignment destroys the first thread object. Replace the
joinable() guard with a static std::once_flag and wrap the entire initialization
logic (from g_start_time assignment through g_worker_thread assignment) inside a
std::call_once block to ensure thread-safe one-time initialization of the
logging system regardless of concurrent init() calls.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b101be71-74b6-41d5-9c3b-54ff8a905856
📒 Files selected for processing (4)
Docs/LoggingSinks.mdEngine/cpp/runtime/core/logging/logging.cppEngine/cpp/runtime/core/logging/logging.cppmEngine/cpp/runtime/core/logging/logging.test.cpp
✅ Files skipped from review due to trivial changes (1)
- Docs/LoggingSinks.md
🚧 Files skipped from review as they are similar to previous changes (1)
- Engine/cpp/runtime/core/logging/logging.test.cpp
d9b90b6 to
a0c7815
Compare
There was a problem hiding this comment.
Just address @mcdubhghlas comments, and it can be merged.
Optionally, consider adding constexpr flags exports here or in platform to allow ruling out portions of code in the implementation. We actually could use those in more places too.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Engine/cpp/runtime/core/logging/logging.cpp`:
- Around line 19-20: The logging timestamp formatting code is missing the
required standard header for time types and formatting. Update the include list
in logging.cpp so the section that uses std::tm, localtime_s/localtime_r, and
std::put_time also includes <ctime>, alongside the existing source_location and
system_error headers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7acfb87f-6aa4-4faa-a268-288e7c1b0a7c
📒 Files selected for processing (4)
Docs/LoggingSinks.mdEngine/cpp/runtime/core/logging/logging.cppEngine/cpp/runtime/core/logging/logging.cppmEngine/cpp/runtime/core/logging/logging.test.cpp
✅ Files skipped from review due to trivial changes (1)
- Docs/LoggingSinks.md
🚧 Files skipped from review as they are similar to previous changes (2)
- Engine/cpp/runtime/core/logging/logging.cppm
- Engine/cpp/runtime/core/logging/logging.test.cpp
Summary by CodeRabbit
Release Notes
New Features
Tests
Documentation