mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 20:15:32 +00:00
Log: Add option coloured variants
This commit is contained in:
parent
596cca9be2
commit
3f41dcc97d
@ -44,36 +44,24 @@ static void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUse
|
|||||||
const std::unique_lock<std::mutex>& lock);
|
const std::unique_lock<std::mutex>& lock);
|
||||||
|
|
||||||
static bool FilterTest(Channel channel, Level level);
|
static bool FilterTest(Channel channel, Level level);
|
||||||
static void ExecuteCallbacks(Channel channel, const char* functionName, Level level, std::string_view message,
|
static void ExecuteCallbacks(MessageCategory cat, const char* functionName, std::string_view message);
|
||||||
const std::unique_lock<std::mutex>& lock);
|
static void FormatLogMessageForDisplay(fmt::memory_buffer& buffer, MessageCategory cat, const char* functionName,
|
||||||
static void FormatLogMessageForDisplay(fmt::memory_buffer& buffer, const char* channelName, const char* functionName,
|
std::string_view message, bool timestamp, bool ansi_color_code);
|
||||||
Level level, std::string_view message, bool timestamp, bool ansi_color_code);
|
static void ConsoleOutputLogCallback(void* pUserParam, MessageCategory cat, const char* functionName,
|
||||||
static void ConsoleOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
|
|
||||||
std::string_view message);
|
std::string_view message);
|
||||||
static void DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
|
static void DebugOutputLogCallback(void* pUserParam, MessageCategory cat, const char* functionName,
|
||||||
std::string_view message);
|
std::string_view message);
|
||||||
static void FileOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
|
static void FileOutputLogCallback(void* pUserParam, MessageCategory cat, const char* functionName,
|
||||||
std::string_view message);
|
std::string_view message);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void FormatLogMessageAndPrint(const char* channelName, const char* functionName, Level level,
|
static void FormatLogMessageAndPrint(MessageCategory cat, const char* functionName, std::string_view message,
|
||||||
std::string_view message, bool timestamp, bool ansi_color_code, const T& callback);
|
bool timestamp, bool ansi_color_code, const T& callback);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void FormatLogMessageAndPrintW(const char* channelName, const char* functionName, Level level,
|
static void FormatLogMessageAndPrintW(MessageCategory cat, const char* functionName, std::string_view message,
|
||||||
std::string_view message, bool timestamp, bool ansi_color_code,
|
bool timestamp, bool ansi_color_code, const T& callback);
|
||||||
const T& callback);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ALWAYS_INLINE static Channel UnpackLogChannel(PackedChannelAndLevel cat)
|
|
||||||
{
|
|
||||||
return static_cast<Channel>(cat >> 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE static Level UnpackLogLevel(PackedChannelAndLevel cat)
|
|
||||||
{
|
|
||||||
return static_cast<Level>(cat & 0x7);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr const std::array<char, static_cast<size_t>(Level::MaxCount)> s_log_level_characters = {
|
static constexpr const std::array<char, static_cast<size_t>(Level::MaxCount)> s_log_level_characters = {
|
||||||
{'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'}};
|
{'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'}};
|
||||||
|
|
||||||
@ -191,31 +179,59 @@ bool Log::IsDebugOutputEnabled()
|
|||||||
return s_state.debug_output_enabled;
|
return s_state.debug_output_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::ExecuteCallbacks(Channel channel, const char* functionName, Level level, std::string_view message,
|
Log::Color Log::GetColorForLevel(Level level)
|
||||||
const std::unique_lock<std::mutex>& lock)
|
|
||||||
{
|
{
|
||||||
for (RegisteredCallback& callback : s_state.callbacks)
|
static constexpr const std::array s_level_colours = {
|
||||||
callback.Function(callback.Parameter, s_log_channel_names[static_cast<size_t>(channel)], functionName, level,
|
Color::Default, // None
|
||||||
message);
|
Color::StrongRed, // Error
|
||||||
}
|
Color::StrongYellow, // Warning
|
||||||
|
Color::StrongWhite, // Info
|
||||||
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& buffer, const char* channelName,
|
Color::StrongGreen, // Verbose
|
||||||
const char* functionName, Level level,
|
Color::White, // Dev
|
||||||
std::string_view message, bool timestamp,
|
Color::Green, // Debug
|
||||||
bool ansi_color_code)
|
Color::Blue, // Trace
|
||||||
{
|
|
||||||
static constexpr const std::array s_ansi_color_codes = {
|
|
||||||
"\033[0m"sv, // None
|
|
||||||
"\033[1;31m"sv, // Error
|
|
||||||
"\033[1;33m"sv, // Warning
|
|
||||||
"\033[1;37m"sv, // Info
|
|
||||||
"\033[1;32m"sv, // Verbose
|
|
||||||
"\033[0;37m"sv, // Dev
|
|
||||||
"\033[0;32m"sv, // Debug
|
|
||||||
"\033[0;34m"sv, // Trace
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string_view color_start = ansi_color_code ? s_ansi_color_codes[static_cast<size_t>(level)] : ""sv;
|
return s_level_colours[static_cast<size_t>(level)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::ExecuteCallbacks(MessageCategory cat, const char* functionName, std::string_view message)
|
||||||
|
{
|
||||||
|
for (RegisteredCallback& callback : s_state.callbacks)
|
||||||
|
callback.Function(callback.Parameter, cat, functionName, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& buffer, MessageCategory cat,
|
||||||
|
const char* functionName, std::string_view message,
|
||||||
|
bool timestamp, bool ansi_color_code)
|
||||||
|
{
|
||||||
|
static constexpr const std::array s_ansi_color_codes = {
|
||||||
|
"\033[0m"sv, // default
|
||||||
|
"\033[30m\033[1m"sv, // black
|
||||||
|
"\033[32m"sv, // green
|
||||||
|
"\033[31m"sv, // red
|
||||||
|
"\033[34m"sv, // blue
|
||||||
|
"\033[35m"sv, // magenta
|
||||||
|
"\033[38;5;217m"sv, // orange
|
||||||
|
"\033[36m"sv, // cyan
|
||||||
|
"\033[33m"sv, // yellow
|
||||||
|
"\033[37m"sv, // white
|
||||||
|
"\033[30m\033[1m"sv, // strong black
|
||||||
|
"\033[31m\033[1m"sv, // strong red
|
||||||
|
"\033[32m\033[1m"sv, // strong green
|
||||||
|
"\033[34m\033[1m"sv, // strong blue
|
||||||
|
"\033[35m\033[1m"sv, // strong magenta
|
||||||
|
"\033[38;5;202m"sv, // strong orange
|
||||||
|
"\033[36m\033[1m"sv, // strong cyan
|
||||||
|
"\033[33m\033[1m"sv, // strong yellow
|
||||||
|
"\033[37m\033[1m"sv, // strong white
|
||||||
|
};
|
||||||
|
|
||||||
|
const Level level = UnpackLevel(cat);
|
||||||
|
const Color color = (UnpackColor(cat) == Color::Default) ? GetColorForLevel(level) : UnpackColor(cat);
|
||||||
|
const char* channel_name = GetChannelName(UnpackChannel(cat));
|
||||||
|
|
||||||
|
std::string_view color_start = ansi_color_code ? s_ansi_color_codes[static_cast<size_t>(color)] : ""sv;
|
||||||
std::string_view color_end = ansi_color_code ? s_ansi_color_codes[0] : ""sv;
|
std::string_view color_end = ansi_color_code ? s_ansi_color_codes[0] : ""sv;
|
||||||
|
|
||||||
auto appender = std::back_inserter(buffer);
|
auto appender = std::back_inserter(buffer);
|
||||||
@ -243,7 +259,7 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
fmt::format_to(appender, "[{:10.4f}] {}{}/{}: {}{}{}", message_time, color_start,
|
fmt::format_to(appender, "[{:10.4f}] {}{}/{}: {}{}{}", message_time, color_start,
|
||||||
s_log_level_characters[static_cast<size_t>(level)], channelName, sub_message, color_end,
|
s_log_level_characters[static_cast<size_t>(level)], channel_name, sub_message, color_end,
|
||||||
end_message);
|
end_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,30 +279,30 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
fmt::format_to(appender, "{}{}/{}: {}{}\n", color_start, s_log_level_characters[static_cast<size_t>(level)],
|
fmt::format_to(appender, "{}{}/{}: {}{}\n", color_start, s_log_level_characters[static_cast<size_t>(level)],
|
||||||
channelName, message, color_end);
|
channel_name, message, color_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrint(const char* channelName, const char* functionName, Level level,
|
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrint(MessageCategory cat, const char* functionName,
|
||||||
std::string_view message, bool timestamp, bool ansi_color_code,
|
std::string_view message, bool timestamp, bool ansi_color_code,
|
||||||
const T& callback)
|
const T& callback)
|
||||||
{
|
{
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
FormatLogMessageForDisplay(buffer, channelName, functionName, level, message, timestamp, ansi_color_code);
|
FormatLogMessageForDisplay(buffer, cat, functionName, message, timestamp, ansi_color_code);
|
||||||
callback(std::string_view(buffer.data(), buffer.size()));
|
callback(std::string_view(buffer.data(), buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrintW(const char* channelName, const char* functionName,
|
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrintW(MessageCategory cat, const char* functionName,
|
||||||
Level level, std::string_view message, bool timestamp,
|
std::string_view message, bool timestamp,
|
||||||
bool ansi_color_code, const T& callback)
|
bool ansi_color_code, const T& callback)
|
||||||
{
|
{
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
FormatLogMessageForDisplay(buffer, channelName, functionName, level, message, timestamp, ansi_color_code);
|
FormatLogMessageForDisplay(buffer, cat, functionName, message, timestamp, ansi_color_code);
|
||||||
|
|
||||||
// Convert to UTF-16 first so unicode characters display correctly. NT is going to do it
|
// Convert to UTF-16 first so unicode characters display correctly. NT is going to do it
|
||||||
// anyway...
|
// anyway...
|
||||||
@ -326,7 +342,7 @@ static bool EnableVirtualTerminalProcessing(HANDLE hConsole)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
|
void Log::ConsoleOutputLogCallback(void* pUserParam, MessageCategory cat, const char* functionName,
|
||||||
std::string_view message)
|
std::string_view message)
|
||||||
{
|
{
|
||||||
if (!s_state.console_output_enabled)
|
if (!s_state.console_output_enabled)
|
||||||
@ -334,29 +350,28 @@ void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, co
|
|||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
FormatLogMessageAndPrintW(
|
FormatLogMessageAndPrintW(
|
||||||
channelName, functionName, level, message, s_state.console_output_timestamps, true,
|
cat, functionName, message, s_state.console_output_timestamps, true, [cat](const std::wstring_view& message) {
|
||||||
[level](const std::wstring_view& message) {
|
HANDLE hOutput = (UnpackLevel(cat) <= Level::Warning) ? s_state.hConsoleStdErr : s_state.hConsoleStdOut;
|
||||||
HANDLE hOutput = (level <= Level::Warning) ? s_state.hConsoleStdErr : s_state.hConsoleStdOut;
|
|
||||||
DWORD chars_written;
|
DWORD chars_written;
|
||||||
WriteConsoleW(hOutput, message.data(), static_cast<DWORD>(message.length()), &chars_written, nullptr);
|
WriteConsoleW(hOutput, message.data(), static_cast<DWORD>(message.length()), &chars_written, nullptr);
|
||||||
});
|
});
|
||||||
#elif !defined(__ANDROID__)
|
#elif !defined(__ANDROID__)
|
||||||
FormatLogMessageAndPrint(channelName, functionName, level, message, s_state.console_output_timestamps, true,
|
FormatLogMessageAndPrint(
|
||||||
[level](std::string_view message) {
|
cat, functionName, message, s_state.console_output_timestamps, true, [cat](std::string_view message) {
|
||||||
const int outputFd = (level <= Log::Level::Warning) ? STDERR_FILENO : STDOUT_FILENO;
|
const int outputFd = (UnpackLevel(cat) <= Log::Level::Warning) ? STDERR_FILENO : STDOUT_FILENO;
|
||||||
write(outputFd, message.data(), message.length());
|
write(outputFd, message.data(), message.length());
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
|
void Log::DebugOutputLogCallback(void* pUserParam, MessageCategory cat, const char* functionName,
|
||||||
std::string_view message)
|
std::string_view message)
|
||||||
{
|
{
|
||||||
if (!s_state.debug_output_enabled)
|
if (!s_state.debug_output_enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
FormatLogMessageAndPrintW(channelName, functionName, level, message, false, false,
|
FormatLogMessageAndPrintW(cat, functionName, message, false, false,
|
||||||
[](const std::wstring_view& message) { OutputDebugStringW(message.data()); });
|
[](const std::wstring_view& message) { OutputDebugStringW(message.data()); });
|
||||||
#elif defined(__ANDROID__)
|
#elif defined(__ANDROID__)
|
||||||
if (message.empty())
|
if (message.empty())
|
||||||
@ -373,8 +388,8 @@ void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, cons
|
|||||||
ANDROID_LOG_DEBUG, // Trace
|
ANDROID_LOG_DEBUG, // Trace
|
||||||
};
|
};
|
||||||
|
|
||||||
__android_log_print(logPriority[static_cast<size_t>(level)], channelName, "%.*s", static_cast<int>(message.length()),
|
__android_log_print(logPriority[static_cast<size_t>(UnpackLevel(cat))], GetChannelName(UnpackChannel(cat)), "%.*s",
|
||||||
message.data());
|
static_cast<int>(message.length()), message.data());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,13 +486,13 @@ void Log::SetDebugOutputParams(bool enabled)
|
|||||||
UnregisterCallback(DebugOutputLogCallback, nullptr, lock);
|
UnregisterCallback(DebugOutputLogCallback, nullptr, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::FileOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
|
void Log::FileOutputLogCallback(void* pUserParam, MessageCategory cat, const char* functionName,
|
||||||
std::string_view message)
|
std::string_view message)
|
||||||
{
|
{
|
||||||
if (!s_state.file_output_enabled)
|
if (!s_state.file_output_enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FormatLogMessageAndPrint(channelName, functionName, level, message, true, false, [](std::string_view message) {
|
FormatLogMessageAndPrint(cat, functionName, message, true, false, [](std::string_view message) {
|
||||||
std::fwrite(message.data(), 1, message.size(), s_state.file_handle.get());
|
std::fwrite(message.data(), 1, message.size(), s_state.file_handle.get());
|
||||||
std::fflush(s_state.file_handle.get());
|
std::fflush(s_state.file_handle.get());
|
||||||
});
|
});
|
||||||
@ -494,8 +509,8 @@ void Log::SetFileOutputParams(bool enabled, const char* filename, bool timestamp
|
|||||||
s_state.file_handle = FileSystem::OpenManagedCFile(filename, "wb");
|
s_state.file_handle = FileSystem::OpenManagedCFile(filename, "wb");
|
||||||
if (!s_state.file_handle) [[unlikely]]
|
if (!s_state.file_handle) [[unlikely]]
|
||||||
{
|
{
|
||||||
ExecuteCallbacks(Log::Channel::Log, __FUNCTION__, Level::Error,
|
ExecuteCallbacks(PackCategory(Channel::Log, Level::Error, Color::Default), nullptr,
|
||||||
TinyString::from_format("Failed to open log file '{}'", filename), lock);
|
TinyString::from_format("Failed to open log file '{}'", filename));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,57 +550,54 @@ void Log::SetLogChannelEnabled(Channel channel, bool enabled)
|
|||||||
s_state.log_channels_enabled[static_cast<size_t>(channel)] = enabled;
|
s_state.log_channels_enabled[static_cast<size_t>(channel)] = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* Log::GetChannelName(Channel channel)
|
||||||
|
{
|
||||||
|
return s_log_channel_names[static_cast<size_t>(channel)];
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE bool Log::FilterTest(Channel channel, Level level)
|
ALWAYS_INLINE_RELEASE bool Log::FilterTest(Channel channel, Level level)
|
||||||
{
|
{
|
||||||
return (level <= s_state.log_level && s_state.log_channels_enabled[static_cast<size_t>(channel)]);
|
return (level <= s_state.log_level && s_state.log_channels_enabled[static_cast<size_t>(channel)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::Write(PackedChannelAndLevel cat, std::string_view message)
|
void Log::Write(MessageCategory cat, std::string_view message)
|
||||||
{
|
{
|
||||||
const Channel channel = UnpackLogChannel(cat);
|
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
|
||||||
const Level level = UnpackLogLevel(cat);
|
|
||||||
if (!FilterTest(channel, level))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::unique_lock lock(s_state.callbacks_mutex);
|
std::unique_lock lock(s_state.callbacks_mutex);
|
||||||
ExecuteCallbacks(channel, nullptr, level, message, lock);
|
ExecuteCallbacks(cat, nullptr, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::Write(PackedChannelAndLevel cat, const char* functionName, std::string_view message)
|
void Log::Write(MessageCategory cat, const char* functionName, std::string_view message)
|
||||||
{
|
{
|
||||||
const Channel channel = UnpackLogChannel(cat);
|
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
|
||||||
const Level level = UnpackLogLevel(cat);
|
|
||||||
if (!FilterTest(channel, level))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::unique_lock lock(s_state.callbacks_mutex);
|
std::unique_lock lock(s_state.callbacks_mutex);
|
||||||
ExecuteCallbacks(channel, functionName, level, message, lock);
|
ExecuteCallbacks(cat, functionName, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::WriteFmtArgs(PackedChannelAndLevel cat, fmt::string_view fmt, fmt::format_args args)
|
void Log::WriteFmtArgs(MessageCategory cat, fmt::string_view fmt, fmt::format_args args)
|
||||||
{
|
{
|
||||||
const Channel channel = UnpackLogChannel(cat);
|
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
|
||||||
const Level level = UnpackLogLevel(cat);
|
|
||||||
if (!FilterTest(channel, level))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
|
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
|
||||||
|
|
||||||
std::unique_lock lock(s_state.callbacks_mutex);
|
std::unique_lock lock(s_state.callbacks_mutex);
|
||||||
ExecuteCallbacks(channel, nullptr, level, std::string_view(buffer.data(), buffer.size()), lock);
|
ExecuteCallbacks(cat, nullptr, std::string_view(buffer.data(), buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::WriteFmtArgs(PackedChannelAndLevel cat, const char* functionName, fmt::string_view fmt, fmt::format_args args)
|
void Log::WriteFmtArgs(MessageCategory cat, const char* functionName, fmt::string_view fmt, fmt::format_args args)
|
||||||
{
|
{
|
||||||
const Channel channel = UnpackLogChannel(cat);
|
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
|
||||||
const Level level = UnpackLogLevel(cat);
|
|
||||||
if (!FilterTest(channel, level))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
|
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
|
||||||
|
|
||||||
std::unique_lock lock(s_state.callbacks_mutex);
|
std::unique_lock lock(s_state.callbacks_mutex);
|
||||||
ExecuteCallbacks(channel, functionName, level, std::string_view(buffer.data(), buffer.size()), lock);
|
ExecuteCallbacks(cat, functionName, std::string_view(buffer.data(), buffer.size()));
|
||||||
}
|
}
|
||||||
|
122
src/common/log.h
122
src/common/log.h
@ -29,6 +29,31 @@ enum class Level : u32
|
|||||||
MaxCount
|
MaxCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Color : u32
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Black,
|
||||||
|
Green,
|
||||||
|
Red,
|
||||||
|
Blue,
|
||||||
|
Magenta,
|
||||||
|
Orange,
|
||||||
|
Cyan,
|
||||||
|
Yellow,
|
||||||
|
White,
|
||||||
|
StrongBlack,
|
||||||
|
StrongRed,
|
||||||
|
StrongGreen,
|
||||||
|
StrongBlue,
|
||||||
|
StrongMagenta,
|
||||||
|
StrongOrange,
|
||||||
|
StrongCyan,
|
||||||
|
StrongYellow,
|
||||||
|
StrongWhite,
|
||||||
|
|
||||||
|
MaxCount
|
||||||
|
};
|
||||||
|
|
||||||
enum class Channel : u32
|
enum class Channel : u32
|
||||||
{
|
{
|
||||||
#define LOG_CHANNEL_ENUM(X) X,
|
#define LOG_CHANNEL_ENUM(X) X,
|
||||||
@ -38,8 +63,28 @@ enum class Channel : u32
|
|||||||
MaxCount
|
MaxCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Packs a level and channel into one 16-bit number.
|
||||||
|
using MessageCategory = u32;
|
||||||
|
[[maybe_unused]] ALWAYS_INLINE static constexpr u32 PackCategory(Channel channel, Level level, Color colour)
|
||||||
|
{
|
||||||
|
return ((static_cast<MessageCategory>(colour) << 10) | (static_cast<MessageCategory>(channel) << 3) |
|
||||||
|
static_cast<MessageCategory>(level));
|
||||||
|
}
|
||||||
|
[[maybe_unused]] ALWAYS_INLINE static constexpr Color UnpackColor(MessageCategory cat)
|
||||||
|
{
|
||||||
|
return static_cast<Color>((cat >> 10) & 0x1f);
|
||||||
|
}
|
||||||
|
[[maybe_unused]] ALWAYS_INLINE static constexpr Channel UnpackChannel(MessageCategory cat)
|
||||||
|
{
|
||||||
|
return static_cast<Channel>((cat >> 3) & 0x7f);
|
||||||
|
}
|
||||||
|
[[maybe_unused]] ALWAYS_INLINE static constexpr Level UnpackLevel(MessageCategory cat)
|
||||||
|
{
|
||||||
|
return static_cast<Level>(cat & 0x7);
|
||||||
|
}
|
||||||
|
|
||||||
// log message callback type
|
// log message callback type
|
||||||
using CallbackFunctionType = void (*)(void* pUserParam, const char* channelName, const char* functionName, Level level,
|
using CallbackFunctionType = void (*)(void* pUserParam, MessageCategory category, const char* functionName,
|
||||||
std::string_view message);
|
std::string_view message);
|
||||||
|
|
||||||
// registers a log callback
|
// registers a log callback
|
||||||
@ -79,41 +124,65 @@ void SetLogLevel(Level level);
|
|||||||
// Sets global filter, any messages from these channels won't be sent to any of the logging sinks.
|
// Sets global filter, any messages from these channels won't be sent to any of the logging sinks.
|
||||||
void SetLogChannelEnabled(Channel channel, bool enabled);
|
void SetLogChannelEnabled(Channel channel, bool enabled);
|
||||||
|
|
||||||
// Packs a level and channel into one 16-bit number.
|
// Returns the name of the specified log channel.
|
||||||
using PackedChannelAndLevel = u32;
|
const char* GetChannelName(Channel channel);
|
||||||
[[maybe_unused]] ALWAYS_INLINE static u32 PackChannelAndLevel(Channel channel, Level level)
|
|
||||||
{
|
// Returns the default colour for a log level.
|
||||||
return ((static_cast<PackedChannelAndLevel>(channel) << 3) | static_cast<PackedChannelAndLevel>(level));
|
Color GetColorForLevel(Level level);
|
||||||
}
|
|
||||||
|
|
||||||
// writes a message to the log
|
// writes a message to the log
|
||||||
void Write(PackedChannelAndLevel cat, std::string_view message);
|
void Write(MessageCategory cat, std::string_view message);
|
||||||
void Write(PackedChannelAndLevel cat, const char* functionName, std::string_view message);
|
void Write(MessageCategory cat, const char* functionName, std::string_view message);
|
||||||
void WriteFmtArgs(PackedChannelAndLevel cat, fmt::string_view fmt, fmt::format_args args);
|
void WriteFmtArgs(MessageCategory cat, fmt::string_view fmt, fmt::format_args args);
|
||||||
void WriteFmtArgs(PackedChannelAndLevel cat, const char* functionName, fmt::string_view fmt, fmt::format_args args);
|
void WriteFmtArgs(MessageCategory cat, const char* functionName, fmt::string_view fmt, fmt::format_args args);
|
||||||
|
|
||||||
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, std::string_view message)
|
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, std::string_view message)
|
||||||
{
|
{
|
||||||
if (level <= GetLogLevel()) [[unlikely]]
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
Write(PackChannelAndLevel(channel, level), message);
|
Write(PackCategory(channel, level, Color::Default), message);
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level, std::string_view message)
|
ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level, std::string_view message)
|
||||||
{
|
{
|
||||||
if (level <= GetLogLevel()) [[unlikely]]
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
Write(PackChannelAndLevel(channel, level), functionName, message);
|
Write(PackCategory(channel, level, Color::Default), functionName, message);
|
||||||
}
|
}
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, fmt::format_string<T...> fmt, T&&... args)
|
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, fmt::format_string<T...> fmt, T&&... args)
|
||||||
{
|
{
|
||||||
if (level <= GetLogLevel()) [[unlikely]]
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
WriteFmtArgs(PackChannelAndLevel(channel, level), fmt, fmt::make_format_args(args...));
|
WriteFmtArgs(PackCategory(channel, level, Color::Default), fmt, fmt::make_format_args(args...));
|
||||||
}
|
}
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level,
|
ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level,
|
||||||
fmt::format_string<T...> fmt, T&&... args)
|
fmt::format_string<T...> fmt, T&&... args)
|
||||||
{
|
{
|
||||||
if (level <= GetLogLevel()) [[unlikely]]
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
WriteFmtArgs(PackChannelAndLevel(channel, level), functionName, fmt, fmt::make_format_args(args...));
|
WriteFmtArgs(PackCategory(channel, level, Color::Default), functionName, fmt, fmt::make_format_args(args...));
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, Color colour, std::string_view message)
|
||||||
|
{
|
||||||
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
|
Write(PackCategory(channel, level, colour), message);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level, Color colour,
|
||||||
|
std::string_view message)
|
||||||
|
{
|
||||||
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
|
Write(PackCategory(channel, level, colour), functionName, message);
|
||||||
|
}
|
||||||
|
template<typename... T>
|
||||||
|
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, Color colour, fmt::format_string<T...> fmt,
|
||||||
|
T&&... args)
|
||||||
|
{
|
||||||
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
|
WriteFmtArgs(PackCategory(channel, level, colour), fmt, fmt::make_format_args(args...));
|
||||||
|
}
|
||||||
|
template<typename... T>
|
||||||
|
ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level, Color colour,
|
||||||
|
fmt::format_string<T...> fmt, T&&... args)
|
||||||
|
{
|
||||||
|
if (level <= GetLogLevel()) [[unlikely]]
|
||||||
|
WriteFmtArgs(PackCategory(channel, level, colour), functionName, fmt, fmt::make_format_args(args...));
|
||||||
}
|
}
|
||||||
} // namespace Log
|
} // namespace Log
|
||||||
|
|
||||||
@ -139,3 +208,26 @@ ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, L
|
|||||||
{ \
|
{ \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define ERROR_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, __func__, Log::Level::Error, Log::Color::colour, __VA_ARGS__)
|
||||||
|
#define WARNING_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, __func__, Log::Level::Warning, Log::Color::colour, __VA_ARGS__)
|
||||||
|
#define INFO_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Info, Log::Color::colour, __VA_ARGS__)
|
||||||
|
#define VERBOSE_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Verbose, Log::Color::colour, __VA_ARGS__)
|
||||||
|
#define DEV_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Dev, Log::Color::colour, __VA_ARGS__)
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define DEBUG_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Debug, Log::Color::colour, __VA_ARGS__)
|
||||||
|
#define TRACE_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Trace, Log::Color::colour,__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DEBUG_COLOR_LOG(colour, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
} while (0)
|
||||||
|
#define TRACE_COLOR_LOG(colour, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
@ -77,7 +77,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!stop_on_error)
|
if (!stop_on_error)
|
||||||
{
|
{
|
||||||
Log::WriteFmtArgs(Log::PackChannelAndLevel(Log::Channel::Cheats, Log::Level::Warning), fmt,
|
Log::WriteFmtArgs(Log::PackCategory(Log::Channel::Cheats, Log::Level::Warning, Log::Color::StrongOrange), fmt,
|
||||||
fmt::make_format_args(args...));
|
fmt::make_format_args(args...));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ void LogWindow::onSaveTriggered()
|
|||||||
tr("Log was written to %1.\n").arg(path));
|
tr("Log was written to %1.\n").arg(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogWindow::logCallback(void* pUserParam, const char* channelName, const char* functionName, Log::Level level,
|
void LogWindow::logCallback(void* pUserParam, Log::MessageCategory cat, const char* functionName,
|
||||||
std::string_view message)
|
std::string_view message)
|
||||||
{
|
{
|
||||||
LogWindow* this_ptr = static_cast<LogWindow*>(pUserParam);
|
LogWindow* this_ptr = static_cast<LogWindow*>(pUserParam);
|
||||||
@ -267,16 +267,17 @@ void LogWindow::logCallback(void* pUserParam, const char* channelName, const cha
|
|||||||
qmessage.append(QUtf8StringView(message.data(), message.length()));
|
qmessage.append(QUtf8StringView(message.data(), message.length()));
|
||||||
qmessage.append(QChar('\n'));
|
qmessage.append(QChar('\n'));
|
||||||
|
|
||||||
const QLatin1StringView qchannel((level <= Log::Level::Warning) ? functionName : channelName);
|
const QLatin1StringView qchannel(
|
||||||
|
(Log::UnpackLevel(cat) <= Log::Level::Warning) ? functionName : Log::GetChannelName(Log::UnpackChannel(cat)));
|
||||||
|
|
||||||
if (QThread::isMainThread())
|
if (QThread::isMainThread())
|
||||||
{
|
{
|
||||||
this_ptr->appendMessage(qchannel, static_cast<u32>(level), qmessage);
|
this_ptr->appendMessage(qchannel, static_cast<u32>(cat), qmessage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(this_ptr, "appendMessage", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(this_ptr, "appendMessage", Qt::QueuedConnection,
|
||||||
Q_ARG(const QLatin1StringView&, qchannel), Q_ARG(quint32, static_cast<u32>(level)),
|
Q_ARG(const QLatin1StringView&, qchannel), Q_ARG(quint32, static_cast<u32>(cat)),
|
||||||
Q_ARG(const QString&, qmessage));
|
Q_ARG(const QString&, qmessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,7 +305,7 @@ void LogWindow::changeEvent(QEvent* event)
|
|||||||
QMainWindow::changeEvent(event);
|
QMainWindow::changeEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, const QString& message)
|
void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 cat, const QString& message)
|
||||||
{
|
{
|
||||||
QTextCursor temp_cursor = m_text->textCursor();
|
QTextCursor temp_cursor = m_text->textCursor();
|
||||||
QScrollBar* scrollbar = m_text->verticalScrollBar();
|
QScrollBar* scrollbar = m_text->verticalScrollBar();
|
||||||
@ -316,28 +317,50 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, c
|
|||||||
{
|
{
|
||||||
static constexpr const QChar level_characters[static_cast<size_t>(Log::Level::MaxCount)] = {'X', 'E', 'W', 'I',
|
static constexpr const QChar level_characters[static_cast<size_t>(Log::Level::MaxCount)] = {'X', 'E', 'W', 'I',
|
||||||
'V', 'D', 'B', 'T'};
|
'V', 'D', 'B', 'T'};
|
||||||
static constexpr const QColor level_colors[2][static_cast<size_t>(Log::Level::MaxCount)] = {
|
static constexpr const QColor message_colors[2][static_cast<size_t>(Log::Color::MaxCount)] = {
|
||||||
{
|
|
||||||
// Light theme
|
// Light theme
|
||||||
QColor(0, 0, 0), // NONE
|
|
||||||
QColor(0x80, 0x00, 0x00), // ERROR, Red Intensity
|
|
||||||
QColor(0xb4, 0xb4, 0x00), // WARNING, Yellow Intensity
|
|
||||||
QColor(0x0d, 0x0d, 0x0d), // INFO, White Intensity
|
|
||||||
QColor(0x00, 0x80, 0x00), // VERBOSE, Green Intensity
|
|
||||||
QColor(0x70, 0x70, 0x70), // DEV, White
|
|
||||||
QColor(0xec, 0x5e, 0xf1), // DEBUG, Green
|
|
||||||
QColor(0xe9, 0x39, 0xf3), // TRACE, Blue
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
|
QColor(0x00, 0x00, 0x00), // Default
|
||||||
|
QColor(0x00, 0x00, 0x00), // Black
|
||||||
|
QColor(0x70, 0x00, 0x00), // Red
|
||||||
|
QColor(0xec, 0x5e, 0xf1), // Green
|
||||||
|
QColor(0xe9, 0x39, 0xf3), // Blue
|
||||||
|
QColor(0xA0, 0x00, 0xA0), // Magenta
|
||||||
|
QColor(0xA0, 0x78, 0x00), // Orange
|
||||||
|
QColor(0x80, 0xB4, 0xB4), // Cyan
|
||||||
|
QColor(0xB4, 0xB4, 0x80), // Yellow
|
||||||
|
QColor(0x70, 0x70, 0x70), // White
|
||||||
|
QColor(0x00, 0x00, 0x00), // StrongBlack
|
||||||
|
QColor(0x80, 0x00, 0x00), // StrongRed
|
||||||
|
QColor(0x00, 0x80, 0x00), // StrongGreen
|
||||||
|
QColor(0x00, 0x00, 0x80), // StrongBlue
|
||||||
|
QColor(0xA0, 0x00, 0xA0), // StrongMagenta
|
||||||
|
QColor(0xA0, 0x78, 0x00), // StrongOrange
|
||||||
|
QColor(0x80, 0xB4, 0xB4), // StrongCyan
|
||||||
|
QColor(0xb4, 0xb4, 0x00), // StrongYellow
|
||||||
|
QColor(0x0D, 0x0d, 0x0D) // StrongWhite
|
||||||
|
},
|
||||||
// Dark theme
|
// Dark theme
|
||||||
QColor(255, 255, 255), // NONE
|
{
|
||||||
QColor(0xE7, 0x48, 0x56), // ERROR, Red Intensity
|
QColor(0xD0, 0xD0, 0xD0), // Default
|
||||||
QColor(0xF9, 0xF1, 0xA5), // WARNING, Yellow Intensity
|
QColor(0xFF, 0xFF, 0xFF), // Black
|
||||||
QColor(0xF2, 0xF2, 0xF2), // INFO, White Intensity
|
QColor(0xB4, 0x00, 0x00), // Red
|
||||||
QColor(0x16, 0xC6, 0x0C), // VERBOSE, Green Intensity
|
QColor(0x13, 0xA1, 0x0E), // Green
|
||||||
QColor(0xCC, 0xCC, 0xCC), // DEV, White
|
QColor(0x00, 0x37, 0xDA), // Blue
|
||||||
QColor(0x13, 0xA1, 0x0E), // DEBUG, Green
|
QColor(0xA0, 0x00, 0xA0), // Magenta
|
||||||
QColor(0x00, 0x37, 0xDA), // TRACE, Blue
|
QColor(0xA0, 0x78, 0x00), // Orange
|
||||||
|
QColor(0x80, 0xB4, 0xB4), // Cyan
|
||||||
|
QColor(0xB4, 0xB4, 0x80), // Yellow
|
||||||
|
QColor(0xCC, 0xCC, 0xCC), // White
|
||||||
|
QColor(0xFF, 0xFF, 0xFF), // StrongBlack
|
||||||
|
QColor(0xE7, 0x48, 0x56), // StrongRed
|
||||||
|
QColor(0x16, 0xC6, 0x0C), // StrongGreen
|
||||||
|
QColor(0x20, 0x20, 0xCC), // StrongBlue
|
||||||
|
QColor(0xA0, 0x00, 0xA0), // StrongMagenta
|
||||||
|
QColor(0xB4, 0x96, 0x00), // StrongOrange
|
||||||
|
QColor(0x80, 0xB4, 0xB4), // StrongCyan
|
||||||
|
QColor(0xF9, 0xF1, 0xA5), // StrongYellow
|
||||||
|
QColor(0xFF, 0xFF, 0xFF), // StrongWhite
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
static constexpr const QColor timestamp_color[2] = {QColor(0x60, 0x60, 0x60), QColor(0xcc, 0xcc, 0xcc)};
|
static constexpr const QColor timestamp_color[2] = {QColor(0x60, 0x60, 0x60), QColor(0xcc, 0xcc, 0xcc)};
|
||||||
@ -355,15 +378,20 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, c
|
|||||||
temp_cursor.insertText(qtimestamp);
|
temp_cursor.insertText(qtimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString qchannel = (level <= static_cast<u32>(Log::Level::Warning)) ?
|
const Log::Level level = Log::UnpackLevel(static_cast<Log::MessageCategory>(cat));
|
||||||
QStringLiteral("%1(%2): ").arg(level_characters[level]).arg(channel) :
|
const Log::Color color = (Log::UnpackColor(static_cast<Log::MessageCategory>(cat)) == Log::Color::Default) ?
|
||||||
QStringLiteral("%1/%2: ").arg(level_characters[level]).arg(channel);
|
Log::GetColorForLevel(level) :
|
||||||
|
Log::UnpackColor(static_cast<Log::MessageCategory>(cat));
|
||||||
|
const QString qchannel =
|
||||||
|
(level <= Log::Level::Warning) ?
|
||||||
|
QStringLiteral("%1(%2): ").arg(level_characters[static_cast<size_t>(level)]).arg(channel) :
|
||||||
|
QStringLiteral("%1/%2: ").arg(level_characters[static_cast<size_t>(level)]).arg(channel);
|
||||||
format.setForeground(QBrush(channel_color[dark]));
|
format.setForeground(QBrush(channel_color[dark]));
|
||||||
temp_cursor.setCharFormat(format);
|
temp_cursor.setCharFormat(format);
|
||||||
temp_cursor.insertText(qchannel);
|
temp_cursor.insertText(qchannel);
|
||||||
|
|
||||||
// message has \n already
|
// message has \n already
|
||||||
format.setForeground(QBrush(level_colors[dark][level]));
|
format.setForeground(QBrush(message_colors[dark][static_cast<size_t>(color)]));
|
||||||
temp_cursor.setCharFormat(format);
|
temp_cursor.setCharFormat(format);
|
||||||
temp_cursor.insertText(message);
|
temp_cursor.insertText(message);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ private:
|
|||||||
void updateLogLevelUi();
|
void updateLogLevelUi();
|
||||||
void setLogLevel(Log::Level level);
|
void setLogLevel(Log::Level level);
|
||||||
|
|
||||||
static void logCallback(void* pUserParam, const char* channelName, const char* functionName, Log::Level level,
|
static void logCallback(void* pUserParam, Log::MessageCategory cat, const char* functionName,
|
||||||
std::string_view message);
|
std::string_view message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -42,7 +42,7 @@ protected:
|
|||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onClearTriggered();
|
void onClearTriggered();
|
||||||
void onSaveTriggered();
|
void onSaveTriggered();
|
||||||
void appendMessage(const QLatin1StringView& channel, quint32 level, const QString& message);
|
void appendMessage(const QLatin1StringView& channel, quint32 cat, const QString& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int DEFAULT_WIDTH = 750;
|
static constexpr int DEFAULT_WIDTH = 750;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user