diff --git a/include/logvisor/logvisor.hpp b/include/logvisor/logvisor.hpp index df5f361..fd5a5ec 100644 --- a/include/logvisor/logvisor.hpp +++ b/include/logvisor/logvisor.hpp @@ -15,8 +15,7 @@ extern "C" void logvisorBp(); -namespace logvisor -{ +namespace logvisor { void logvisorAbort(); @@ -30,30 +29,24 @@ extern bool XtermColor; /** * @brief Severity level for log messages */ -enum Level -{ - Info, /**< Non-error informative message */ - Warning, /**< Non-error warning message */ - Error, /**< Recoverable error message */ - Fatal /**< Non-recoverable error message (throws exception) */ +enum Level { + Info, /**< Non-error informative message */ + Warning, /**< Non-error warning message */ + Error, /**< Recoverable error message */ + Fatal /**< Non-recoverable error message (throws exception) */ }; /** * @brief Backend interface for receiving app-wide log events */ -struct ILogger -{ - virtual ~ILogger() {} - virtual void report(const char* modName, Level severity, - const char* format, va_list ap)=0; - virtual void report(const char* modName, Level severity, - const wchar_t* format, va_list ap)=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, - const wchar_t* format, va_list ap)=0; +struct ILogger { + virtual ~ILogger() {} + virtual void report(const char* modName, Level severity, const char* format, va_list ap) = 0; + virtual void report(const char* modName, Level severity, const wchar_t* format, va_list ap) = 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, + const wchar_t* format, va_list ap) = 0; }; /** @@ -97,18 +90,16 @@ extern std::atomic_uint_fast64_t FrameIndex; * * Ensures logging streams aren't written concurrently */ -struct LogMutex -{ - bool enabled = true; - std::recursive_mutex mutex; - ~LogMutex() { enabled = false; } - std::unique_lock lock() - { - if (enabled) - return std::unique_lock(mutex); - else - return std::unique_lock(); - } +struct LogMutex { + bool enabled = true; + std::recursive_mutex mutex; + ~LogMutex() { enabled = false; } + std::unique_lock lock() { + if (enabled) + return std::unique_lock(mutex); + else + return std::unique_lock(); + } }; extern LogMutex _LogMutex; @@ -116,10 +107,7 @@ extern LogMutex _LogMutex; * @brief Take a centralized lock for the logging output stream(s) * @return RAII mutex lock */ -static inline std::unique_lock LockLog() -{ - return _LogMutex.lock(); -} +static inline std::unique_lock LockLog() { return _LogMutex.lock(); } extern uint64_t _LogCounter; @@ -127,15 +115,12 @@ extern uint64_t _LogCounter; * @brief Get current count of logging events * @return Log Count */ -static inline uint64_t GetLogCounter() -{ - return _LogCounter; -} +static inline uint64_t GetLogCounter() { return _LogCounter; } /** * @brief Restore centralized logger vector to default state (silent operation) */ -static inline void UnregisterLoggers() {MainLoggers.clear();} +static inline void UnregisterLoggers() { MainLoggers.clear(); } /** * @brief Construct and register a real-time console logger singleton @@ -180,89 +165,82 @@ void RegisterFileLogger(const wchar_t* filepath); /** * @brief This is constructed per-subsystem in a locally centralized fashon */ -class Module -{ - const char* m_modName; +class Module { + const char* m_modName; + public: - Module(const char* modName) : m_modName(modName) {} + Module(const char* modName) : m_modName(modName) {} - /** - * @brief Route new log message to centralized ILogger - * @param severity Level of log report severity - * @param format Standard printf-style format string - */ - template - inline void report(Level severity, const CharType* format, ...) - { - if (MainLoggers.empty() && severity != Level::Fatal) - return; - va_list ap; - va_start(ap, format); - report(severity, format, ap); - va_end(ap); + /** + * @brief Route new log message to centralized ILogger + * @param severity Level of log report severity + * @param format Standard printf-style format string + */ + template + inline void report(Level severity, const CharType* format, ...) { + if (MainLoggers.empty() && severity != Level::Fatal) + return; + va_list ap; + va_start(ap, format); + report(severity, format, ap); + va_end(ap); + } + + template + inline void report(Level severity, const CharType* format, va_list ap) { + auto lk = LockLog(); + ++_LogCounter; + if (severity == Fatal) + RegisterConsoleLogger(); + 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; + } + + /** + * @brief Route new log message with source info to centralized ILogger + * @param severity Level of log report severity + * @param file Source file name from __FILE__ macro + * @param linenum Source line number from __LINE__ macro + * @param format Standard printf-style format string + */ + template + inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, ...) { + if (MainLoggers.empty() && severity != Level::Fatal) + return; + va_list ap; + va_start(ap, format); + reportSource(severity, file, linenum, format, ap); + va_end(ap); + } + + template + inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, va_list ap) { + auto lk = LockLog(); + ++_LogCounter; + if (severity == Fatal) + RegisterConsoleLogger(); + for (auto& logger : MainLoggers) { + va_list apc; + va_copy(apc, ap); + logger->reportSource(m_modName, severity, file, linenum, format, apc); + va_end(apc); } - template - inline void report(Level severity, const CharType* format, va_list ap) - { - auto lk = LockLog(); - ++_LogCounter; - if (severity == Fatal) - RegisterConsoleLogger(); - 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; - } - - /** - * @brief Route new log message with source info to centralized ILogger - * @param severity Level of log report severity - * @param file Source file name from __FILE__ macro - * @param linenum Source line number from __LINE__ macro - * @param format Standard printf-style format string - */ - template - inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, ...) - { - if (MainLoggers.empty() && severity != Level::Fatal) - return; - va_list ap; - va_start(ap, format); - reportSource(severity, file, linenum, format, ap); - va_end(ap); - } - - template - inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, va_list ap) - { - auto lk = LockLog(); - ++_LogCounter; - if (severity == Fatal) - RegisterConsoleLogger(); - 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; - } + if (severity == Fatal) + logvisorAbort(); + else if (severity == Error) + ++ErrorCount; + } }; -} - +} // namespace logvisor diff --git a/lib/logvisor.cpp b/lib/logvisor.cpp index 5951168..776714b 100644 --- a/lib/logvisor.cpp +++ b/lib/logvisor.cpp @@ -44,45 +44,37 @@ #define NORMAL "\x1b[0m" #if _WIN32 -#define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE +#define FOREGROUND_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE #endif void logvisorBp() {} -namespace logvisor -{ +namespace logvisor { static Module Log("logvisor"); static std::unordered_map ThreadMap; -static void AddThreadToMap(const char* name) -{ - auto lk = LockLog(); - ThreadMap[std::this_thread::get_id()] = name; +static void AddThreadToMap(const char* name) { + auto lk = LockLog(); + ThreadMap[std::this_thread::get_id()] = name; } -void RegisterThreadName(const char* name) -{ - AddThreadToMap(name); +void RegisterThreadName(const char* name) { + AddThreadToMap(name); #if __APPLE__ - pthread_setname_np(name); + pthread_setname_np(name); #elif __linux__ - prctl(PR_SET_NAME, name); + prctl(PR_SET_NAME, name); #elif _MSC_VER - struct - { - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to name (in user addr space). - DWORD dwThreadID; // Thread ID (-1=caller thread). - DWORD dwFlags; // Reserved for future use, must be zero. - } info = {0x1000, name, (DWORD)-1, 0}; - __try - { - RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - } + struct { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. + } info = {0x1000, name, (DWORD)-1, 0}; + __try { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) {} #endif } @@ -95,176 +87,154 @@ void RegisterThreadName(const char* name) #define WINDOWS_STORE 0 #endif -void KillProcessTree() -{ - DWORD myprocID = GetCurrentProcessId(); - PROCESSENTRY32 pe = {}; - pe.dwSize = sizeof(PROCESSENTRY32); +void KillProcessTree() { + DWORD myprocID = GetCurrentProcessId(); + PROCESSENTRY32 pe = {}; + pe.dwSize = sizeof(PROCESSENTRY32); - HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (::Process32First(hSnap, &pe)) - { - BOOL bContinue = TRUE; + if (::Process32First(hSnap, &pe)) { + BOOL bContinue = TRUE; - // kill child processes - while (bContinue) - { - // only kill child processes - if (pe.th32ParentProcessID == myprocID) - { - HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); + // kill child processes + while (bContinue) { + // only kill child processes + if (pe.th32ParentProcessID == myprocID) { + HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); - if (hChildProc) - { - ::TerminateProcess(hChildProc, 1); - ::CloseHandle(hChildProc); - } - } - - bContinue = ::Process32Next(hSnap, &pe); + if (hChildProc) { + ::TerminateProcess(hChildProc, 1); + ::CloseHandle(hChildProc); } + } + + bContinue = ::Process32Next(hSnap, &pe); } + } } -void logvisorAbort() -{ +void logvisorAbort() { #if !WINDOWS_STORE - unsigned int i; - void* stack[100]; - unsigned short frames; - SYMBOL_INFO* symbol; - HANDLE process; + unsigned int i; + void* stack[100]; + unsigned short frames; + SYMBOL_INFO* symbol; + HANDLE process; - process = GetCurrentProcess(); - SymInitialize(process, NULL, TRUE); - frames = CaptureStackBackTrace(0, 100, stack, NULL); - symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); - symbol->MaxNameLen = 255; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + frames = CaptureStackBackTrace(0, 100, stack, NULL); + symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); + symbol->MaxNameLen = 255; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - for (i = 0; i < frames; i++) - { - SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); + for (i = 0; i < frames; i++) { + SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); - fprintf(stderr, "%i: %s - 0x%0llX", frames - i - 1, symbol->Name, symbol->Address); + fprintf(stderr, "%i: %s - 0x%0llX", frames - i - 1, symbol->Name, symbol->Address); - DWORD dwDisplacement; - IMAGEHLP_LINE64 line; - SymSetOptions(SYMOPT_LOAD_LINES); + DWORD dwDisplacement; + IMAGEHLP_LINE64 line; + SymSetOptions(SYMOPT_LOAD_LINES); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - if (SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &dwDisplacement, &line)) - { - // SymGetLineFromAddr64 returned success - fprintf(stderr, " LINE %d\n", int(line.LineNumber)); - } - else - { - fprintf(stderr, "\n"); - } + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + if (SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &dwDisplacement, &line)) { + // SymGetLineFromAddr64 returned success + fprintf(stderr, " LINE %d\n", int(line.LineNumber)); + } else { + fprintf(stderr, "\n"); } + } - fflush(stderr); - free(symbol); + fflush(stderr); + free(symbol); #endif - KillProcessTree(); + KillProcessTree(); - // If you caught one of the above signals, it is likely you just - // want to quit your program right now. + // If you caught one of the above signals, it is likely you just + // want to quit your program right now. #ifndef NDEBUG - signal(SIGABRT, SIG_DFL); - abort(); + signal(SIGABRT, SIG_DFL); + abort(); #else - exit(1); + exit(1); #endif } #elif defined(__SWITCH__) -void logvisorAbort() -{ - exit(1); -} +void logvisorAbort() { exit(1); } #else void KillProcessTree() {} #include -void logvisorAbort() -{ - void* array[128]; - size_t size = backtrace(array, 128); +void logvisorAbort() { + void* array[128]; + size_t size = backtrace(array, 128); - constexpr size_t exeBufSize = 1024 + 1; - char exeNameBuffer[exeBufSize] = {}; + constexpr size_t exeBufSize = 1024 + 1; + char exeNameBuffer[exeBufSize] = {}; #if __linux__ - readlink("/proc/self/exe", exeNameBuffer, exeBufSize); + readlink("/proc/self/exe", exeNameBuffer, exeBufSize); #endif - char cmdLine[1024]; + char cmdLine[1024]; #if __APPLE__ - snprintf(cmdLine, 1024, "atos -p %d", getpid()); + snprintf(cmdLine, 1024, "atos -p %d", getpid()); #else - snprintf(cmdLine, 1024, "2>/dev/null addr2line -C -f -e \"%s\"", exeNameBuffer); + snprintf(cmdLine, 1024, "2>/dev/null addr2line -C -f -e \"%s\"", exeNameBuffer); #endif - std::string cmdLineStr = cmdLine; - for (size_t i = 0; i < size; i++) - { + std::string cmdLineStr = cmdLine; + for (size_t i = 0; i < size; i++) { #if __linux__ - Dl_info dlip; - if (dladdr(array[i], &dlip)) - snprintf(cmdLine, 128, " %p", (void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase)); - else - snprintf(cmdLine, 128, " %p", array[i]); -#else - snprintf(cmdLine, 128, " %p", array[i]); -#endif - cmdLineStr += cmdLine; - } - - FILE* fp = popen(cmdLineStr.c_str(), "r"); - if (fp) - { - char readBuf[256]; - size_t readSz; - while ((readSz = fread(readBuf, 1, 256, fp))) - fwrite(readBuf, 1, readSz, stderr); - pclose(fp); - } + Dl_info dlip; + if (dladdr(array[i], &dlip)) + snprintf(cmdLine, 128, " %p", (void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase)); else - { - for (size_t i = 0; i < size; i++) - { - fprintf(stderr, "- "); - Dl_info dlip; - if (dladdr(array[i], &dlip)) - { - int 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, - (void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase)); - free(demangledName); - } - else - { - fprintf(stderr, "%p\n", array[i]); - } - } - } + snprintf(cmdLine, 128, " %p", array[i]); +#else + snprintf(cmdLine, 128, " %p", array[i]); +#endif + cmdLineStr += cmdLine; + } - fflush(stderr); - fflush(stdout); - KillProcessTree(); + FILE* fp = popen(cmdLineStr.c_str(), "r"); + if (fp) { + char readBuf[256]; + size_t readSz; + while ((readSz = fread(readBuf, 1, 256, fp))) + fwrite(readBuf, 1, readSz, stderr); + pclose(fp); + } else { + for (size_t i = 0; i < size; i++) { + fprintf(stderr, "- "); + Dl_info dlip; + if (dladdr(array[i], &dlip)) { + int 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, + (void*)((uint8_t*)array[i] - (uint8_t*)dlip.dli_fbase)); + free(demangledName); + } else { + fprintf(stderr, "%p\n", array[i]); + } + } + } + + fflush(stderr); + fflush(stdout); + KillProcessTree(); #ifndef NDEBUG - signal(SIGABRT, SIG_DFL); - abort(); + signal(SIGABRT, SIG_DFL); + abort(); #else - exit(1); + exit(1); #endif } @@ -272,22 +242,20 @@ void logvisorAbort() LogMutex _LogMutex; -static void AbortHandler(int signum) -{ - _LogMutex.enabled = false; - switch (signum) - { - case SIGSEGV: - Log.report(logvisor::Fatal, "Segmentation Fault"); - case SIGILL: - Log.report(logvisor::Fatal, "Bad Execution"); - case SIGFPE: - Log.report(logvisor::Fatal, "Floating Point Exception"); - case SIGABRT: - Log.report(logvisor::Fatal, "Abort Signal"); - default: - Log.report(logvisor::Fatal, "unknown signal %d", signum); - } +static void AbortHandler(int signum) { + _LogMutex.enabled = false; + switch (signum) { + case SIGSEGV: + Log.report(logvisor::Fatal, "Segmentation Fault"); + case SIGILL: + Log.report(logvisor::Fatal, "Bad Execution"); + case SIGFPE: + Log.report(logvisor::Fatal, "Floating Point Exception"); + case SIGABRT: + Log.report(logvisor::Fatal, "Abort Signal"); + default: + Log.report(logvisor::Fatal, "unknown signal %d", signum); + } } uint64_t _LogCounter; @@ -296,29 +264,27 @@ std::vector> MainLoggers; std::atomic_size_t ErrorCount(0); static std::chrono::steady_clock MonoClock; static std::chrono::steady_clock::time_point GlobalStart = MonoClock.now(); -static inline std::chrono::steady_clock::duration CurrentUptime() -{return MonoClock.now() - GlobalStart;} +static inline std::chrono::steady_clock::duration CurrentUptime() { return MonoClock.now() - GlobalStart; } std::atomic_uint_fast64_t FrameIndex(0); -static inline int ConsoleWidth() -{ - int retval = 80; +static inline int ConsoleWidth() { + int retval = 80; #if _WIN32 #if !WINDOWS_STORE - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); - retval = info.dwSize.X - 1; + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); + retval = info.dwSize.X - 1; #endif #elif defined(__SWITCH__) - return 80; + return 80; #else - struct winsize w; - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) - retval = w.ws_col; + struct winsize w; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) + retval = w.ws_col; #endif - if (retval < 10) - return 10; - return retval; + if (retval < 10) + return 10; + return retval; } #if _WIN32 @@ -327,361 +293,320 @@ static HANDLE Term = 0; static const char* Term = nullptr; #endif bool XtermColor = false; -struct ConsoleLogger : public ILogger -{ - ConsoleLogger() - { +struct ConsoleLogger : public ILogger { + ConsoleLogger() { #if _WIN32 #if !WINDOWS_STORE - const char* conemuANSI = getenv("ConEmuANSI"); - if (conemuANSI && !strcmp(conemuANSI, "ON")) - XtermColor = true; + const char* conemuANSI = getenv("ConEmuANSI"); + if (conemuANSI && !strcmp(conemuANSI, "ON")) + XtermColor = true; #endif - if (!Term) - Term = GetStdHandle(STD_ERROR_HANDLE); + if (!Term) + Term = GetStdHandle(STD_ERROR_HANDLE); #else - if (!Term) - { - Term = getenv("TERM"); - if (Term && !strncmp(Term, "xterm", 5)) - { - XtermColor = true; - putenv((char*)"TERM=xterm-16color"); - } - } -#endif + if (!Term) { + Term = getenv("TERM"); + if (Term && !strncmp(Term, "xterm", 5)) { + XtermColor = true; + putenv((char*)"TERM=xterm-16color"); + } } +#endif + } - static void _reportHead(const char* modName, const char* sourceInfo, Level severity) - { - /* Clear current line out */ - int width = ConsoleWidth(); - fprintf(stderr, "\r"); - for (int w=0 ; w(logger.get()); - if (filelogger) - { - if (!wcscmp(filepath, filelogger->m_filepath)) - return; - } +void RegisterFileLogger(const wchar_t* filepath) { + /* Determine if file logger already added */ + for (auto& logger : MainLoggers) { + FileLogger16* filelogger = dynamic_cast(logger.get()); + if (filelogger) { + if (!wcscmp(filepath, filelogger->m_filepath)) + return; } + } - /* Otherwise construct new file logger */ - MainLoggers.emplace_back(new FileLogger16(filepath)); + /* Otherwise construct new file logger */ + MainLoggers.emplace_back(new FileLogger16(filepath)); } #endif -} +} // namespace logvisor