[common/logging] Add thread names

Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2026-06-24 20:24:56 +00:00
parent 599ab16288
commit 22dc52009a
4 changed files with 34 additions and 28 deletions

View file

@ -41,6 +41,19 @@ namespace Common::Log {
namespace {
/// @brief A log entry. Log entries are store in a structured format to permit more varied output
/// formatting on different frontends, as well as facilitating filtering and aggregation.
struct Entry {
std::string_view thread_name;
std::string message;
std::chrono::microseconds timestamp;
Class log_class{};
Level log_level{};
const char* filename = nullptr;
const char* function = nullptr;
unsigned int line_num = 0;
};
/// @brief Returns the name of the passed log class as a C-string. Subclasses are separated by periods
/// instead of underscores as in the enumeration.
/// @note GetClassName is a macro defined by Windows.h, grrr...
@ -79,7 +92,7 @@ std::string FormatLogMessage(const Entry& entry) noexcept {
auto const time_fractional = uint32_t(entry.timestamp.count() % 1000000);
auto const class_name = GetLogClassName(entry.log_class);
auto const level_name = GetLevelName(entry.log_level);
return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}", time_seconds, time_fractional, class_name, level_name, entry.filename, entry.line_num, entry.function, entry.message);
return fmt::format("[{:4d}.{:06d}] {} <{}> (eden:{}) {}:{}:{}: {}", time_seconds, time_fractional, class_name, level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message);
}
namespace {
@ -165,7 +178,7 @@ struct Backend {
};
/// @brief Formatting specifier (to use with printf) of the equivalent fmt::format() expression
#define CCB_PRINTF_FMT "[%4d.%06d] %s <%s> %s:%u:%s: %s"
#define CCB_PRINTF_FMT "[%4d.%06d] %s <%s> (eden:%s) %s:%u:%s: %s"
/// @brief Instead of using fmt::format() just use the system's formatting capabilities directly
struct DirectFormatArgs {
@ -208,7 +221,7 @@ struct ColorConsoleBackend final : public Backend {
}());
SetConsoleTextAttribute(console_handle, color);
auto const df = GetDirectFormatArgs(entry);
std::fprintf(stdout, CCB_PRINTF_FMT "\n", df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str());
std::fprintf(stdout, CCB_PRINTF_FMT "\n", df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message.c_str());
}
}
void Flush() noexcept override {}
@ -234,7 +247,7 @@ struct ColorConsoleBackend final : public Backend {
}
}();
auto const df = GetDirectFormatArgs(entry);
std::fprintf(stdout, color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str());
std::fprintf(stdout, color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message.c_str());
#undef ESC
}
}
@ -338,7 +351,7 @@ struct LogcatBackend : public Backend {
}
}();
auto const df = GetDirectFormatArgs(entry);
__android_log_print(android_log_priority, "YuzuNative", CCB_PRINTF_FMT, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message.c_str());
__android_log_print(android_log_priority, "YuzuNative", CCB_PRINTF_FMT, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.thread_name.data(), entry.filename, entry.line_num, entry.function, entry.message.c_str());
}
void Flush() noexcept override {}
};
@ -421,6 +434,7 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, u
auto const flush = ::Settings::values.log_flush_line.GetValue();
logging_instance->ForEachBackend([=](Backend& backend) {
backend.Write(Entry{
.thread_name = Common::GetCurrentThreadName(),
.message = fmt::vformat(format, args),
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
.log_class = log_class,

View file

@ -140,25 +140,4 @@ void Stop();
void SetGlobalFilter(const Filter& filter);
void SetColorConsoleBackendEnabled(bool enabled);
/// @brief A log entry. Log entries are store in a structured format to permit more varied output
/// formatting on different frontends, as well as facilitating filtering and aggregation.
struct Entry {
std::string message;
std::chrono::microseconds timestamp;
Class log_class{};
Level log_level{};
const char* filename = nullptr;
const char* function = nullptr;
unsigned int line_num = 0;
};
/// Formats a log entry into the provided text buffer.
std::string FormatLogMessage(const Entry& entry) noexcept;
/// Prints the same message as `PrintMessage`, but colored according to the severity level.
void PrintColoredMessage(const Entry& entry) noexcept;
/// Formats and prints a log entry to the android logcat.
void PrintMessageToLogcat(const Entry& entry) noexcept;
} // namespace Common::Log

View file

@ -52,6 +52,13 @@
namespace Common {
// The use of TLS is justified as it is faster than using pthread_* functions
// and generally will be better long term... yeah %fs/%gs reloads aren't great
// but it's better than doing a potential call-stack-fuckery...
thread_local struct {
std::string name{};
} per_thread_data = {};
void SetCurrentThreadPriority(ThreadPriority new_priority) {
#ifdef _WIN32
int windows_priority = [&]() {
@ -96,7 +103,7 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
#endif
}
void SetCurrentThreadName(const char* name) {
void SetCurrentThreadName(const char* name) noexcept {
#ifdef _MSC_VER
// Sets the debugger-visible name of the current thread.
if (auto pf = (decltype(&SetThreadDescription))(void*)GetProcAddress(GetModuleHandle(TEXT("KernelBase.dll")), "SetThreadDescription"); pf)
@ -130,6 +137,11 @@ void SetCurrentThreadName(const char* name) {
#else
pthread_setname_np(pthread_self(), name);
#endif
per_thread_data.name = std::string{name};
}
std::string_view GetCurrentThreadName() noexcept {
return per_thread_data.name;
}
void PinCurrentThreadToPerformanceCore(size_t core_id) {

View file

@ -100,7 +100,8 @@ enum class ThreadPriority : u32 {
};
void SetCurrentThreadPriority(ThreadPriority new_priority);
void SetCurrentThreadName(const char* name);
void SetCurrentThreadName(const char* name) noexcept;
std::string_view GetCurrentThreadName() noexcept;
void PinCurrentThreadToPerformanceCore(size_t core_id);
} // namespace Common