From c4e5e05b8d90893e71c39a7dd93447ba7592dc5c Mon Sep 17 00:00:00 2001 From: Pengfei Date: Fri, 10 Sep 2021 22:04:25 +0800 Subject: [PATCH] Overhauls the logging system Updated fmt to 8.0.0. This is now more compile-time, and outputs to stderr, file as well as a buffer. --- externals/fmt | 2 +- src/common/common_paths.h | 2 ++ src/common/logging/log.cpp | 47 ++++++++++++++++++++++++++++-- src/common/logging/log.h | 52 +++++++++++++++++++++------------- src/core/db/title_keys_bin.cpp | 2 +- src/core/importer.cpp | 8 ++++-- 6 files changed, 86 insertions(+), 27 deletions(-) diff --git a/externals/fmt b/externals/fmt index 7512a55..a58c133 160000 --- a/externals/fmt +++ b/externals/fmt @@ -1 +1 @@ -Subproject commit 7512a55aa3ae309587ca89668ef9ec4074a51a1f +Subproject commit a58c1338216d2b712f0bd231ec4229db88a06f90 diff --git a/src/common/common_paths.h b/src/common/common_paths.h index e518874..de6753f 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h @@ -25,6 +25,8 @@ #endif #define CITRA_EXECUTABLE "citra-qt" +#define LOG_FILE "threeSD.log.txt" + // Subdirs in the User dir returned by GetUserPath(UserPath::UserDir) #define CONFIG_DIR "config" #define CACHE_DIR "cache" diff --git a/src/common/logging/log.cpp b/src/common/logging/log.cpp index 7881687..dd0bdb0 100644 --- a/src/common/logging/log.cpp +++ b/src/common/logging/log.cpp @@ -3,9 +3,20 @@ // Refer to the license.txt file included. #include +#include +#ifdef _WIN32 +#include // For _SH_DENYWR +#else +#define _SH_DENYWR 0 +#endif + +#include "common/common_paths.h" +#include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" +namespace Common::Logging { + std::uint64_t GetLoggingTime() { static auto time_origin = std::chrono::steady_clock::now(); return std::chrono::duration_cast(std::chrono::steady_clock::now() - @@ -13,6 +24,38 @@ std::uint64_t GetLoggingTime() { .count(); } -std::string StandardizeLogClass(const std::string& log_class) { - return Common::ReplaceAll(log_class, "_", "."); +// _SH_DENYWR allows read-only access for other programs. For non-Windows it's defined to 0. +static FileUtil::IOFile g_log_file{LOG_FILE, "w", _SH_DENYWR}; + +static std::array g_error_buffer{}; +static int g_error_buffer_pos = 0; + +void WriteLog(Entry entry) { + // stderr + fmt::print(stderr, entry.style, entry.message); + + // log file + g_log_file.WriteString(entry.message); + if (entry.level >= Level::Error) { + g_log_file.Flush(); // Do not flush the file too often + } + + // log buffer + if (entry.level >= Level::Error) { + g_error_buffer[g_error_buffer_pos] = std::move(entry); + g_error_buffer_pos = (g_error_buffer_pos + 1) % g_error_buffer.size(); + } } + +std::string GetLastErrors() { + std::string output; + for (std::size_t i = 0; i < g_error_buffer.size(); ++i) { + const std::size_t pos = (g_error_buffer_pos + i) % g_error_buffer.size(); + if (g_error_buffer[pos].level != Level::Invalid) { + output.append(g_error_buffer[pos].message); + } + } + return output; +} + +} // namespace Common::Logging diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 2c0b03f..47691b6 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -12,37 +12,49 @@ #include #include -std::uint64_t GetLoggingTime(); -std::string StandardizeLogClass(const std::string& log_class); +namespace Common::Logging { -#define LOG_PRINT(log_class, level, text_style, file, line, func, format, ...) \ - { \ - fmt::print(stderr, text_style, "[{:12.6f}] {} <{}> {}:{}:{}: " format "\n", \ - GetLoggingTime() / 1000000.0, StandardizeLogClass(log_class), level, file, \ - line, func __VA_OPT__(, ) __VA_ARGS__); \ - fflush(stderr); \ - } +std::uint64_t GetLoggingTime(); + +enum Level { Invalid = 0, Trace, Debug, Info, Warning, Error, Critical }; +struct Entry { + Level level; + fmt::text_style style; + std::string message; +}; + +void WriteLog(Entry entry); + +// Returns up to 3 latest error messages +std::string GetLastErrors(); + +} // namespace Common::Logging + +#define HELPER_STR(line) #line +#define HELPER_STR2(line) HELPER_STR(line) +#define LOG_PRINT(log_class, level, text_style, format_str, ...) \ + Common::Logging::WriteLog( \ + Common::Logging::Entry{Common::Logging::Level::level, text_style, \ + fmt::format("[{:12.6f}] " log_class " <" #level "> " __FILE__ \ + ":" HELPER_STR2(__LINE__) ":{}: " format_str "\n", \ + Common::Logging::GetLoggingTime() / 1000000.0, \ + __func__ __VA_OPT__(, ) __VA_ARGS__)}); #ifdef _DEBUG #define LOG_TRACE(log_class, ...) \ - LOG_PRINT(#log_class, "Trace", fmt::fg(fmt::terminal_color::bright_black), __FILE__, __LINE__, \ + LOG_PRINT(#log_class, Trace, fmt::fg(fmt::terminal_color::bright_black), __FILE__, __LINE__, \ __func__, __VA_ARGS__) #else #define LOG_TRACE(log_class, fmt, ...) (void(0)) #endif #define LOG_DEBUG(log_class, ...) \ - LOG_PRINT(#log_class, "Debug", fmt::fg(fmt::terminal_color::cyan), __FILE__, __LINE__, \ - __func__, __VA_ARGS__) + LOG_PRINT(#log_class, Debug, fmt::fg(fmt::terminal_color::cyan), __VA_ARGS__) #define LOG_INFO(log_class, ...) \ - LOG_PRINT(#log_class, "Info", fmt::fg(fmt::terminal_color::white), __FILE__, __LINE__, \ - __func__, __VA_ARGS__) + LOG_PRINT(#log_class, Info, fmt::fg(fmt::terminal_color::white), __VA_ARGS__) #define LOG_WARNING(log_class, ...) \ - LOG_PRINT(#log_class, "Warning", fmt::fg(fmt::terminal_color::bright_yellow), __FILE__, \ - __LINE__, __func__, __VA_ARGS__) + LOG_PRINT(#log_class, Warning, fmt::fg(fmt::terminal_color::bright_yellow), __VA_ARGS__) #define LOG_ERROR(log_class, ...) \ - LOG_PRINT(#log_class, "Error", fmt::fg(fmt::terminal_color::bright_red), __FILE__, __LINE__, \ - __func__, __VA_ARGS__) + LOG_PRINT(#log_class, Error, fmt::fg(fmt::terminal_color::bright_red), __VA_ARGS__) #define LOG_CRITICAL(log_class, ...) \ - LOG_PRINT(#log_class, "Critical", fmt::fg(fmt::terminal_color::bright_magenta), __FILE__, \ - __LINE__, __func__, __VA_ARGS__) + LOG_PRINT(#log_class, Critical, fmt::fg(fmt::terminal_color::bright_magenta), __VA_ARGS__) diff --git a/src/core/db/title_keys_bin.cpp b/src/core/db/title_keys_bin.cpp index bd053b7..1287448 100644 --- a/src/core/db/title_keys_bin.cpp +++ b/src/core/db/title_keys_bin.cpp @@ -30,7 +30,7 @@ bool LoadTitleKeysBin(TitleKeysMap& out, const std::string& path) { } if (file.Tell() != file.GetSize()) { - LOG_ERROR(Core, "File {} has redundant data, may be corrupted"); + LOG_ERROR(Core, "File {} has redundant data, may be corrupted", path); return false; } return true; diff --git a/src/core/importer.cpp b/src/core/importer.cpp index d8e704d..85c9451 100644 --- a/src/core/importer.cpp +++ b/src/core/importer.cpp @@ -437,8 +437,9 @@ std::shared_ptr SDMCImporter::OpenContent(const ContentSpecifi const auto format_str = (specifier.id >> 32) == 0x0004008c ? "/title/{:08x}/{:08x}/content/00000000/{:08x}.app" : "/title/{:08x}/{:08x}/content/{:08x}.app"; - const auto path = - fmt::format(format_str, (specifier.id >> 32), (specifier.id & 0xFFFFFFFF), content_id); + const auto path = fmt::vformat( + format_str, + fmt::make_format_args((specifier.id >> 32), (specifier.id & 0xFFFFFFFF), content_id)); return std::make_shared(config.sdmc_path, path, "rb"); } } @@ -970,7 +971,8 @@ void SDMCImporter::ListExtdata(std::vector& out) const { } const u64 id = std::stoull(virtual_name, nullptr, 16); - const auto citra_path = fmt::format(citra_path_template, virtual_name); + const auto citra_path = + fmt::vformat(citra_path_template, fmt::make_format_args(virtual_name)); out.push_back({type, (id_high << 32) | id, FileUtil::Exists(citra_path), FileUtil::GetDirectoryTreeSize(directory + virtual_name + "/")}); return true;