From 2f3e61c1f5d9bef07f4c71cf8a0c8eb8330c99ea Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sat, 15 Mar 2025 09:48:51 +0000 Subject: [PATCH] Add SetLogLevel() to the public API While the callback can filter log messages to the desired level, setting the log level in libloot means that it can avoid doing work to construct error messages that may then be discarded. --- include/loot/api.h | 9 +++++++++ src/api/api.cpp | 2 ++ src/api/helpers/logging.cpp | 27 +++++++++++++++++++++++++++ src/api/helpers/logging.h | 2 ++ src/tests/api/interface/main.cpp | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/include/loot/api.h b/include/loot/api.h index 2984aa4b..f3baa6ac 100644 --- a/include/loot/api.h +++ b/include/loot/api.h @@ -57,6 +57,15 @@ namespace loot { LOOT_API void SetLoggingCallback( std::function callback); +/** + * @brief Set the log severity level. + * @details The default level setting is trace. This function has no effect if + * no logging callback has been set. + * @param level + * Messages of this severity level and higher will be logged. + */ +LOOT_API void SetLogLevel(LogLevel level); + /** * @} * @name Version Functions diff --git a/src/api/api.cpp b/src/api/api.cpp index c08ccedf..2ce689ad 100644 --- a/src/api/api.cpp +++ b/src/api/api.cpp @@ -90,6 +90,8 @@ LOOT_API void SetLoggingCallback( spdlog::register_logger(logger); } +LOOT_API void SetLogLevel(LogLevel level) { setLoggerLevel(level); } + LOOT_API bool IsCompatible(const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int) { diff --git a/src/api/helpers/logging.cpp b/src/api/helpers/logging.cpp index c13293d1..41712dd0 100644 --- a/src/api/helpers/logging.cpp +++ b/src/api/helpers/logging.cpp @@ -51,6 +51,26 @@ LogLevel mapFromSpdlog(spdlog::level::level_enum severity) { } } +spdlog::level::level_enum mapToSpdlog(LogLevel severity) { + using spdlog::level::level_enum; + switch (severity) { + case LogLevel::trace: + return level_enum::trace; + case LogLevel::debug: + return level_enum::debug; + case LogLevel::info: + return level_enum::info; + case LogLevel::warning: + return level_enum::warn; + case LogLevel::error: + return level_enum::err; + case LogLevel::fatal: + return level_enum::critical; + default: + return level_enum::trace; + } +} + class SpdLoggingSink : public spdlog::sinks::base_sink { public: explicit SpdLoggingSink(std::function callback) { @@ -83,4 +103,11 @@ std::shared_ptr createLogger( return logger; } + +void setLoggerLevel(LogLevel level) { + auto logger = getLogger(); + if (logger) { + logger->set_level(mapToSpdlog(level)); + } +} } diff --git a/src/api/helpers/logging.h b/src/api/helpers/logging.h index a948c4e4..cce669b0 100644 --- a/src/api/helpers/logging.h +++ b/src/api/helpers/logging.h @@ -33,6 +33,8 @@ std::shared_ptr getLogger(); std::shared_ptr createLogger( std::function callback); + +void setLoggerLevel(LogLevel level); } #endif diff --git a/src/tests/api/interface/main.cpp b/src/tests/api/interface/main.cpp index 405173f4..34ffffd5 100644 --- a/src/tests/api/interface/main.cpp +++ b/src/tests/api/interface/main.cpp @@ -122,5 +122,37 @@ TEST(SetLoggingCallback, SetLoggingCallback([](LogLevel, const char *) {}); } } + +TEST(SetLogLevel, shouldOnlyRunTheCallbackForMessagesAtOrAboveTheGivenLevel) { + std::vector> loggedMessages; + auto callback = [&](LogLevel level, const char *string) { + loggedMessages.push_back(std::make_pair(level, std::string(string))); + }; + SetLoggingCallback(callback); + SetLogLevel(LogLevel::fatal); + + try { + CreateGameHandle(GameType::tes4, "dummy"); + FAIL(); + } catch (...) { + EXPECT_TRUE(loggedMessages.empty()); + } + + SetLogLevel(LogLevel::info); + + try { + CreateGameHandle(GameType::tes4, "dummy"); + FAIL(); + } catch (...) { + ASSERT_EQ(1, loggedMessages.size()); + EXPECT_EQ(LogLevel::info, loggedMessages[0].first); + EXPECT_EQ( + "Attempting to create a game handle for game type \"The Elder Scrolls " + "IV: Oblivion\" with game path \"dummy\" and game local path \"\"", + loggedMessages[0].second); + + SetLoggingCallback([](LogLevel, const char *) {}); + } +} } }