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.
This commit is contained in:
Pengfei
2021-09-10 22:04:25 +08:00
parent ecdbe63c47
commit c4e5e05b8d
6 changed files with 86 additions and 27 deletions
+1 -1
+2
View File
@@ -25,6 +25,8 @@
#endif #endif
#define CITRA_EXECUTABLE "citra-qt" #define CITRA_EXECUTABLE "citra-qt"
#define LOG_FILE "threeSD.log.txt"
// Subdirs in the User dir returned by GetUserPath(UserPath::UserDir) // Subdirs in the User dir returned by GetUserPath(UserPath::UserDir)
#define CONFIG_DIR "config" #define CONFIG_DIR "config"
#define CACHE_DIR "cache" #define CACHE_DIR "cache"
+45 -2
View File
@@ -3,9 +3,20 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <chrono> #include <chrono>
#include <cstdio>
#ifdef _WIN32
#include <share.h> // 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/logging/log.h"
#include "common/string_util.h" #include "common/string_util.h"
namespace Common::Logging {
std::uint64_t GetLoggingTime() { std::uint64_t GetLoggingTime() {
static auto time_origin = std::chrono::steady_clock::now(); static auto time_origin = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() -
@@ -13,6 +24,38 @@ std::uint64_t GetLoggingTime() {
.count(); .count();
} }
std::string StandardizeLogClass(const std::string& log_class) { // _SH_DENYWR allows read-only access for other programs. For non-Windows it's defined to 0.
return Common::ReplaceAll(log_class, "_", "."); static FileUtil::IOFile g_log_file{LOG_FILE, "w", _SH_DENYWR};
static std::array<Entry, 3> 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
+32 -20
View File
@@ -12,37 +12,49 @@
#include <fmt/color.h> #include <fmt/color.h>
#include <fmt/format.h> #include <fmt/format.h>
std::uint64_t GetLoggingTime(); namespace Common::Logging {
std::string StandardizeLogClass(const std::string& log_class);
#define LOG_PRINT(log_class, level, text_style, file, line, func, format, ...) \ std::uint64_t GetLoggingTime();
{ \
fmt::print(stderr, text_style, "[{:12.6f}] {} <{}> {}:{}:{}: " format "\n", \ enum Level { Invalid = 0, Trace, Debug, Info, Warning, Error, Critical };
GetLoggingTime() / 1000000.0, StandardizeLogClass(log_class), level, file, \ struct Entry {
line, func __VA_OPT__(, ) __VA_ARGS__); \ Level level;
fflush(stderr); \ 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 #ifdef _DEBUG
#define LOG_TRACE(log_class, ...) \ #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__) __func__, __VA_ARGS__)
#else #else
#define LOG_TRACE(log_class, fmt, ...) (void(0)) #define LOG_TRACE(log_class, fmt, ...) (void(0))
#endif #endif
#define LOG_DEBUG(log_class, ...) \ #define LOG_DEBUG(log_class, ...) \
LOG_PRINT(#log_class, "Debug", fmt::fg(fmt::terminal_color::cyan), __FILE__, __LINE__, \ LOG_PRINT(#log_class, Debug, fmt::fg(fmt::terminal_color::cyan), __VA_ARGS__)
__func__, __VA_ARGS__)
#define LOG_INFO(log_class, ...) \ #define LOG_INFO(log_class, ...) \
LOG_PRINT(#log_class, "Info", fmt::fg(fmt::terminal_color::white), __FILE__, __LINE__, \ LOG_PRINT(#log_class, Info, fmt::fg(fmt::terminal_color::white), __VA_ARGS__)
__func__, __VA_ARGS__)
#define LOG_WARNING(log_class, ...) \ #define LOG_WARNING(log_class, ...) \
LOG_PRINT(#log_class, "Warning", fmt::fg(fmt::terminal_color::bright_yellow), __FILE__, \ LOG_PRINT(#log_class, Warning, fmt::fg(fmt::terminal_color::bright_yellow), __VA_ARGS__)
__LINE__, __func__, __VA_ARGS__)
#define LOG_ERROR(log_class, ...) \ #define LOG_ERROR(log_class, ...) \
LOG_PRINT(#log_class, "Error", fmt::fg(fmt::terminal_color::bright_red), __FILE__, __LINE__, \ LOG_PRINT(#log_class, Error, fmt::fg(fmt::terminal_color::bright_red), __VA_ARGS__)
__func__, __VA_ARGS__)
#define LOG_CRITICAL(log_class, ...) \ #define LOG_CRITICAL(log_class, ...) \
LOG_PRINT(#log_class, "Critical", fmt::fg(fmt::terminal_color::bright_magenta), __FILE__, \ LOG_PRINT(#log_class, Critical, fmt::fg(fmt::terminal_color::bright_magenta), __VA_ARGS__)
__LINE__, __func__, __VA_ARGS__)
+1 -1
View File
@@ -30,7 +30,7 @@ bool LoadTitleKeysBin(TitleKeysMap& out, const std::string& path) {
} }
if (file.Tell() != file.GetSize()) { 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 false;
} }
return true; return true;
+5 -3
View File
@@ -437,8 +437,9 @@ std::shared_ptr<FileUtil::IOFile> SDMCImporter::OpenContent(const ContentSpecifi
const auto format_str = (specifier.id >> 32) == 0x0004008c const auto format_str = (specifier.id >> 32) == 0x0004008c
? "/title/{:08x}/{:08x}/content/00000000/{:08x}.app" ? "/title/{:08x}/{:08x}/content/00000000/{:08x}.app"
: "/title/{:08x}/{:08x}/content/{:08x}.app"; : "/title/{:08x}/{:08x}/content/{:08x}.app";
const auto path = const auto path = fmt::vformat(
fmt::format(format_str, (specifier.id >> 32), (specifier.id & 0xFFFFFFFF), content_id); format_str,
fmt::make_format_args((specifier.id >> 32), (specifier.id & 0xFFFFFFFF), content_id));
return std::make_shared<SDMCFile>(config.sdmc_path, path, "rb"); return std::make_shared<SDMCFile>(config.sdmc_path, path, "rb");
} }
} }
@@ -970,7 +971,8 @@ void SDMCImporter::ListExtdata(std::vector<ContentSpecifier>& out) const {
} }
const u64 id = std::stoull(virtual_name, nullptr, 16); 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), out.push_back({type, (id_high << 32) | id, FileUtil::Exists(citra_path),
FileUtil::GetDirectoryTreeSize(directory + virtual_name + "/")}); FileUtil::GetDirectoryTreeSize(directory + virtual_name + "/")});
return true; return true;