text_formatter.cpp
1 // Copyright 2014 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #include <array> 6 #include <cstdio> 7 8 #ifdef _WIN32 9 #include <windows.h> 10 #elif defined(ANDROID) 11 #include <android/log.h> 12 #endif 13 14 #include "common/assert.h" 15 #include "common/logging/filter.h" 16 #include "common/logging/log.h" 17 #include "common/logging/log_entry.h" 18 #include "common/logging/text_formatter.h" 19 20 namespace Common::Log { 21 22 std::string FormatLogMessage(const Entry& entry) { 23 unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000); 24 unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000); 25 26 const char* class_name = GetLogClassName(entry.log_class); 27 const char* level_name = GetLevelName(entry.log_level); 28 29 return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}", time_seconds, time_fractional, 30 class_name, level_name, entry.filename, entry.function, entry.line_num, 31 entry.message); 32 } 33 34 void PrintMessage(const Entry& entry) { 35 const auto str = FormatLogMessage(entry).append(1, '\n'); 36 fputs(str.c_str(), stderr); 37 } 38 39 void PrintColoredMessage(const Entry& entry) { 40 #ifdef _WIN32 41 HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE); 42 if (console_handle == INVALID_HANDLE_VALUE) { 43 return; 44 } 45 46 CONSOLE_SCREEN_BUFFER_INFO original_info{}; 47 GetConsoleScreenBufferInfo(console_handle, &original_info); 48 49 WORD color = 0; 50 switch (entry.log_level) { 51 case Level::Trace: // Grey 52 color = FOREGROUND_INTENSITY; 53 break; 54 case Level::Debug: // Cyan 55 color = FOREGROUND_GREEN | FOREGROUND_BLUE; 56 break; 57 case Level::Info: // Bright gray 58 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; 59 break; 60 case Level::Warning: // Bright yellow 61 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; 62 break; 63 case Level::Error: // Bright red 64 color = FOREGROUND_RED | FOREGROUND_INTENSITY; 65 break; 66 case Level::Critical: // Bright magenta 67 color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; 68 break; 69 case Level::Count: 70 UNREACHABLE(); 71 } 72 73 SetConsoleTextAttribute(console_handle, color); 74 #else 75 #define ESC "\x1b" 76 const char* color = ""; 77 switch (entry.log_level) { 78 case Level::Trace: // Grey 79 color = ESC "[1;30m"; 80 break; 81 case Level::Debug: // Cyan 82 color = ESC "[0;36m"; 83 break; 84 case Level::Info: // Bright gray 85 color = ESC "[0;37m"; 86 break; 87 case Level::Warning: // Bright yellow 88 color = ESC "[1;33m"; 89 break; 90 case Level::Error: // Bright red 91 color = ESC "[1;31m"; 92 break; 93 case Level::Critical: // Bright magenta 94 color = ESC "[1;35m"; 95 break; 96 case Level::Count: 97 UNREACHABLE(); 98 } 99 100 fputs(color, stderr); 101 #endif 102 103 PrintMessage(entry); 104 105 #ifdef _WIN32 106 SetConsoleTextAttribute(console_handle, original_info.wAttributes); 107 #else 108 fputs(ESC "[0m", stderr); 109 #undef ESC 110 #endif 111 } 112 113 void PrintMessageToLogcat([[maybe_unused]] const Entry& entry) { 114 #ifdef ANDROID 115 const auto str = FormatLogMessage(entry); 116 117 android_LogPriority android_log_priority; 118 switch (entry.log_level) { 119 case Level::Trace: 120 android_log_priority = ANDROID_LOG_VERBOSE; 121 break; 122 case Level::Debug: 123 android_log_priority = ANDROID_LOG_DEBUG; 124 break; 125 case Level::Info: 126 android_log_priority = ANDROID_LOG_INFO; 127 break; 128 case Level::Warning: 129 android_log_priority = ANDROID_LOG_WARN; 130 break; 131 case Level::Error: 132 android_log_priority = ANDROID_LOG_ERROR; 133 break; 134 case Level::Critical: 135 android_log_priority = ANDROID_LOG_FATAL; 136 break; 137 case Level::Count: 138 UNREACHABLE(); 139 } 140 __android_log_print(android_log_priority, "CitraNative", "%s", str.c_str()); 141 #endif 142 } 143 } // namespace Common::Log