From 8d45280bed2261f3a00ca2e51082e5f7551adf77 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Mon, 1 Jun 2026 09:45:58 +0300 Subject: [PATCH 1/2] fix(mdbx): restore optional build MDBX support was hidden behind an opt-in flag, so CI did not compile the backend test or the example path. The backend also relied on private Logger internals and lacked the value serialization contract required by mdbx-containers. Constraint: keep vendored mdbx-containers unchanged Directive: LOGIT_WITH_MDBX requires C++17 or newer Confidence: high Scope-risk: moderate Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 23 +++++++++++++ CMakeLists.txt | 6 +++- examples/example_logit_mdbx_logger.cpp | 2 +- include/logit_cpp/logit/Logger.hpp | 16 +++++++++ include/logit_cpp/logit/log_macros.hpp | 7 +--- .../logit_cpp/logit/loggers/MdbxLogger.hpp | 33 +++++++++++++++++++ 6 files changed, 79 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 937b14c..1840665 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,29 @@ jobs: build/Testing/Temporary/LastTest.log if-no-files-found: ignore + linux-mdbx: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - run: git submodule update --init --recursive + - name: Configure MDBX + run: cmake -S . -B build-mdbx -DLOGIT_CPP_BUILD_TESTS=ON -DLOGIT_CPP_BUILD_EXAMPLES=ON -DLOGIT_WITH_MDBX=ON -DLOGIT_USE_SUBMODULES=ON -DCMAKE_CXX_STANDARD=17 + - name: Build MDBX + run: cmake --build build-mdbx + - name: Test MDBX + run: ctest --test-dir build-mdbx --output-on-failure -R mdbx_logger_test + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: logs-mdbx + path: | + build-mdbx/CMakeFiles/CMakeOutput.log + build-mdbx/Testing/Temporary/LastTest.log + if-no-files-found: ignore + windows: runs-on: windows-latest strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt index b6e932c..2efdaba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ option(LOGIT_USE_MPSC_RING "Enable lock-free TaskExecutor queue" ON) option(LOGIT_ENABLE_DROP_OLDEST_SLOWPATH "Enable TaskExecutor DropOldest slow-path" ON) if(NOT DEFINED CMAKE_CXX_STANDARD) - if(LOGIT_WITH_OTLP OR LOGIT_WITH_PROMETHEUS_SERVER) + if(LOGIT_WITH_OTLP OR LOGIT_WITH_PROMETHEUS_SERVER OR LOGIT_WITH_MDBX) set(CMAKE_CXX_STANDARD 17) else() set(CMAKE_CXX_STANDARD 11) @@ -33,6 +33,10 @@ if(NOT DEFINED CMAKE_CXX_STANDARD) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) +if(LOGIT_WITH_MDBX AND CMAKE_CXX_STANDARD LESS 17) + message(FATAL_ERROR "LOGIT_WITH_MDBX requires C++17 or newer.") +endif() + # Dependency: TimeShield find_package(TimeShield 1.0.6 QUIET CONFIG) if(NOT TimeShield_FOUND) diff --git a/examples/example_logit_mdbx_logger.cpp b/examples/example_logit_mdbx_logger.cpp index 5641b2f..d8c36d2 100644 --- a/examples/example_logit_mdbx_logger.cpp +++ b/examples/example_logit_mdbx_logger.cpp @@ -63,7 +63,7 @@ int main() { ("[%l] %v")); // The MDBX logger is now the last added backend; its index is: - const int mdbx_index = static_cast(logit::Logger::get_instance().get_all_strategy_snapshots().size()) - 1; + const int mdbx_index = static_cast(logit::Logger::get_instance().logger_count()) - 1; // Also add a console logger for live observation (optional). LOGIT_ADD_CONSOLE_DEFAULT(); diff --git a/include/logit_cpp/logit/Logger.hpp b/include/logit_cpp/logit/Logger.hpp index dcd3a66..5b48916 100644 --- a/include/logit_cpp/logit/Logger.hpp +++ b/include/logit_cpp/logit/Logger.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #if __cplusplus >= 201703L #include @@ -398,6 +399,21 @@ namespace logit { } } + /// \brief Returns the number of registered logger strategies. + std::size_t logger_count() const { + LoggerReadLock lock(m_loggers_mx); + return m_loggers.size(); + } + + /// \brief Retrieves a typed backend pointer from a logger by index. + template + LoggerT* get_logger_as(int logger_index) const { + auto strategy = get_strategy_snapshot(logger_index); + return (strategy && strategy->logger) + ? dynamic_cast(strategy->logger.get()) + : nullptr; + } + /// \brief Shuts down logger system. /// /// Disables further logging, waits for asynchronous tasks to complete, diff --git a/include/logit_cpp/logit/log_macros.hpp b/include/logit_cpp/logit/log_macros.hpp index 9d65ea4..4080976 100644 --- a/include/logit_cpp/logit/log_macros.hpp +++ b/include/logit_cpp/logit/log_macros.hpp @@ -2910,12 +2910,7 @@ static_assert(LOGIT_LEVEL_FATAL == static_cast(logit::LogLevel::LOG_LVL_FAT /// \param logger_type Concrete logger type (e.g., logit::MdbxLogger). /// \return Pointer to the backend, or nullptr if index/type does not match. #define LOGIT_GET_LOGGER_AS(logger_index, logger_type) \ - ([](int _logit_logger_index) -> logger_type* { \ - auto _logit_strategy = ::logit::Logger::get_instance().get_strategy_snapshot(_logit_logger_index); \ - return (_logit_strategy && _logit_strategy->logger) \ - ? dynamic_cast(_logit_strategy->logger.get()) \ - : nullptr; \ - }((logger_index))) + (::logit::Logger::get_instance().get_logger_as((logger_index))) /// \brief Executes a code block when the logger backend has the requested type. /// \param logger_index Index of logger. diff --git a/include/logit_cpp/logit/loggers/MdbxLogger.hpp b/include/logit_cpp/logit/loggers/MdbxLogger.hpp index 75047d0..79b9cab 100644 --- a/include/logit_cpp/logit/loggers/MdbxLogger.hpp +++ b/include/logit_cpp/logit/loggers/MdbxLogger.hpp @@ -384,6 +384,9 @@ namespace logit { int64_t end_time_ms = 0; uint64_t process_id = 0; uint32_t schema_version = 1; + + std::vector to_bytes() const; + static Session from_bytes(const void* data, size_t size); }; struct Record { @@ -396,12 +399,18 @@ namespace logit { std::string file; std::string function; int line = 0; + + std::vector to_bytes() const; + static Record from_bytes(const void* data, size_t size); }; struct Payload { uint64_t payload_id = 0; MdbxPayloadCompression compression = MdbxPayloadCompression::None; std::string data; + + std::vector to_bytes() const; + static Payload from_bytes(const void* data, size_t size); }; typedef mdbxc::KeyValueTable SessionTable; @@ -905,6 +914,30 @@ namespace logit { } }; + inline std::vector MdbxLogger::Session::to_bytes() const { + return MdbxLogger::serialize_session(*this); + } + + inline MdbxLogger::Session MdbxLogger::Session::from_bytes(const void* data, size_t size) { + return MdbxLogger::deserialize_session(data, size); + } + + inline std::vector MdbxLogger::Record::to_bytes() const { + return MdbxLogger::serialize_record(*this); + } + + inline MdbxLogger::Record MdbxLogger::Record::from_bytes(const void* data, size_t size) { + return MdbxLogger::deserialize_record(data, size); + } + + inline std::vector MdbxLogger::Payload::to_bytes() const { + return MdbxLogger::serialize_payload(*this); + } + + inline MdbxLogger::Payload MdbxLogger::Payload::from_bytes(const void* data, size_t size) { + return MdbxLogger::deserialize_payload(data, size); + } + } // namespace logit #endif // _LOGIT_MDBX_LOGGER_HPP_INCLUDED From 6c26fa6476a8871226b0ba279784cb58ef6038cc Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Mon, 1 Jun 2026 10:35:02 +0300 Subject: [PATCH 2/2] fix(mdbx): preserve const backend lookup The typed Logger backend accessor should not expose a mutable backend pointer through a const Logger instance. Split it into mutable and const overloads so the public API matches the registry constness. Constraint: keep existing mutable macro behavior unchanged Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 4.8 --- include/logit_cpp/logit/Logger.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/logit_cpp/logit/Logger.hpp b/include/logit_cpp/logit/Logger.hpp index 5b48916..cb5298f 100644 --- a/include/logit_cpp/logit/Logger.hpp +++ b/include/logit_cpp/logit/Logger.hpp @@ -407,13 +407,22 @@ namespace logit { /// \brief Retrieves a typed backend pointer from a logger by index. template - LoggerT* get_logger_as(int logger_index) const { + LoggerT* get_logger_as(int logger_index) { auto strategy = get_strategy_snapshot(logger_index); return (strategy && strategy->logger) ? dynamic_cast(strategy->logger.get()) : nullptr; } + /// \brief Retrieves a typed backend pointer from a logger by index. + template + const LoggerT* get_logger_as(int logger_index) const { + auto strategy = get_strategy_snapshot(logger_index); + return (strategy && strategy->logger) + ? dynamic_cast(strategy->logger.get()) + : nullptr; + } + /// \brief Shuts down logger system. /// /// Disables further logging, waits for asynchronous tasks to complete,