diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index a8e3541cd..1bb076299 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -16,6 +16,8 @@ #include "game_list_p.h" #include "ui_settings.h" +REGISTER_LOGGER("Class Name"); + GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) { this->gamelist = gamelist; edit_filter_text_old = ""; @@ -198,6 +200,7 @@ GameList::GameList(GMainWindow* parent) : QWidget{parent} { watcher = new QFileSystemWatcher(this); connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); + SPDLOG_WARNING("Test! {1} {0}", "world!", "Hello"); this->main_window = parent; layout = new QVBoxLayout; tree_view = new QTreeView; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c229aceec..c8dfafb24 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -28,9 +28,11 @@ set(SRCS break_points.cpp file_util.cpp hash.cpp - logging/filter.cpp - logging/text_formatter.cpp logging/backend.cpp + logging/backend_spdlog.cpp + logging/filter.cpp + logging/formatter.cpp + logging/text_formatter.cpp memory_util.cpp microprofile.cpp misc.cpp @@ -57,10 +59,12 @@ set(HEADERS file_util.h hash.h linear_disk_cache.h - logging/text_formatter.h - logging/filter.h - logging/log.h logging/backend.h + logging/backend_spdlog.h + logging/filter.h + logging/formatter.h + logging/log.h + logging/text_formatter.h math_util.h memory_util.h microprofile.h diff --git a/src/common/logging/backend_spdlog.cpp b/src/common/logging/backend_spdlog.cpp new file mode 100644 index 000000000..91f803c0b --- /dev/null +++ b/src/common/logging/backend_spdlog.cpp @@ -0,0 +1,87 @@ +#include "common/assert.h" +#include "common/logging/backend_spdlog.h" +#include "common/logging/formatter.h" +#include "common/string_util.h" + +namespace Log { + +SpdLogBackend& SpdLogBackend::instance() { + static SpdLogBackend instance; + return instance; +} + +SpdLogBackend::SpdLogBackend() { + // setup the custom citra formatter + spdlog::set_formatter(std::make_shared()); + + // Define the sinks to be passed to the loggers + // true means truncate file + auto file_sink = std::make_shared("citra_log.txt", true); +#ifdef _WIN32 + auto color_sink = std::make_shared(); +#else + auto stderr_sink = spdlog::sinks::stderr_sink_mt::instance(); + auto color_sink = std::make_shared(stderr_sink); +#endif + sinks.push_back(file_sink); + sinks.push_back(color_sink); +} + +SpdLogBackend::~SpdLogBackend() { + spdlog::drop_all(); +} + +const std::shared_ptr SpdLogBackend::GetLogger(u32 logger) const { + return loggers[logger]; +} + +u32 SpdLogBackend::RegisterLogger(const char* class_name) { + loggers.push_back(std::make_shared(class_name, sinks.begin(), sinks.end())); + return loggers.size() - 1; +} + +spdlog::level_t GetLevel(Level log_level) { + switch (log_level) { + case Level::Trace: + return spdlog::level::trace; + case Level::Debug: + return spdlog::level::debug; + case Level::Info: + return spdlog::level::info; + case Level::Warning: + return spdlog::level::warn; + case Level::Error: + return spdlog::level::err; + case Level::Critical: + return spdlog::level::critical; + default: + UNREACHABLE(); + break; + } + return spdlog::level::off; +} + +template +void SpdLogMessage(u32 logger, Level log_level, const char* filename, unsigned int line_nr, + const char* function, const char* format, const Arg1& arg, const Args&... args) { + auto log = SpdLogBackend::instance().GetLogger(logger); + fmt::MemoryWriter formatting_buffer; + formatting_buffer << Common::TrimSourcePath(filename) << ':' << function << ':' << line_nr + << ": " << format; + log->log(GetLevel(log_level), formatting_buffer.c_str(), arg, args...); +} + +template +void SpdLogMessage(u32 logger, Level log_level, const char* filename, unsigned int line_nr, + const char* function, const T& msg) { + auto log = SpdLogBackend::instance().GetLogger(logger); + fmt::MemoryWriter formatting_buffer; + formatting_buffer << Common::TrimSourcePath(filename) << ':' << function << ':' << line_nr + << ": " << msg; + log->log(GetLevel(log_level), formatting_buffer.c_str()); +} + +u32 RegisterLogger(const char* class_name) { + return SpdLogBackend::instance().RegisterLogger(class_name); +} +}; // namespace Log diff --git a/src/common/logging/backend_spdlog.h b/src/common/logging/backend_spdlog.h new file mode 100644 index 000000000..934fd25ce --- /dev/null +++ b/src/common/logging/backend_spdlog.h @@ -0,0 +1,27 @@ +#include +#include +#include +#include "common/logging/log.h" + +namespace Log { + +class SpdLogBackend { +public: + static SpdLogBackend& instance(); + + SpdLogBackend(SpdLogBackend const&) = delete; + void operator=(SpdLogBackend const&) = delete; + + u32 RegisterLogger(const char* class_name); + + const std::shared_ptr GetLogger(u32 logger) const; + +private: + SpdLogBackend(); + + ~SpdLogBackend(); + + std::vector> loggers; + std::vector sinks; +}; +} // namespace Log \ No newline at end of file diff --git a/src/common/logging/formatter.cpp b/src/common/logging/formatter.cpp new file mode 100644 index 000000000..87db782c6 --- /dev/null +++ b/src/common/logging/formatter.cpp @@ -0,0 +1,48 @@ +#include +#include +#include "common/assert.h" +#include "common/logging/formatter.h" + +namespace Log { + +Formatter::Formatter() {} + +const char* GetLevelName(spdlog::level_t log_level) { + switch (log_level) { + case spdlog::level::trace: + return "Trace"; + case spdlog::level::debug: + return "Debug"; + case spdlog::level::info: + return "Info"; + case spdlog::level::warn: + return "Warn"; + case spdlog::level::err: + return "Error"; + case spdlog::level::critical: + return "Critical"; + default: + UNREACHABLE(); + return "UNREACHABLE"; + } +} + +void Formatter::format(spdlog::details::log_msg& msg) { + using std::chrono::steady_clock; + using std::chrono::duration_cast; + + static steady_clock::time_point time_origin = steady_clock::now(); + auto timestamp = duration_cast(steady_clock::now() - time_origin); + + unsigned int time_seconds = static_cast(timestamp.count() / 1000000); + unsigned int time_fractional = static_cast(timestamp.count() % 1000000); + + msg.formatted << '[' << fmt::pad(time_seconds, 4, ' ') << '.' + << fmt::pad(time_fractional, 6, '0') << "] "; + msg.formatted << *msg.logger_name << " <" << GetLevelName(msg.level) << "> "; + + msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); + msg.formatted.write(spdlog::details::os::eol, spdlog::details::os::eol_size); +} + +} // namespace Log \ No newline at end of file diff --git a/src/common/logging/formatter.h b/src/common/logging/formatter.h new file mode 100644 index 000000000..586334c96 --- /dev/null +++ b/src/common/logging/formatter.h @@ -0,0 +1,14 @@ +#include + +namespace Log { + +class Formatter : public spdlog::formatter { + +public: + explicit Formatter(); + Formatter(const Formatter&) = delete; + Formatter& operator=(const Formatter&) = delete; + void format(spdlog::details::log_msg& msg) override; +}; + +} // namespace Log \ No newline at end of file diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 1b905f66c..1a73e3343 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -106,6 +106,15 @@ void LogMessage(Class log_class, Level log_level, const char* filename, unsigned #endif ; +template +void SpdLogMessage(u32 logger, Level log_level, const char* filename, unsigned int line_nr, + const char* function, const char* format, const Arg1& arg, const Args&... args); +template +void SpdLogMessage(u32 logger, Level log_level, const char* filename, unsigned int line_nr, + const char* function, const T& msg); + +u32 RegisterLogger(const char* class_name); + } // namespace Log #define LOG_GENERIC(log_class, log_level, ...) \ @@ -128,3 +137,31 @@ void LogMessage(Class log_class, Level log_level, const char* filename, unsigned LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__) #define LOG_CRITICAL(log_class, ...) \ LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__) + +// Define the spdlog level macros + +#define REGISTER_LOGGER(class_name) static u32 _logger = ::Log::RegisterLogger(class_name) + +#ifdef _DEBUG +#define SPDLOG_TRACE(fmt, ...) \ + ::Log::SpdLogMessage(_logger, ::Log::Level::Trace, __FILE__, __LINE__, __func__, fmt, \ + ##__VA_ARGS__) +#else +#define SPDLOG_TRACE(fmt, ...) (void(0)) +#endif + +#define SPDLOG_DEBUG(fmt, ...) \ + ::Log::SpdLogMessage(_logger, ::Log::Level::Debug, __FILE__, __LINE__, __func__, fmt, \ + ##__VA_ARGS__) +#define SPDLOG_INFO(fmt, ...) \ + ::Log::SpdLogMessage(_logger, ::Log::Level::Info, __FILE__, __LINE__, __func__, fmt, \ + ##__VA_ARGS__) +#define SPDLOG_WARNING(fmt, ...) \ + ::Log::SpdLogMessage(_logger, ::Log::Level::Warning, __FILE__, __LINE__, __func__, fmt, \ + ##__VA_ARGS__) +#define SPDLOG_ERROR(fmt, ...) \ + ::Log::SpdLogMessage(_logger, ::Log::Level::Error, __FILE__, __LINE__, __func__, fmt, \ + ##__VA_ARGS__) +#define SPDLOG_CRITICAL(fmt, ...) \ + ::Log::SpdLogMessage(_logger, ::Log::Level::Critical, __FILE__, __LINE__, __func__, fmt, \ + ##__VA_ARGS__)