Integrate libfmt for format strings

This commit is contained in:
Jack Andersen 2019-07-19 18:21:39 -10:00
parent a0ef17d895
commit 3bedd268e8
5 changed files with 215 additions and 162 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "fmt"]
path = fmt
url = https://github.com/fmtlib/fmt

View File

@ -7,15 +7,18 @@ endif()
include (CMakePackageConfigHelpers) include (CMakePackageConfigHelpers)
add_subdirectory(fmt)
add_library(logvisor add_library(logvisor
lib/logvisor.cpp lib/logvisor.cpp
include/logvisor/logvisor.hpp) include/logvisor/logvisor.hpp)
target_link_libraries(logvisor PUBLIC ${CMAKE_DL_LIBS}) target_link_libraries(logvisor PUBLIC ${CMAKE_DL_LIBS} fmt)
target_include_directories(logvisor PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>) target_include_directories(logvisor PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
install(DIRECTORY include/logvisor DESTINATION include) install(DIRECTORY include/logvisor DESTINATION include)
install(DIRECTORY fmt/include/fmt DESTINATION include)
set(version_config_file "${PROJECT_BINARY_DIR}/logvisorConfigVersion.cmake") set(version_config_file "${PROJECT_BINARY_DIR}/logvisorConfigVersion.cmake")
set(config_file "${PROJECT_BINARY_DIR}/logvisorConfig.cmake") set(config_file "${PROJECT_BINARY_DIR}/logvisorConfig.cmake")
@ -23,7 +26,7 @@ set(config_install_dir "lib/cmake/logvisor")
# Associate target with export # Associate target with export
install( install(
TARGETS logvisor TARGETS logvisor fmt
EXPORT logvisorTargets EXPORT logvisorTargets
ARCHIVE DESTINATION "lib" ARCHIVE DESTINATION "lib"
INCLUDES DESTINATION include # This sets the INTERFACE_INCLUDE_DIRECTORIES property of the target. INCLUDES DESTINATION include # This sets the INTERFACE_INCLUDE_DIRECTORIES property of the target.

1
fmt Submodule

@ -0,0 +1 @@
Subproject commit 6bcc3fd21694b5634cc006915bd049cf460a9a8d

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cstdarg>
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@ -9,6 +8,11 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#define FMT_STRING_ALIAS 1
#define FMT_ENFORCE_COMPILE_STRING 1
#define FMT_USE_GRISU 0
#include <fmt/format.h>
#ifdef __SWITCH__ #ifdef __SWITCH__
#include "nxstl/mutex" #include "nxstl/mutex"
#endif #endif
@ -40,13 +44,13 @@ enum Level {
* @brief Backend interface for receiving app-wide log events * @brief Backend interface for receiving app-wide log events
*/ */
struct ILogger { struct ILogger {
virtual ~ILogger() {} virtual ~ILogger() = default;
virtual void report(const char* modName, Level severity, const char* format, va_list ap) = 0; virtual void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) = 0;
virtual void report(const char* modName, Level severity, const wchar_t* format, va_list ap) = 0; virtual void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) = 0;
virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, const char* format,
va_list ap) = 0;
virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
const wchar_t* format, va_list ap) = 0; fmt::string_view format, fmt::format_args args) = 0;
virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
fmt::wstring_view format, fmt::wformat_args args) = 0;
}; };
/** /**
@ -107,7 +111,7 @@ extern LogMutex _LogMutex;
* @brief Take a centralized lock for the logging output stream(s) * @brief Take a centralized lock for the logging output stream(s)
* @return RAII mutex lock * @return RAII mutex lock
*/ */
static inline std::unique_lock<std::recursive_mutex> LockLog() { return _LogMutex.lock(); } inline std::unique_lock<std::recursive_mutex> LockLog() { return _LogMutex.lock(); }
extern uint64_t _LogCounter; extern uint64_t _LogCounter;
@ -115,12 +119,12 @@ extern uint64_t _LogCounter;
* @brief Get current count of logging events * @brief Get current count of logging events
* @return Log Count * @return Log Count
*/ */
static inline uint64_t GetLogCounter() { return _LogCounter; } inline uint64_t GetLogCounter() { return _LogCounter; }
/** /**
* @brief Restore centralized logger vector to default state (silent operation) * @brief Restore centralized logger vector to default state (silent operation)
*/ */
static inline void UnregisterLoggers() { MainLoggers.clear(); } inline void UnregisterLoggers() { MainLoggers.clear(); }
/** /**
* @brief Construct and register a real-time console logger singleton * @brief Construct and register a real-time console logger singleton
@ -168,6 +172,40 @@ void RegisterFileLogger(const wchar_t* filepath);
class Module { class Module {
const char* m_modName; const char* m_modName;
template <typename Char>
void _vreport(Level severity, fmt::basic_string_view<Char> format,
fmt::basic_format_args<fmt::buffer_context<Char>> args) {
auto lk = LockLog();
++_LogCounter;
if (severity == Fatal)
RegisterConsoleLogger();
for (auto& logger : MainLoggers)
logger->report(m_modName, severity, format, args);
if (severity == Error || severity == Fatal)
logvisorBp();
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
}
template <typename Char>
void _vreportSource(Level severity, const char* file, unsigned linenum, fmt::basic_string_view<Char> format,
fmt::basic_format_args<fmt::buffer_context<Char>> args) {
auto lk = LockLog();
++_LogCounter;
if (severity == Fatal)
RegisterConsoleLogger();
for (auto& logger : MainLoggers)
logger->reportSource(m_modName, severity, file, linenum, format, args);
if (severity == Error || severity == Fatal)
logvisorBp();
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
}
public: public:
Module(const char* modName) : m_modName(modName) {} Module(const char* modName) : m_modName(modName) {}
@ -176,34 +214,21 @@ public:
* @param severity Level of log report severity * @param severity Level of log report severity
* @param format Standard printf-style format string * @param format Standard printf-style format string
*/ */
template <typename CharType> template <typename S, typename... Args, typename Char = fmt::char_t<S>>
inline void report(Level severity, const CharType* format, ...) { void report(Level severity, const S& format, Args&&... args) {
if (MainLoggers.empty() && severity != Level::Fatal) if (MainLoggers.empty() && severity != Level::Fatal)
return; return;
va_list ap; _vreport(severity, fmt::to_string_view<Char>(format),
va_start(ap, format); fmt::basic_format_args<fmt::buffer_context<Char>>(
report(severity, format, ap); fmt::internal::make_args_checked<Args...>(format, args...)));
va_end(ap);
} }
template <typename CharType> template <typename Char>
inline void report(Level severity, const CharType* format, va_list ap) { void vreport(Level severity, fmt::basic_string_view<Char> format,
auto lk = LockLog(); fmt::basic_format_args<fmt::buffer_context<Char>> args) {
++_LogCounter; if (MainLoggers.empty() && severity != Level::Fatal)
if (severity == Fatal) return;
RegisterConsoleLogger(); _vreport(severity, format, args);
for (auto& logger : MainLoggers) {
va_list apc;
va_copy(apc, ap);
logger->report(m_modName, severity, format, apc);
va_end(apc);
}
if (severity == Error || severity == Fatal)
logvisorBp();
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
} }
/** /**
@ -213,34 +238,66 @@ public:
* @param linenum Source line number from __LINE__ macro * @param linenum Source line number from __LINE__ macro
* @param format Standard printf-style format string * @param format Standard printf-style format string
*/ */
template <typename CharType> template <typename S, typename... Args, typename Char = fmt::char_t<S>>
inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, ...) { void reportSource(Level severity, const char* file, unsigned linenum, const S& format, Args&&... args) {
if (MainLoggers.empty() && severity != Level::Fatal) if (MainLoggers.empty() && severity != Level::Fatal)
return; return;
va_list ap; _vreportSource(
va_start(ap, format); severity, file, linenum, fmt::to_string_view<Char>(format),
reportSource(severity, file, linenum, format, ap); fmt::basic_format_args<fmt::buffer_context<Char>>(
va_end(ap); fmt::internal::make_args_checked<Args...>(format, args...)));
} }
template <typename CharType> template <typename Char>
inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, va_list ap) { void vreportSource(Level severity, const char* file, unsigned linenum, fmt::basic_string_view<Char> format,
auto lk = LockLog(); fmt::basic_format_args<fmt::buffer_context<Char>> args) {
++_LogCounter; if (MainLoggers.empty() && severity != Level::Fatal)
if (severity == Fatal) return;
RegisterConsoleLogger(); _vreportSource(severity, file, linenum, format, args);
for (auto& logger : MainLoggers) {
va_list apc;
va_copy(apc, ap);
logger->reportSource(m_modName, severity, file, linenum, format, apc);
va_end(apc);
}
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
} }
}; };
#define Lfmt(str) fmt(L##str)
#define ufmt(str) fmt(u##str)
#define Ufmt(str) fmt(U##str)
#define FMT_CUSTOM_FORMATTER(tp, ...) \
namespace fmt { \
template <> \
struct formatter<tp, char> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), __VA_ARGS__); \
} \
}; \
template <> \
struct formatter<tp, wchar_t> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), L##__VA_ARGS__); \
} \
}; \
template <> \
struct formatter<tp, char16_t> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), u##__VA_ARGS__); \
} \
}; \
template <> \
struct formatter<tp, char32_t> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), U##__VA_ARGS__); \
} \
}; \
}
} // namespace logvisor } // namespace logvisor

View File

@ -184,25 +184,22 @@ void logvisorAbort() {
readlink("/proc/self/exe", exeNameBuffer, exeBufSize); readlink("/proc/self/exe", exeNameBuffer, exeBufSize);
#endif #endif
char cmdLine[1024];
#if __APPLE__ #if __APPLE__
snprintf(cmdLine, 1024, "atos -p %d", getpid()); std::string cmdLineStr = fmt::format(fmt("atos -p {}"), getpid());
#else #else
snprintf(cmdLine, 1024, "2>/dev/null addr2line -C -f -e \"%s\"", exeNameBuffer); std::string cmdLineStr = fmt::format(fmt("2>/dev/null addr2line -C -f -e \"{}\""), exeNameBuffer);
#endif #endif
std::string cmdLineStr = cmdLine;
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
#if __linux__ #if __linux__
Dl_info dlip; Dl_info dlip;
if (dladdr(array[i], &dlip)) if (dladdr(array[i], &dlip))
snprintf(cmdLine, 128, " %p", (void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase)); cmdLineStr += fmt::format(fmt(" 0x{:016X}"), (uintptr_t)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase));
else else
snprintf(cmdLine, 128, " %p", array[i]); cmdLineStr += fmt::format(fmt(" 0x{:016X}"), (uintptr_t)array[i]);
#else #else
snprintf(cmdLine, 128, " %p", array[i]); cmdLineStr += fmt::format(fmt(" 0x{:016X}"), (uintptr_t)array[i]);
#endif #endif
cmdLineStr += cmdLine;
} }
FILE* fp = popen(cmdLineStr.c_str(), "r"); FILE* fp = popen(cmdLineStr.c_str(), "r");
@ -210,26 +207,26 @@ void logvisorAbort() {
char readBuf[256]; char readBuf[256];
size_t readSz; size_t readSz;
while ((readSz = fread(readBuf, 1, 256, fp))) while ((readSz = fread(readBuf, 1, 256, fp)))
fwrite(readBuf, 1, readSz, stderr); std::fwrite(readBuf, 1, readSz, stderr);
pclose(fp); pclose(fp);
} else { } else {
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
fprintf(stderr, "- "); std::fputs("- ", stderr);
Dl_info dlip; Dl_info dlip;
if (dladdr(array[i], &dlip)) { if (dladdr(array[i], &dlip)) {
int status; int status;
char* demangledName = abi::__cxa_demangle(dlip.dli_sname, nullptr, nullptr, &status); char* demangledName = abi::__cxa_demangle(dlip.dli_sname, nullptr, nullptr, &status);
fprintf(stderr, "%p(%s+%p)\n", dlip.dli_saddr, demangledName ? demangledName : dlip.dli_sname, std::fprintf(stderr, "%p(%s+%p)\n", dlip.dli_saddr, demangledName ? demangledName : dlip.dli_sname,
(void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase)); (void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase));
free(demangledName); std::free(demangledName);
} else { } else {
fprintf(stderr, "%p\n", array[i]); std::fprintf(stderr, "%p\n", array[i]);
} }
} }
} }
fflush(stderr); std::fflush(stderr);
fflush(stdout); std::fflush(stdout);
KillProcessTree(); KillProcessTree();
#ifndef NDEBUG #ifndef NDEBUG
@ -248,19 +245,19 @@ static void AbortHandler(int signum) {
_LogMutex.enabled = false; _LogMutex.enabled = false;
switch (signum) { switch (signum) {
case SIGSEGV: case SIGSEGV:
Log.report(logvisor::Fatal, "Segmentation Fault"); Log.report(logvisor::Fatal, fmt("Segmentation Fault"));
break; break;
case SIGILL: case SIGILL:
Log.report(logvisor::Fatal, "Bad Execution"); Log.report(logvisor::Fatal, fmt("Bad Execution"));
break; break;
case SIGFPE: case SIGFPE:
Log.report(logvisor::Fatal, "Floating Point Exception"); Log.report(logvisor::Fatal, fmt("Floating Point Exception"));
break; break;
case SIGABRT: case SIGABRT:
Log.report(logvisor::Fatal, "Abort Signal"); Log.report(logvisor::Fatal, fmt("Abort Signal"));
break; break;
default: default:
Log.report(logvisor::Fatal, "unknown signal %d", signum); Log.report(logvisor::Fatal, fmt("unknown signal {}"), signum);
break; break;
} }
} }
@ -324,10 +321,10 @@ struct ConsoleLogger : public ILogger {
static void _reportHead(const char* modName, const char* sourceInfo, Level severity) { static void _reportHead(const char* modName, const char* sourceInfo, Level severity) {
/* Clear current line out */ /* Clear current line out */
int width = ConsoleWidth(); int width = ConsoleWidth();
fprintf(stderr, "\r"); std::fputs("\r", stderr);
for (int w = 0; w < width; ++w) for (int w = 0; w < width; ++w)
fprintf(stderr, " "); std::fputs(" ", stderr);
fprintf(stderr, "\r"); std::fputs("\r", stderr);
std::chrono::steady_clock::duration tm = CurrentUptime(); std::chrono::steady_clock::duration tm = CurrentUptime();
double tmd = tm.count() * std::chrono::steady_clock::duration::period::num / double tmd = tm.count() * std::chrono::steady_clock::duration::period::num /
@ -338,33 +335,33 @@ struct ConsoleLogger : public ILogger {
thrName = ThreadMap[thrId]; thrName = ThreadMap[thrId];
if (XtermColor) { if (XtermColor) {
fprintf(stderr, BOLD "["); std::fputs(BOLD "[", stderr);
fprintf(stderr, GREEN "%5.4f ", tmd); fmt::print(stderr, fmt(GREEN "{:5.4} "), tmd);
uint_fast64_t fIdx = FrameIndex.load(); uint_fast64_t fIdx = FrameIndex.load();
if (fIdx) if (fIdx)
fprintf(stderr, "(%" PRIu64 ") ", fIdx); fmt::print(stderr, fmt("({}) "), fIdx);
switch (severity) { switch (severity) {
case Info: case Info:
fprintf(stderr, BOLD CYAN "INFO"); std::fputs(BOLD CYAN "INFO", stderr);
break; break;
case Warning: case Warning:
fprintf(stderr, BOLD YELLOW "WARNING"); std::fputs(BOLD YELLOW "WARNING", stderr);
break; break;
case Error: case Error:
fprintf(stderr, RED BOLD "ERROR"); std::fputs(RED BOLD "ERROR", stderr);
break; break;
case Fatal: case Fatal:
fprintf(stderr, BOLD RED "FATAL ERROR"); std::fputs(BOLD RED "FATAL ERROR", stderr);
break; break;
default: default:
break; break;
}; };
fprintf(stderr, NORMAL BOLD " %s", modName); fmt::print(stderr, fmt(NORMAL BOLD " {}"), modName);
if (sourceInfo) if (sourceInfo)
fprintf(stderr, BOLD YELLOW " {%s}", sourceInfo); fmt::print(stderr, fmt(BOLD YELLOW " {{}}"), sourceInfo);
if (thrName) if (thrName)
fprintf(stderr, BOLD MAGENTA " (%s)", thrName); fmt::print(stderr, fmt(BOLD MAGENTA " ({})"), thrName);
fprintf(stderr, NORMAL BOLD "] " NORMAL); std::fputs(NORMAL BOLD "] " NORMAL, stderr);
} else { } else {
#if _WIN32 #if _WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
@ -408,69 +405,65 @@ struct ConsoleLogger : public ILogger {
SetConsoleTextAttribute(Term, FOREGROUND_WHITE); SetConsoleTextAttribute(Term, FOREGROUND_WHITE);
#endif #endif
#else #else
fprintf(stderr, "["); std::fputs("[", stderr);
fprintf(stderr, "%5.4f ", tmd); fmt::print(stderr, fmt("{:5.4} "), tmd);
uint_fast64_t fIdx = FrameIndex.load(); uint_fast64_t fIdx = FrameIndex.load();
if (fIdx) if (fIdx)
fprintf(stderr, "(%" PRIu64 ") ", fIdx); fmt::print(stderr, fmt("({}) "), fIdx);
switch (severity) { switch (severity) {
case Info: case Info:
fprintf(stderr, "INFO"); std::fputs("INFO", stderr);
break; break;
case Warning: case Warning:
fprintf(stderr, "WARNING"); std::fputs("WARNING", stderr);
break; break;
case Error: case Error:
fprintf(stderr, "ERROR"); std::fputs("ERROR", stderr);
break; break;
case Fatal: case Fatal:
fprintf(stderr, "FATAL ERROR"); std::fputs("FATAL ERROR", stderr);
break; break;
default: default:
break; break;
}; };
fprintf(stderr, " %s", modName); fmt::print(stderr, fmt(" {}"), modName);
if (sourceInfo) if (sourceInfo)
fprintf(stderr, " {%s}", sourceInfo); fmt::print(stderr, fmt(" {{}}"), sourceInfo);
if (thrName) if (thrName)
fprintf(stderr, " (%s)", thrName); fmt::print(stderr, fmt(" ({})"), thrName);
fprintf(stderr, "] "); std::fputs("] ", stderr);
#endif #endif
} }
} }
void report(const char* modName, Level severity, const char* format, va_list ap) { void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) {
_reportHead(modName, nullptr, severity); _reportHead(modName, nullptr, severity);
vfprintf(stderr, format, ap); fmt::vprint(stderr, format, args);
fprintf(stderr, "\n"); std::fputs("\n", stderr);
fflush(stderr); std::fflush(stderr);
} }
void report(const char* modName, Level severity, const wchar_t* format, va_list ap) { void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) {
_reportHead(modName, nullptr, severity); _reportHead(modName, nullptr, severity);
vfwprintf(stderr, format, ap); fmt::vprint(stderr, format, args);
fprintf(stderr, "\n"); std::fputs("\n", stderr);
fflush(stderr); std::fflush(stderr);
} }
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, const char* format, void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
va_list ap) { fmt::string_view format, fmt::format_args args) {
char sourceInfo[128]; _reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
snprintf(sourceInfo, 128, "%s:%u", file, linenum); fmt::vprint(stderr, format, args);
_reportHead(modName, sourceInfo, severity); std::fputs("\n", stderr);
vfprintf(stderr, format, ap); std::fflush(stderr);
fprintf(stderr, "\n");
fflush(stderr);
} }
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, const wchar_t* format, void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
va_list ap) { fmt::wstring_view format, fmt::wformat_args args) {
char sourceInfo[128]; _reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
snprintf(sourceInfo, 128, "%s:%u", file, linenum); fmt::vprint(stderr, format, args);
_reportHead(modName, sourceInfo, severity); std::fputs("\n", stderr);
vfwprintf(stderr, format, ap); std::fflush(stderr);
fprintf(stderr, "\n");
fflush(stderr);
} }
}; };
@ -502,7 +495,7 @@ void RegisterStandardExceptions() {
struct FileLogger : public ILogger { struct FileLogger : public ILogger {
FILE* fp; FILE* fp;
virtual void openFile() = 0; virtual void openFile() = 0;
virtual void closeFile() { fclose(fp); } virtual void closeFile() { std::fclose(fp); }
void _reportHead(const char* modName, const char* sourceInfo, Level severity) { void _reportHead(const char* modName, const char* sourceInfo, Level severity) {
std::chrono::steady_clock::duration tm = CurrentUptime(); std::chrono::steady_clock::duration tm = CurrentUptime();
@ -513,70 +506,66 @@ struct FileLogger : public ILogger {
if (ThreadMap.find(thrId) != ThreadMap.end()) if (ThreadMap.find(thrId) != ThreadMap.end())
thrName = ThreadMap[thrId]; thrName = ThreadMap[thrId];
fprintf(fp, "["); std::fputs("[", fp);
fprintf(fp, "%5.4f ", tmd); std::fprintf(fp, "%5.4f ", tmd);
uint_fast64_t fIdx = FrameIndex.load(); uint_fast64_t fIdx = FrameIndex.load();
if (fIdx) if (fIdx)
fprintf(fp, "(%" PRIu64 ") ", fIdx); std::fprintf(fp, "(%" PRIu64 ") ", fIdx);
switch (severity) { switch (severity) {
case Info: case Info:
fprintf(fp, "INFO"); std::fputs("INFO", fp);
break; break;
case Warning: case Warning:
fprintf(fp, "WARNING"); std::fputs("WARNING", fp);
break; break;
case Error: case Error:
fprintf(fp, "ERROR"); std::fputs("ERROR", fp);
break; break;
case Fatal: case Fatal:
fprintf(fp, "FATAL ERROR"); std::fputs("FATAL ERROR", fp);
break; break;
default: default:
break; break;
}; };
fprintf(fp, " %s", modName); std::fprintf(fp, " %s", modName);
if (sourceInfo) if (sourceInfo)
fprintf(fp, " {%s}", sourceInfo); std::fprintf(fp, " {%s}", sourceInfo);
if (thrName) if (thrName)
fprintf(fp, " (%s)", thrName); std::fprintf(fp, " (%s)", thrName);
fprintf(fp, "] "); std::fputs("] ", fp);
} }
void report(const char* modName, Level severity, const char* format, va_list ap) { void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) {
openFile(); openFile();
_reportHead(modName, nullptr, severity); _reportHead(modName, nullptr, severity);
vfprintf(fp, format, ap); fmt::vprint(fp, format, args);
fprintf(fp, "\n"); std::fputs("\n", fp);
closeFile(); closeFile();
} }
void report(const char* modName, Level severity, const wchar_t* format, va_list ap) { void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) {
openFile(); openFile();
_reportHead(modName, nullptr, severity); _reportHead(modName, nullptr, severity);
vfwprintf(fp, format, ap); fmt::vprint(fp, format, args);
fprintf(fp, "\n"); std::fputs("\n", fp);
closeFile(); closeFile();
} }
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, const char* format, void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
va_list ap) { fmt::string_view format, fmt::format_args args) {
openFile(); openFile();
char sourceInfo[128]; _reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
snprintf(sourceInfo, 128, "%s:%u", file, linenum); fmt::vprint(fp, format, args);
_reportHead(modName, sourceInfo, severity); std::fputs("\n", fp);
vfprintf(fp, format, ap);
fprintf(fp, "\n");
closeFile(); closeFile();
} }
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, const wchar_t* format, void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
va_list ap) { fmt::wstring_view format, fmt::wformat_args args) {
openFile(); openFile();
char sourceInfo[128]; _reportHead(modName, fmt::format(fmt("{}:{}"), file, linenum).c_str(), severity);
snprintf(sourceInfo, 128, "%s:%u", file, linenum); fmt::vprint(fp, format, args);
_reportHead(modName, sourceInfo, severity); std::fputs("\n", fp);
vfwprintf(fp, format, ap);
fprintf(fp, "\n");
closeFile(); closeFile();
} }
}; };
@ -584,7 +573,7 @@ struct FileLogger : public ILogger {
struct FileLogger8 : public FileLogger { struct FileLogger8 : public FileLogger {
const char* m_filepath; const char* m_filepath;
FileLogger8(const char* filepath) : m_filepath(filepath) {} FileLogger8(const char* filepath) : m_filepath(filepath) {}
void openFile() { fp = fopen(m_filepath, "a"); } void openFile() { fp = std::fopen(m_filepath, "a"); }
}; };
void RegisterFileLogger(const char* filepath) { void RegisterFileLogger(const char* filepath) {