From 84f43dbaecf5e01c8b3e899bb32e7dcfb3bdea20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Wed, 9 Jul 2025 14:33:47 +0200 Subject: [PATCH] wip: basic AnyLogHandler impl with pointer support --- libmamba/include/mamba/core/logging.hpp | 237 +++++++++++++++++++----- libmamba/src/core/logging.cpp | 7 - 2 files changed, 192 insertions(+), 52 deletions(-) diff --git a/libmamba/include/mamba/core/logging.hpp b/libmamba/include/mamba/core/logging.hpp index d200effe2..776371763 100644 --- a/libmamba/include/mamba/core/logging.hpp +++ b/libmamba/include/mamba/core/logging.hpp @@ -8,6 +8,7 @@ #define MAMBA_CORE_LOGGING_HPP #include +#include #include #include #include @@ -46,11 +47,12 @@ namespace mamba libsolv }; - auto name_of(log_source source) -> const char*; + /// @returns The name of the specified log source as an UTF-8 null-terminated string. + constexpr auto name_of(log_source source) -> const char*; /// @returns All `log_source` values as a range. - auto all_log_sources() -> std::initializer_list; + constexpr auto all_log_sources() -> std::initializer_list; namespace logging { @@ -60,7 +62,7 @@ namespace mamba struct LogRecord { - std::string message; + std::string message; // THINK: cool be made lazy if it was a function instead log_level level; log_source source; }; @@ -69,7 +71,7 @@ namespace mamba // NOTE: it might make more sense to talka bout sinks than sources when it comes to the // implementation - template + template concept LogHandler = std::movable and requires( T& handler, @@ -116,15 +118,18 @@ namespace mamba handler.flush(std::optional{}); }; + template + concept LogHandlerOrPtr = LogHandler or (std::is_pointer_v and LogHandler>); + class AnyLogHandler { public: - AnyLogHandler(); - ~AnyLogHandler(); + AnyLogHandler() = default; + ~AnyLogHandler() = default; - AnyLogHandler(AnyLogHandler&&); - AnyLogHandler& operator=(AnyLogHandler&&); + AnyLogHandler(AnyLogHandler&&) noexcept = default; + AnyLogHandler& operator=(AnyLogHandler&&) noexcept = default; template requires(not std::is_same_v, AnyLogHandler>) @@ -189,24 +194,25 @@ namespace mamba /// @returns An identifier for the stored object's type, or `std::nullopt` if there is /// no stored object (`has_value() == false`). - std::optional type_id() const; + auto type_id() const noexcept -> std::optional; private: struct Interface; - template - struct OwningImpl; + template + struct Wrapper; - template - struct NonOwningImpl; - - SBO_storage m_stored; + SBO_storage m_storage; }; static_assert(LogHandler); // NEEDED? AnyLogHandler must not recursively // host itself + //////////////////////////////////////////////////////////////////////////////// + // Logging System API + + // not thread-safe auto set_log_handler(AnyLogHandler handler, std::optional maybe_new_params = {}) @@ -292,7 +298,7 @@ namespace mamba::logging { // NOTE: the following definitions are inline for performance reasons. - inline auto name_of(log_source source) -> const char* + inline constexpr auto name_of(log_source source) -> const char* { switch (source) { @@ -305,10 +311,10 @@ namespace mamba::logging } // TODO(c++23): std::unreachable(); - return ""; + return "unknown"; } - inline auto all_log_sources() -> std::initializer_list + inline constexpr auto all_log_sources() -> std::initializer_list { return { log_source::libmamba, log_source::libcurl, log_source::libsolv }; } @@ -362,41 +368,182 @@ namespace mamba::logging virtual void set_log_level(log_level new_level) = 0; virtual void set_params(LoggingParams new_params) = 0; virtual void log(LogRecord record) noexcept = 0; - virtual void log_stacktrace(std::optional source = {}) noexcept = 0; - virtual void log_stacktrace_no_guards(std::optional source = {}) noexcept = 0; - virtual void flush(std::optional source = {}) noexcept = 0; - virtual std::optional type_id() const = 0; + virtual void log_stacktrace(std::optional source) noexcept = 0; + virtual void log_stacktrace_no_guards(std::optional source) noexcept = 0; + virtual void flush(std::optional source) noexcept = 0; + virtual std::type_index type_id() const = 0; }; template - struct AnyLogHandler::OwningImpl : Interface + T& as_ref(T& object) + { + return object; + } + + template + T& as_ref(T* object) + { + assert(object); + return *object; + } + + template + struct AnyLogHandler::Wrapper : Interface { T object; - void start_log_handling(LoggingParams params, std::vector sources) override; - void stop_log_handling() override; - void set_log_level(log_level new_level) override; - void set_params(LoggingParams new_params) override; - void log(LogRecord record) noexcept override; - void log_stacktrace(std::optional source = {}) noexcept override; - void log_stacktrace_no_guards(std::optional source = {}) noexcept override; - void flush(std::optional source = {}) noexcept override; - std::optional type_id() const override; + + void start_log_handling(LoggingParams params, std::vector sources) override + { + as_ref(object).start_log_handling(std::move(params), std::move(sources)); + } + + void stop_log_handling() override + { + as_ref(object).stop_log_handling(); + } + + void set_log_level(log_level new_level) override + { + as_ref(object).set_log_level(new_level); + } + + void set_params(LoggingParams new_params) override + { + as_ref(object).set_params(std::move(new_params)); + } + + void log(LogRecord record) noexcept override + { + as_ref(object).log(std::move(record)); + } + + void log_stacktrace(std::optional source) noexcept override + { + as_ref(object).log_stacktrace(std::move(source)); + } + + void log_stacktrace_no_guards(std::optional source) noexcept override + { + as_ref(object).log_stacktrace_no_guards(std::move(source)); + } + + void flush(std::optional source) noexcept override + { + as_ref(object).flush(std::move(source)); + } + + std::type_index type_id() const override + { + return typeid(object); + } }; - template - struct AnyLogHandler::NonOwningImpl : Interface + template + requires(not std::is_same_v, AnyLogHandler>) and LogHandler + AnyLogHandler::AnyLogHandler(T&& handler) + : m_storage(std::make_unique>(std::forward(handler))) { - T* object; - void start_log_handling(LoggingParams params, std::vector sources) override; - void stop_log_handling() override; - void set_log_level(log_level new_level) override; - void set_params(LoggingParams new_params) override; - void log(LogRecord record) noexcept override; - void log_stacktrace(std::optional source = {}) noexcept override; - void log_stacktrace_no_guards(std::optional source = {}) noexcept override; - void flush(std::optional source = {}) noexcept override; - std::optional type_id() const override; - }; + + } + + template + requires(not std::is_same_v, AnyLogHandler>) and LogHandler + AnyLogHandler::AnyLogHandler(T* handler_ptr) + : m_storage(std::make_unique>(handler_ptr)) + { + assert(handler_ptr); + } + + template + requires(not std::is_same_v, AnyLogHandler>) and LogHandler + AnyLogHandler& AnyLogHandler::operator=(T&& new_handler) + { + if (m_storage and typeid(T) == m_storage->type_id()) + { + static_cast*>(m_storage.get())->object = std::forward(new_handler); + } + else + { + m_storage = std::make_unique>(std::forward(new_handler)); + } + return *this; + } + + template + requires(not std::is_same_v, AnyLogHandler>) and LogHandler + AnyLogHandler& AnyLogHandler::operator=(T* new_handler_ptr) + { + assert(new_handler_ptr); + if (m_storage and typeid(T*) == m_storage->type_id()) + { + static_cast*>(m_storage.get())->object = new_handler_ptr; + } + else + { + m_storage = std::make_unique>(new_handler_ptr); + } + return *this; + } + + inline auto AnyLogHandler::start_log_handling(LoggingParams params, std::vector sources) -> void + { + assert(m_storage); + m_storage->start_log_handling(std::move(params), std::move(sources)); + } + + inline auto AnyLogHandler::stop_log_handling() -> void + { + assert(m_storage); + m_storage->stop_log_handling(); + } + + inline auto AnyLogHandler::set_log_level(log_level new_level) -> void + { + assert(m_storage); + m_storage->set_log_level(new_level); + } + + inline auto AnyLogHandler::set_params(LoggingParams new_params) -> void + { + assert(m_storage); + m_storage->set_params(new_params); + } + + inline auto AnyLogHandler::log(LogRecord record) noexcept -> void + { + assert(m_storage); + m_storage->log(std::move(record)); + } + + inline auto AnyLogHandler::log_stacktrace(std::optional source) noexcept -> void + { + assert(m_storage); + m_storage->log_stacktrace_no_guards(std::move(source)); + } + + inline auto + AnyLogHandler::log_stacktrace_no_guards(std::optional source) noexcept + -> void + { + assert(m_storage); + m_storage->log_stacktrace_no_guards(std::move(source)); + } + + inline auto AnyLogHandler::flush(std::optional source) noexcept -> void + { + assert(m_storage); + m_storage->flush(std::move(source)); + } + + inline auto AnyLogHandler::has_value() const noexcept -> bool + { + return m_storage ? true : false; + } + + inline auto AnyLogHandler::type_id() const noexcept -> std::optional + { + return m_storage ? std::make_optional(m_storage->type_id()) : std::nullopt; + } } diff --git a/libmamba/src/core/logging.cpp b/libmamba/src/core/logging.cpp index c067ab41e..873199d5e 100644 --- a/libmamba/src/core/logging.cpp +++ b/libmamba/src/core/logging.cpp @@ -113,13 +113,6 @@ namespace mamba::logging } - /////////////////////////////////////////////////////////////////// - // AnyLogHandler - - AnyLogHandler::AnyLogHandler() = default; - AnyLogHandler::~AnyLogHandler() = default; - - /////////////////////////////////////////////////////////////////// // MessageLogger