| |
| |
|
|
| #include <array> |
| #include <cstdio> |
|
|
| #ifdef _WIN32 |
| #include <windows.h> |
| #endif |
|
|
| #ifdef ANDROID |
| #include <android/log.h> |
| #endif |
|
|
| #include "common/assert.h" |
| #include "common/logging/filter.h" |
| #include "common/logging/log.h" |
| #include "common/logging/log_entry.h" |
| #include "common/logging/text_formatter.h" |
|
|
| namespace Common::Log { |
|
|
| std::string FormatLogMessage(const Entry& entry) { |
| unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000); |
| unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000); |
|
|
| const char* class_name = GetLogClassName(entry.log_class); |
| const char* level_name = GetLevelName(entry.log_level); |
|
|
| return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}", time_seconds, time_fractional, |
| class_name, level_name, entry.filename, entry.function, entry.line_num, |
| entry.message); |
| } |
|
|
| void PrintMessage(const Entry& entry) { |
| const auto str = FormatLogMessage(entry).append(1, '\n'); |
| fputs(str.c_str(), stderr); |
| } |
|
|
| void PrintColoredMessage(const Entry& entry) { |
| #ifdef _WIN32 |
| HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE); |
| if (console_handle == INVALID_HANDLE_VALUE) { |
| return; |
| } |
|
|
| CONSOLE_SCREEN_BUFFER_INFO original_info = {}; |
| GetConsoleScreenBufferInfo(console_handle, &original_info); |
|
|
| WORD color = 0; |
| switch (entry.log_level) { |
| case Level::Trace: |
| color = FOREGROUND_INTENSITY; |
| break; |
| case Level::Debug: |
| color = FOREGROUND_GREEN | FOREGROUND_BLUE; |
| break; |
| case Level::Info: |
| color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; |
| break; |
| case Level::Warning: |
| color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; |
| break; |
| case Level::Error: |
| color = FOREGROUND_RED | FOREGROUND_INTENSITY; |
| break; |
| case Level::Critical: |
| color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; |
| break; |
| case Level::Count: |
| UNREACHABLE(); |
| } |
|
|
| SetConsoleTextAttribute(console_handle, color); |
| #else |
| #define ESC "\x1b" |
| const char* color = ""; |
| switch (entry.log_level) { |
| case Level::Trace: |
| color = ESC "[1;30m"; |
| break; |
| case Level::Debug: |
| color = ESC "[0;36m"; |
| break; |
| case Level::Info: |
| color = ESC "[0;37m"; |
| break; |
| case Level::Warning: |
| color = ESC "[1;33m"; |
| break; |
| case Level::Error: |
| color = ESC "[1;31m"; |
| break; |
| case Level::Critical: |
| color = ESC "[1;35m"; |
| break; |
| case Level::Count: |
| UNREACHABLE(); |
| } |
|
|
| fputs(color, stderr); |
| #endif |
|
|
| PrintMessage(entry); |
|
|
| #ifdef _WIN32 |
| SetConsoleTextAttribute(console_handle, original_info.wAttributes); |
| #else |
| fputs(ESC "[0m", stderr); |
| #undef ESC |
| #endif |
| } |
|
|
| void PrintMessageToLogcat(const Entry& entry) { |
| #ifdef ANDROID |
| const auto str = FormatLogMessage(entry); |
|
|
| android_LogPriority android_log_priority; |
| switch (entry.log_level) { |
| case Level::Trace: |
| android_log_priority = ANDROID_LOG_VERBOSE; |
| break; |
| case Level::Debug: |
| android_log_priority = ANDROID_LOG_DEBUG; |
| break; |
| case Level::Info: |
| android_log_priority = ANDROID_LOG_INFO; |
| break; |
| case Level::Warning: |
| android_log_priority = ANDROID_LOG_WARN; |
| break; |
| case Level::Error: |
| android_log_priority = ANDROID_LOG_ERROR; |
| break; |
| case Level::Critical: |
| android_log_priority = ANDROID_LOG_FATAL; |
| break; |
| case Level::Count: |
| UNREACHABLE(); |
| } |
| __android_log_print(android_log_priority, "YuzuNative", "%s", str.c_str()); |
| #endif |
| } |
| } |
|
|