mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Replace logging API
Allow clients to provide a callback function that the LOOT API will use when logging. This provides more flexibility than the previous choice of outputting to an exclusive file or the console.
This commit is contained in:
+1
-1
@@ -187,7 +187,7 @@ set (LOOT_API_HEADERS "${CMAKE_SOURCE_DIR}/include/loot/api.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/exception/file_access_error.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/exception/git_state_error.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/enum/game_type.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/enum/log_verbosity.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/enum/log_level.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/enum/message_type.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/game_interface.h"
|
||||
"${CMAKE_SOURCE_DIR}/include/loot/loot_version.h"
|
||||
|
||||
+9
-15
@@ -25,6 +25,7 @@
|
||||
#ifndef LOOT_API_H
|
||||
#define LOOT_API_H
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@@ -36,7 +37,7 @@
|
||||
#include "loot/exception/file_access_error.h"
|
||||
#include "loot/exception/git_state_error.h"
|
||||
#include "loot/enum/game_type.h"
|
||||
#include "loot/enum/log_verbosity.h"
|
||||
#include "loot/enum/log_level.h"
|
||||
#include "loot/loot_version.h"
|
||||
|
||||
namespace loot {
|
||||
@@ -47,21 +48,14 @@ namespace loot {
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* @brief Set the API's logging verbosity.
|
||||
* @details The default is ``LogVerbosity::off``.
|
||||
* @param verbosity
|
||||
* The logging verbosity to set.
|
||||
* @brief Set the callback function that is called when logging.
|
||||
* @details If this function is not called, the default behaviour is to
|
||||
* print messages to the console.
|
||||
* @param callback
|
||||
* The function called when logging. The first parameter is the
|
||||
* level of the message being logged, and the second is the message.
|
||||
*/
|
||||
LOOT_API void SetLoggingVerbosity(LogVerbosity verbosity);
|
||||
|
||||
/**
|
||||
* @brief Set the file path that logging statements are written to.
|
||||
* @details If no file is set the default behaviour is to print logging
|
||||
* statements to the console.
|
||||
* @param path
|
||||
* The log file path.
|
||||
*/
|
||||
LOOT_API void SetLogFile(const std::string& path);
|
||||
LOOT_API void SetLoggingCallback(std::function<void(LogLevel, const char*)> callback);
|
||||
|
||||
/**@}*/
|
||||
/**********************************************************************//**
|
||||
|
||||
@@ -22,20 +22,23 @@ along with LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LOOT_LOG_VERBOSITY
|
||||
#define LOOT_LOG_VERBOSITY
|
||||
#ifndef LOOT_LOG_LEVEL
|
||||
#define LOOT_LOG_LEVEL
|
||||
|
||||
/**
|
||||
* The namespace used by the LOOT API.
|
||||
*/
|
||||
namespace loot {
|
||||
/**
|
||||
* @brief Codes used to specify different levels of API logging verbosity.
|
||||
* @brief Codes used to specify different levels of API logging.
|
||||
*/
|
||||
enum struct LogVerbosity : unsigned int {
|
||||
off,
|
||||
warning,
|
||||
enum struct LogLevel : unsigned int {
|
||||
trace,
|
||||
debug,
|
||||
info,
|
||||
warning,
|
||||
error,
|
||||
fatal
|
||||
};
|
||||
}
|
||||
|
||||
+45
-25
@@ -46,34 +46,54 @@ std::string ResolvePath(const std::string& path) {
|
||||
return fs::read_symlink(path).string();
|
||||
}
|
||||
|
||||
LOOT_API void SetLoggingVerbosity(LogVerbosity verbosity) {
|
||||
switch (verbosity) {
|
||||
case LogVerbosity::off:
|
||||
boost::log::core::get()->set_logging_enabled(false);
|
||||
break;
|
||||
case LogVerbosity::warning:
|
||||
boost::log::core::get()->set_filter(boost::log::trivial::severity > boost::log::trivial::warning);
|
||||
boost::log::core::get()->set_logging_enabled(true);
|
||||
break;
|
||||
case LogVerbosity::trace:
|
||||
boost::log::core::get()->reset_filter();
|
||||
boost::log::core::get()->set_logging_enabled(true);
|
||||
break;
|
||||
LogLevel mapFromBoostLog(boost::log::trivial::severity_level severity) {
|
||||
using boost::log::trivial::severity_level;
|
||||
switch (severity) {
|
||||
case severity_level::trace:
|
||||
return LogLevel::trace;
|
||||
case severity_level::debug:
|
||||
return LogLevel::debug;
|
||||
case severity_level::info:
|
||||
return LogLevel::info;
|
||||
case severity_level::warning:
|
||||
return LogLevel::warning;
|
||||
case severity_level::error:
|
||||
return LogLevel::error;
|
||||
case severity_level::fatal:
|
||||
return LogLevel::fatal;
|
||||
default:
|
||||
return LogLevel::trace;
|
||||
}
|
||||
}
|
||||
|
||||
LOOT_API void SetLogFile(const std::string& path) {
|
||||
boost::log::add_file_log(
|
||||
boost::log::keywords::file_name = path,
|
||||
boost::log::keywords::auto_flush = true,
|
||||
boost::log::keywords::format = (
|
||||
boost::log::expressions::stream
|
||||
<< "[" << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S.%f") << "]"
|
||||
<< " [" << boost::log::trivial::severity << "]: "
|
||||
<< boost::log::expressions::smessage
|
||||
)
|
||||
);
|
||||
boost::log::add_common_attributes();
|
||||
class LoggingSink : public boost::log::sinks::basic_formatted_sink_backend<char, boost::log::sinks::concurrent_feeding> {
|
||||
public:
|
||||
LoggingSink(std::function<void(LogLevel, const char*)> callback) {
|
||||
this->callback = callback;
|
||||
}
|
||||
|
||||
void consume(const boost::log::record_view& rec, const std::string& str) {
|
||||
using boost::log::trivial::severity_level;
|
||||
auto severity = rec.attribute_values()[boost::log::aux::default_attribute_names::severity()].extract<severity_level>();
|
||||
if (!severity) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(mapFromBoostLog(*severity), str.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(LogLevel, const char*)> callback;
|
||||
};
|
||||
|
||||
LOOT_API void SetLoggingCallback(std::function<void(LogLevel, const char*)> callback) {
|
||||
typedef boost::log::sinks::synchronous_sink<LoggingSink> sink_t;
|
||||
|
||||
auto sink_backend = boost::make_shared<LoggingSink>(callback);
|
||||
boost::shared_ptr<sink_t> sink(new sink_t(sink_backend));
|
||||
|
||||
boost::log::core::get()->remove_all_sinks();
|
||||
boost::log::core::get()->add_sink(sink);
|
||||
}
|
||||
|
||||
LOOT_API bool IsCompatible(const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int versionPatch) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "loot/api.h"
|
||||
#include "tests/api/interface/create_game_handle_test.h"
|
||||
#include "tests/api/interface/database_interface_test.h"
|
||||
#include "tests/api/interface/game_interface_test.h"
|
||||
@@ -33,15 +34,37 @@
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
//Set the locale to get encoding conversions working correctly.
|
||||
//Set the locale to get encoding conversions working correctly.
|
||||
std::locale::global(boost::locale::generator().generate(""));
|
||||
boost::filesystem::path::imbue(std::locale());
|
||||
loot::InitialiseLocale("");
|
||||
|
||||
//Disable logging or else stdout will get overrun.
|
||||
boost::log::core::get()->set_logging_enabled(false);
|
||||
loot::SetLoggingVerbosity(loot::LogVerbosity::off);
|
||||
//Set a null log callback or else stdout will get overrun.
|
||||
loot::SetLoggingCallback([](loot::LogLevel, const char *) {});
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
namespace loot {
|
||||
namespace test {
|
||||
TEST(SetLoggingCallback, shouldWriteMessagesToGivenCallback) {
|
||||
std::string loggedMessages;
|
||||
SetLoggingCallback([&](LogLevel level, const char * string) {
|
||||
loggedMessages += std::string(string);
|
||||
});
|
||||
|
||||
try {
|
||||
CreateGameHandle(GameType::tes4, "", "");
|
||||
}
|
||||
catch (...) {
|
||||
EXPECT_EQ("Initialising load order data for game of type 0 at: \"\"", loggedMessages);
|
||||
|
||||
SetLoggingCallback([](LogLevel, const char *) {});
|
||||
return;
|
||||
}
|
||||
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user