From e3e0fe64458e8ea1ac8f838b5dd93d24fee18566 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 10 Nov 2024 13:23:25 +1000 Subject: [PATCH] Log: Prepend timestamp to multi-line messages --- src/common/log.cpp | 70 +++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/src/common/log.cpp b/src/common/log.cpp index 0b05b9432..2fbdfe9af 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -47,8 +47,7 @@ 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& 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, - bool newline); + 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, std::string_view message); static void DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level, @@ -57,12 +56,11 @@ static void FileOutputLogCallback(void* pUserParam, const char* channelName, con std::string_view message); template static void FormatLogMessageAndPrint(const char* channelName, const char* functionName, Level level, - std::string_view message, bool timestamp, bool ansi_color_code, bool newline, - const T& callback); + std::string_view message, bool timestamp, bool ansi_color_code, const T& callback); #ifdef _WIN32 template static void FormatLogMessageAndPrintW(const char* channelName, const char* functionName, Level level, - std::string_view message, bool timestamp, bool ansi_color_code, bool newline, + std::string_view message, bool timestamp, bool ansi_color_code, const T& callback); #endif @@ -204,7 +202,7 @@ void Log::ExecuteCallbacks(Channel channel, const char* functionName, Level leve 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, bool newline) + bool ansi_color_code) { static constexpr const std::array s_ansi_color_codes = { "\033[0m"sv, // None @@ -219,7 +217,6 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b std::string_view color_start = ansi_color_code ? s_ansi_color_codes[static_cast(level)] : ""sv; std::string_view color_end = ansi_color_code ? s_ansi_color_codes[0] : ""sv; - std::string_view message_end = newline ? "\n"sv : ""sv; auto appender = std::back_inserter(buffer); @@ -228,28 +225,45 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b // find time since start of process const float message_time = Log::GetCurrentMessageTime(); - if (functionName) + // have to break it up into lines + std::string_view::size_type start = 0; + for (;;) { - fmt::format_to(appender, "[{:10.4f}] {}{}({}): {}{}{}", message_time, color_start, - s_log_level_characters[static_cast(level)], functionName, message, color_end, message_end); - } - else - { - fmt::format_to(appender, "[{:10.4f}] {}{}/{}: {}{}{}", message_time, color_start, - s_log_level_characters[static_cast(level)], channelName, message, color_end, message_end); + const std::string_view::size_type pos = message.find('\n', start); + const std::string_view sub_message = + (pos == std::string_view::npos) ? message.substr(start) : message.substr(start, pos - start); + const std::string_view end_message = sub_message.ends_with('\n') ? ""sv : "\n"sv; + + if (functionName) + { + fmt::format_to(appender, "[{:10.4f}] {}{}({}): {}{}{}", message_time, color_start, + s_log_level_characters[static_cast(level)], functionName, sub_message, color_end, + end_message); + } + else + { + fmt::format_to(appender, "[{:10.4f}] {}{}/{}: {}{}{}", message_time, color_start, + s_log_level_characters[static_cast(level)], channelName, sub_message, color_end, + end_message); + } + + if (pos != std::string_view::npos) + start = pos + 1; + else + break; } } else { if (functionName) { - fmt::format_to(appender, "{}{}({}): {}{}{}", color_start, s_log_level_characters[static_cast(level)], - functionName, message, color_end, message_end); + fmt::format_to(appender, "{}{}({}): {}{}\n", color_start, s_log_level_characters[static_cast(level)], + functionName, message, color_end); } else { - fmt::format_to(appender, "{}{}/{}: {}{}{}", color_start, s_log_level_characters[static_cast(level)], - channelName, message, color_end, message_end); + fmt::format_to(appender, "{}{}/{}: {}{}\n", color_start, s_log_level_characters[static_cast(level)], + channelName, message, color_end); } } } @@ -257,11 +271,10 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b template ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrint(const char* channelName, const char* functionName, Level level, std::string_view message, bool timestamp, bool ansi_color_code, - bool newline, const T& callback) + const T& callback) { fmt::memory_buffer buffer; - Log::FormatLogMessageForDisplay(buffer, channelName, functionName, level, message, timestamp, ansi_color_code, - newline); + FormatLogMessageForDisplay(buffer, channelName, functionName, level, message, timestamp, ansi_color_code); callback(std::string_view(buffer.data(), buffer.size())); } @@ -270,11 +283,10 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrint(const char* channelName template ALWAYS_INLINE_RELEASE void Log::FormatLogMessageAndPrintW(const char* channelName, const char* functionName, Level level, std::string_view message, bool timestamp, - bool ansi_color_code, bool newline, const T& callback) + bool ansi_color_code, const T& callback) { fmt::memory_buffer buffer; - Log::FormatLogMessageForDisplay(buffer, channelName, functionName, level, message, timestamp, ansi_color_code, - newline); + FormatLogMessageForDisplay(buffer, channelName, functionName, level, message, timestamp, ansi_color_code); // Convert to UTF-16 first so unicode characters display correctly. NT is going to do it // anyway... @@ -322,14 +334,14 @@ void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, co #if defined(_WIN32) FormatLogMessageAndPrintW( - channelName, functionName, level, message, s_state.console_output_timestamps, true, true, + 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; DWORD chars_written; WriteConsoleW(hOutput, message.data(), static_cast(message.length()), &chars_written, nullptr); }); #elif !defined(__ANDROID__) - FormatLogMessageAndPrint(channelName, functionName, level, message, s_state.console_output_timestamps, true, true, + 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()); @@ -344,7 +356,7 @@ void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, cons return; #if defined(_WIN32) - FormatLogMessageAndPrintW(channelName, functionName, level, message, false, false, true, + FormatLogMessageAndPrintW(channelName, functionName, level, message, false, false, [](const std::wstring_view& message) { OutputDebugStringW(message.data()); }); #elif defined(__ANDROID__) if (message.empty()) @@ -465,7 +477,7 @@ void Log::FileOutputLogCallback(void* pUserParam, const char* channelName, const if (!s_state.file_output_enabled) return; - FormatLogMessageAndPrint(channelName, functionName, level, message, true, false, true, [](std::string_view message) { + FormatLogMessageAndPrint(channelName, functionName, level, 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()); });