Skip to content

Feature/add logger #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

Feature/add logger #40

wants to merge 7 commits into from

Conversation

kimkulling
Copy link
Owner

@kimkulling kimkulling commented Jul 21, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a flexible logging system with multiple verbosity levels and support for domain-tagged messages.
    • Added helper functions and macros for streamlined logging with automatic file and line tracking.
    • Enhanced string handling with new operators for appending strings and characters, and for element access.
  • Improvements

    • Increased the initial buffer size for strings, allowing for larger default string storage.
    • Refined internal logic for string copying and buffer management for improved clarity and reliability.

Copy link
Contributor

coderabbitai bot commented Jul 21, 2025

Walkthrough

A logging system was introduced to the project, including a new Logger singleton class, log stream abstractions, and helper macros for various log levels. The build configuration was updated to include the new logger files. Additionally, the TStringBase class was extended with new operators and a larger initial buffer size, along with minor refactoring.

Changes

File(s) Change Summary
CMakeLists.txt Added Logger.h and Logger.cpp to the common source group for build integration.
code/Common/Logger.cpp
include/cppcore/Common/Logger.h
Introduced a logging framework: singleton Logger, log stream abstraction, log level methods, helper macros, etc.
include/cppcore/Common/TStringBase.h Added += operators and index operator; increased buffer size; refactored copyFrom; minor signature correction.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Logger (Singleton)
    participant LogStream(s)

    User->>Logger (Singleton): log_<level>(domain, message)
    Logger (Singleton)->>Logger (Singleton): Format message (add domain, severity, trace info)
    Logger (Singleton)->>LogStream(s): Write formatted message
Loading

Estimated code review effort

3 (~45 minutes)

Poem

In the land of code where rabbits dwell,
A logger hops in, with stories to tell.
Streams and macros, all in a row,
Trace and debug, let messages flow!
Strings grow larger, with operators new—
The burrow’s now brighter, thanks to this crew.
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (3)
code/Common/Logger.cpp (2)

256-270: Implement getDateTime functionality

The getDateTime method is stubbed out and always returns "none", making the timestamp feature non-functional.

Would you like me to implement a proper datetime formatting function using standard C++ chrono library? This would provide actual timestamps for log messages when PrintMode::WithDateTime is used.


48-55: Optimize stripFilename for cross-platform compatibility

The current implementation only handles forward slashes and could be more efficient.

Consider using std::filesystem for better cross-platform support:

-static ::std::string stripFilename(const ::std::string &filename) {
-    if (filename.empty()) {
-        return filename;
-    }
-
-    ::std::string::size_type pos = filename.find_last_of("/");
-    if (pos == ::std::string::npos) {
-        return filename;
-    }
-    const ::std::string strippedName = filename.substr(pos + 1, filename.size() - pos - 1);
-
-    return strippedName;
-}
+static ::std::string stripFilename(const ::std::string &filename) {
+    if (filename.empty()) {
+        return filename;
+    }
+    // Handle both forward and backward slashes
+    ::std::string::size_type pos = filename.find_last_of("/\\");
+    if (pos == ::std::string::npos) {
+        return filename;
+    }
+    return filename.substr(pos + 1);
+}
include/cppcore/Common/Logger.h (1)

207-252: Fix documentation inconsistencies

The documentation for the logging macros references osre_trace, osre_debug, etc., but the actual macro names are log_trace, log_debug, etc.

Update the documentation to match the actual macro names:

-///	@fn		osre_trace
+///	@fn		log_trace

And fix the typo "writhe" → "write" in lines 234, 242, and 250.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4d2c0c and 0b0c425.

📒 Files selected for processing (4)
  • CMakeLists.txt (1 hunks)
  • code/Common/Logger.cpp (1 hunks)
  • include/cppcore/Common/Logger.h (1 hunks)
  • include/cppcore/Common/TStringBase.h (3 hunks)
🔇 Additional comments (2)
CMakeLists.txt (1)

78-79: Build configuration looks good!

The Logger header and source files are correctly added to the cppcore_common_src group, maintaining consistency with the project structure.

include/cppcore/Common/Logger.h (1)

143-143: Update default parameter after fixing enum typo

After fixing the WhithoutDateTime typo, update this line as well.

Comment on lines 162 to 182
inline void TStringBase<T>::copyFrom(TStringBase<T> &base, const T *ptr, size_t size) {
if (ptr != nullptr) {
T *targetPtr = base.mBuffer;
if (size > 0) {
if (size > base.mCapacity) {
if (base.mStringBuffer != nullptr) {
delete [] base.mStringBuffer;
}
base.mStringBuffer = new T[size];
base.mCapacity = size;
targetPtr = base.mStringBuffer;
}
memcpy(targetPtr, ptr, size * sizeof(T));
base.mSize = size;
if (ptr == nullptr) {
return;
}

T *targetPtr = base.mBuffer;
if (size == 0) {
return;
}

if (size > base.mCapacity) {
if (base.mStringBuffer != nullptr) {
delete [] base.mStringBuffer;
}
base.mStringBuffer = new T[size];
base.mCapacity = size;
targetPtr = base.mStringBuffer;
}
memcpy(targetPtr, ptr, size * sizeof(T));
base.mSize = size;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

copyFrom doesn't ensure null termination

The copyFrom method uses memcpy but doesn't ensure null termination for C-style strings, which could lead to issues when using c_str().

Add null termination after copying:

     memcpy(targetPtr, ptr, size * sizeof(T));
     base.mSize = size;
+    // Ensure null termination
+    if (base.mStringBuffer != nullptr) {
+        base.mStringBuffer[size] = '\0';
+    } else if (size < InitSize) {
+        base.mBuffer[size] = '\0';
+    }

Also, when allocating mStringBuffer, allocate size + 1 to accommodate the null terminator:

-        base.mStringBuffer = new T[size];
+        base.mStringBuffer = new T[size + 1];
-        base.mCapacity = size;
+        base.mCapacity = size + 1;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
inline void TStringBase<T>::copyFrom(TStringBase<T> &base, const T *ptr, size_t size) {
if (ptr != nullptr) {
T *targetPtr = base.mBuffer;
if (size > 0) {
if (size > base.mCapacity) {
if (base.mStringBuffer != nullptr) {
delete [] base.mStringBuffer;
}
base.mStringBuffer = new T[size];
base.mCapacity = size;
targetPtr = base.mStringBuffer;
}
memcpy(targetPtr, ptr, size * sizeof(T));
base.mSize = size;
if (ptr == nullptr) {
return;
}
T *targetPtr = base.mBuffer;
if (size == 0) {
return;
}
if (size > base.mCapacity) {
if (base.mStringBuffer != nullptr) {
delete [] base.mStringBuffer;
}
base.mStringBuffer = new T[size];
base.mCapacity = size;
targetPtr = base.mStringBuffer;
}
memcpy(targetPtr, ptr, size * sizeof(T));
base.mSize = size;
}
inline void TStringBase<T>::copyFrom(TStringBase<T> &base, const T *ptr, size_t size) {
if (ptr == nullptr) {
return;
}
T *targetPtr = base.mBuffer;
if (size == 0) {
return;
}
if (size > base.mCapacity) {
if (base.mStringBuffer != nullptr) {
delete [] base.mStringBuffer;
}
// Allocate an extra slot for the null terminator
base.mStringBuffer = new T[size + 1];
base.mCapacity = size + 1;
targetPtr = base.mStringBuffer;
}
memcpy(targetPtr, ptr, size * sizeof(T));
base.mSize = size;
// Ensure null termination
if (base.mStringBuffer != nullptr) {
base.mStringBuffer[size] = '\0';
} else if (size < InitSize) {
base.mBuffer[size] = '\0';
}
}
🤖 Prompt for AI Agents
In include/cppcore/Common/TStringBase.h lines 162 to 182, the copyFrom method
copies data using memcpy but does not ensure null termination for C-style
strings, which can cause issues with c_str(). Fix this by allocating
mStringBuffer with size + 1 when resizing, and after copying, explicitly set the
character at index size to the null terminator to guarantee proper string
termination.

Comment on lines +203 to +212
template <class T>
inline TStringBase<T> &TStringBase<T>::operator += (const TStringBase<T> &rhs) {
if (rhs.isEmpty()) {
return *this;
}

copyFrom(*this, rhs.c_str(), rhs.size());

return *this;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

operator+= replaces content instead of appending

The operator+= implementation uses copyFrom which replaces the entire string content rather than appending to it. This is incorrect behavior for a concatenation operator.

The operator should append the content, not replace it. Consider implementing proper string concatenation logic that:

  1. Calculates the new total size
  2. Reallocates if necessary
  3. Copies the existing content and appends the new content
  4. Updates the size accordingly
🤖 Prompt for AI Agents
In include/cppcore/Common/TStringBase.h around lines 203 to 212, the operator+=
incorrectly replaces the string content instead of appending. To fix this,
modify the operator to calculate the new total size by adding the current size
and rhs size, reallocate the internal buffer if needed to accommodate the new
size, copy the existing content followed by the rhs content into the buffer, and
update the size member to reflect the concatenated string length before
returning *this.

Comment on lines +220 to +223
template <class T>
inline T TStringBase<T>::operator[](size_t index) const {
return mBuffer[index];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add bounds checking to operator[]

The index operator doesn't validate the index against the string size, which could lead to out-of-bounds access.

Add bounds checking:

 template <class T>
 inline T TStringBase<T>::operator[](size_t index) const {
+    if (index >= mSize) {
+        // Handle error - throw exception or return default value
+        throw std::out_of_range("Index out of bounds");
+    }
-    return mBuffer[index];
+    return c_str()[index];
}

Also note that the current implementation always returns from mBuffer, but it should use c_str() to handle cases where mStringBuffer is in use.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template <class T>
inline T TStringBase<T>::operator[](size_t index) const {
return mBuffer[index];
}
template <class T>
inline T TStringBase<T>::operator[](size_t index) const {
if (index >= mSize) {
// Handle error - throw exception or return default value
throw std::out_of_range("Index out of bounds");
}
return c_str()[index];
}
🤖 Prompt for AI Agents
In include/cppcore/Common/TStringBase.h around lines 220 to 223, the operator[]
lacks bounds checking and always accesses mBuffer directly, which risks
out-of-bounds errors and ignores cases where mStringBuffer is used. Modify
operator[] to first check if the index is within the valid range of the string
size, throwing an exception or handling the error if not. Then, access the
character via c_str() instead of mBuffer to correctly handle both buffer storage
scenarios.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
code/Common/Logger.cpp (2)

156-160: Refactor fragile indentation logic.

The hardcoded character positions (6, 7) for detecting indentation markers remain fragile and should be refactored as previously suggested.


184-188: Refactor fragile indentation logic.

The hardcoded character positions (6, 7) for detecting indentation markers remain fragile and should be refactored as previously suggested.

🧹 Nitpick comments (4)
code/Common/Logger.cpp (4)

83-106: Consider thread safety for the singleton pattern.

The singleton implementation is correct for single-threaded use. For multi-threaded environments, consider using std::once_flag or similar mechanisms to ensure thread-safe initialization.


138-148: Simplify the verbosity condition.

The condition for info() can be simplified since it covers most verbosity modes except potentially a hypothetical "Silent" mode.

Consider simplifying to:

-if (getVerboseMode() == VerboseMode::Normal || getVerboseMode() == VerboseMode::Verbose || getVerboseMode() == VerboseMode::Debug || getVerboseMode() == VerboseMode::Trace) {
+if (getVerboseMode() != VerboseMode::Silent) { // assuming Silent mode exists

Or use a numeric comparison if verbosity levels are ordered.


231-236: Consider ownership semantics for log streams.

The unregisterLogStream method deletes the stream, which assumes the Logger owns all registered streams. This could cause issues if streams are shared or managed externally. Consider documenting this ownership model or providing separate methods for owned vs. unowned streams.


272-312: Consider refactoring to reduce code duplication.

All helper print functions follow the same pattern. Consider extracting the common logic into a template or helper function to reduce duplication.

Example approach:

template<typename LogMethod>
void printHelper(LogMethod method, const String &domain, const String &file, int line, const String &msg) {
    String message = msg;
    addTraceInfo(file, line, message);
    (Logger::getInstance()->*method)(domain, message);
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b0c425 and 123a525.

📒 Files selected for processing (3)
  • code/Common/Logger.cpp (1 hunks)
  • include/cppcore/Common/Logger.h (1 hunks)
  • include/cppcore/Common/TStringBase.h (3 hunks)
🪛 GitHub Actions: CMake
code/Common/Logger.cpp

[warning] 253-253: Compiler warning: unused variable ‘Space’ [-Wunused-variable]

🚧 Files skipped from review as they are similar to previous changes (2)
  • include/cppcore/Common/TStringBase.h
  • include/cppcore/Common/Logger.h
🧰 Additional context used
🪛 GitHub Actions: CMake
code/Common/Logger.cpp

[warning] 253-253: Compiler warning: unused variable ‘Space’ [-Wunused-variable]

🔇 Additional comments (7)
code/Common/Logger.cpp (7)

1-30: LGTM!

The license header and includes are properly structured and appropriate for the logger implementation.


32-69: Well-implemented helper functions.

The static helper functions are correctly implemented with proper error handling:

  • appendDomain safely handles empty domains
  • stripFilename properly handles edge cases
  • addTraceInfo conditionally adds trace information based on verbosity mode

71-82: LGTM!

The AbstractLogStream methods are correctly implemented for managing stream activation state.


108-114: LGTM!

Simple and correct getter/setter implementation for verbosity mode.


239-250: LGTM!

Constructor and destructor are properly implemented, with consistent ownership semantics for managing log streams.


268-270: LGTM!

Simple and correct implementation of standard output stream.


314-315: LGTM!

Proper namespace closing.

}

String Logger::getDateTime() {
static const uint32_t Space = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix unused variable warning.

The variable Space is declared but unused since the DateTime implementation is commented out. Either implement the DateTime functionality or remove the unused variable to fix the compiler warning.

-    static const uint32_t Space = 2;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static const uint32_t Space = 2;
🧰 Tools
🪛 GitHub Actions: CMake

[warning] 253-253: Compiler warning: unused variable ‘Space’ [-Wunused-variable]

🤖 Prompt for AI Agents
In code/Common/Logger.cpp at line 253, the variable 'Space' is declared but
unused because the DateTime implementation is commented out. To fix the compiler
warning, either remove the declaration of 'Space' if the DateTime functionality
is not needed, or uncomment and implement the DateTime code that uses 'Space' so
the variable is utilized.

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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.

2 participants