Log: Add option coloured variants

This commit is contained in:
Stenzek 2024-11-02 14:21:56 +10:00
parent 596cca9be2
commit 3f41dcc97d
No known key found for this signature in database
5 changed files with 266 additions and 134 deletions

View File

@ -44,36 +44,24 @@ static void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUse
const std::unique_lock<std::mutex>& lock);
static bool FilterTest(Channel channel, Level level);
static void ExecuteCallbacks(Channel channel, const char* functionName, Level level, std::string_view message,
const std::unique_lock<std::mutex>& lock);
static void FormatLogMessageForDisplay(fmt::memory_buffer& buffer, const char* channelName, const char* functionName,
Level level, std::string_view message, bool timestamp, bool ansi_color_code);
static void ConsoleOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
static void ExecuteCallbacks(MessageCategory cat, const char* functionName, std::string_view message);
static void FormatLogMessageForDisplay(fmt::memory_buffer& buffer, MessageCategory cat, const char* functionName,
std::string_view message, bool timestamp, bool ansi_color_code);
static void ConsoleOutputLogCallback(void* pUserParam, MessageCategory cat, const char* functionName,
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);
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);
template<typename T>
static void FormatLogMessageAndPrint(const char* channelName, const char* functionName, Level level,
std::string_view message, bool timestamp, bool ansi_color_code, const T& callback);
static void FormatLogMessageAndPrint(MessageCategory cat, const char* functionName, std::string_view message,
bool timestamp, bool ansi_color_code, const T& callback);
#ifdef _WIN32
template<typename T>
static void FormatLogMessageAndPrintW(const char* channelName, const char* functionName, Level level,
std::string_view message, bool timestamp, bool ansi_color_code,
const T& callback);
static void FormatLogMessageAndPrintW(MessageCategory cat, const char* functionName, std::string_view message,
bool timestamp, bool ansi_color_code, const T& callback);
#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 = {
{'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'}};
@ -191,31 +179,59 @@ bool Log::IsDebugOutputEnabled()
return s_state.debug_output_enabled;
}
void Log::ExecuteCallbacks(Channel channel, const char* functionName, Level level, std::string_view message,
const std::unique_lock<std::mutex>& lock)
Log::Color Log::GetColorForLevel(Level level)
{
for (RegisteredCallback& callback : s_state.callbacks)
callback.Function(callback.Parameter, s_log_channel_names[static_cast<size_t>(channel)], functionName, level,
message);
}
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& buffer, const char* channelName,
const char* functionName, Level level,
std::string_view message, bool timestamp,
bool ansi_color_code)
{
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
static constexpr const std::array s_level_colours = {
Color::Default, // None
Color::StrongRed, // Error
Color::StrongYellow, // Warning
Color::StrongWhite, // Info
Color::StrongGreen, // Verbose
Color::White, // Dev
Color::Green, // Debug
Color::Blue, // 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;
auto appender = std::back_inserter(buffer);
@ -243,7 +259,7 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b
else
{
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);
}
@ -263,30 +279,30 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b
else
{
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>
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,
const T& callback)
{
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()));
}
#ifdef _WIN32
template<typename T>
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrintW(const char* channelName, const char* functionName,
Level level, std::string_view message, bool timestamp,
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrintW(MessageCategory cat, const char* functionName,
std::string_view message, bool timestamp,
bool ansi_color_code, const T& callback)
{
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
// anyway...
@ -326,7 +342,7 @@ static bool EnableVirtualTerminalProcessing(HANDLE hConsole)
#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)
{
if (!s_state.console_output_enabled)
@ -334,29 +350,28 @@ void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, co
#if defined(_WIN32)
FormatLogMessageAndPrintW(
channelName, functionName, level, message, s_state.console_output_timestamps, true,
[level](const std::wstring_view& message) {
HANDLE hOutput = (level <= Level::Warning) ? s_state.hConsoleStdErr : s_state.hConsoleStdOut;
cat, functionName, message, s_state.console_output_timestamps, true, [cat](const std::wstring_view& message) {
HANDLE hOutput = (UnpackLevel(cat) <= Level::Warning) ? s_state.hConsoleStdErr : s_state.hConsoleStdOut;
DWORD chars_written;
WriteConsoleW(hOutput, message.data(), static_cast<DWORD>(message.length()), &chars_written, nullptr);
});
#elif !defined(__ANDROID__)
FormatLogMessageAndPrint(channelName, functionName, level, message, s_state.console_output_timestamps, true,
[level](std::string_view message) {
const int outputFd = (level <= Log::Level::Warning) ? STDERR_FILENO : STDOUT_FILENO;
write(outputFd, message.data(), message.length());
});
FormatLogMessageAndPrint(
cat, functionName, message, s_state.console_output_timestamps, true, [cat](std::string_view message) {
const int outputFd = (UnpackLevel(cat) <= Log::Level::Warning) ? STDERR_FILENO : STDOUT_FILENO;
write(outputFd, message.data(), message.length());
});
#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)
{
if (!s_state.debug_output_enabled)
return;
#if defined(_WIN32)
FormatLogMessageAndPrintW(channelName, functionName, level, message, false, false,
FormatLogMessageAndPrintW(cat, functionName, message, false, false,
[](const std::wstring_view& message) { OutputDebugStringW(message.data()); });
#elif defined(__ANDROID__)
if (message.empty())
@ -373,8 +388,8 @@ void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, cons
ANDROID_LOG_DEBUG, // Trace
};
__android_log_print(logPriority[static_cast<size_t>(level)], channelName, "%.*s", static_cast<int>(message.length()),
message.data());
__android_log_print(logPriority[static_cast<size_t>(UnpackLevel(cat))], GetChannelName(UnpackChannel(cat)), "%.*s",
static_cast<int>(message.length()), message.data());
#endif
}
@ -471,13 +486,13 @@ void Log::SetDebugOutputParams(bool enabled)
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)
{
if (!s_state.file_output_enabled)
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::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");
if (!s_state.file_handle) [[unlikely]]
{
ExecuteCallbacks(Log::Channel::Log, __FUNCTION__, Level::Error,
TinyString::from_format("Failed to open log file '{}'", filename), lock);
ExecuteCallbacks(PackCategory(Channel::Log, Level::Error, Color::Default), nullptr,
TinyString::from_format("Failed to open log file '{}'", filename));
return;
}
@ -535,57 +550,54 @@ void Log::SetLogChannelEnabled(Channel channel, bool 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)
{
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);
const Level level = UnpackLogLevel(cat);
if (!FilterTest(channel, level))
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
return;
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);
const Level level = UnpackLogLevel(cat);
if (!FilterTest(channel, level))
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
return;
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);
const Level level = UnpackLogLevel(cat);
if (!FilterTest(channel, level))
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
return;
fmt::memory_buffer buffer;
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
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);
const Level level = UnpackLogLevel(cat);
if (!FilterTest(channel, level))
if (!FilterTest(UnpackChannel(cat), UnpackLevel(cat)))
return;
fmt::memory_buffer buffer;
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
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()));
}

View File

@ -29,6 +29,31 @@ enum class Level : u32
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
{
#define LOG_CHANNEL_ENUM(X) X,
@ -38,8 +63,28 @@ enum class Channel : u32
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
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);
// 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.
void SetLogChannelEnabled(Channel channel, bool enabled);
// Packs a level and channel into one 16-bit number.
using PackedChannelAndLevel = u32;
[[maybe_unused]] ALWAYS_INLINE static u32 PackChannelAndLevel(Channel channel, Level level)
{
return ((static_cast<PackedChannelAndLevel>(channel) << 3) | static_cast<PackedChannelAndLevel>(level));
}
// Returns the name of the specified log channel.
const char* GetChannelName(Channel channel);
// Returns the default colour for a log level.
Color GetColorForLevel(Level level);
// writes a message to the log
void Write(PackedChannelAndLevel cat, std::string_view message);
void Write(PackedChannelAndLevel cat, const char* functionName, std::string_view message);
void WriteFmtArgs(PackedChannelAndLevel 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 Write(MessageCategory cat, std::string_view message);
void Write(MessageCategory cat, const char* functionName, std::string_view message);
void WriteFmtArgs(MessageCategory cat, 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)
{
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)
{
if (level <= GetLogLevel()) [[unlikely]]
Write(PackChannelAndLevel(channel, level), functionName, message);
Write(PackCategory(channel, level, Color::Default), functionName, message);
}
template<typename... T>
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, fmt::format_string<T...> fmt, T&&... args)
{
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>
ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level,
fmt::format_string<T...> fmt, T&&... args)
{
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
@ -139,3 +208,26 @@ ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, L
{ \
} while (0)
#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

View File

@ -77,7 +77,7 @@ public:
{
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...));
return true;
}

View File

@ -254,7 +254,7 @@ void LogWindow::onSaveTriggered()
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)
{
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(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())
{
this_ptr->appendMessage(qchannel, static_cast<u32>(level), qmessage);
this_ptr->appendMessage(qchannel, static_cast<u32>(cat), qmessage);
}
else
{
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));
}
}
@ -304,7 +305,7 @@ void LogWindow::changeEvent(QEvent* 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();
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',
'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(0xF9, 0xF1, 0xA5), // WARNING, Yellow Intensity
QColor(0xF2, 0xF2, 0xF2), // INFO, White Intensity
QColor(0x16, 0xC6, 0x0C), // VERBOSE, Green Intensity
QColor(0xCC, 0xCC, 0xCC), // DEV, White
QColor(0x13, 0xA1, 0x0E), // DEBUG, Green
QColor(0x00, 0x37, 0xDA), // TRACE, Blue
QColor(0xD0, 0xD0, 0xD0), // Default
QColor(0xFF, 0xFF, 0xFF), // Black
QColor(0xB4, 0x00, 0x00), // Red
QColor(0x13, 0xA1, 0x0E), // Green
QColor(0x00, 0x37, 0xDA), // Blue
QColor(0xA0, 0x00, 0xA0), // Magenta
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)};
@ -355,15 +378,20 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, c
temp_cursor.insertText(qtimestamp);
}
const QString qchannel = (level <= static_cast<u32>(Log::Level::Warning)) ?
QStringLiteral("%1(%2): ").arg(level_characters[level]).arg(channel) :
QStringLiteral("%1/%2: ").arg(level_characters[level]).arg(channel);
const Log::Level level = Log::UnpackLevel(static_cast<Log::MessageCategory>(cat));
const Log::Color color = (Log::UnpackColor(static_cast<Log::MessageCategory>(cat)) == Log::Color::Default) ?
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]));
temp_cursor.setCharFormat(format);
temp_cursor.insertText(qchannel);
// 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.insertText(message);
}

View File

@ -32,7 +32,7 @@ private:
void updateLogLevelUi();
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);
protected:
@ -42,7 +42,7 @@ protected:
private Q_SLOTS:
void onClearTriggered();
void onSaveTriggered();
void appendMessage(const QLatin1StringView& channel, quint32 level, const QString& message);
void appendMessage(const QLatin1StringView& channel, quint32 cat, const QString& message);
private:
static constexpr int DEFAULT_WIDTH = 750;