diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e5d455e13..c966446e4 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(common layered_settings_interface.h log.cpp log.h + log_channels.h memmap.cpp memmap.h md5_digest.cpp diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index bbaab73d1..ab8e27fa0 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -24,6 +24,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index a671d44e9..90a750fea 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -49,6 +49,7 @@ + diff --git a/src/common/log.cpp b/src/common/log.cpp index e6ff17134..0b05b9432 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -9,6 +9,8 @@ #include "fmt/format.h" +#include +#include #include #include #include @@ -34,12 +36,15 @@ struct RegisteredCallback }; } // namespace +using ChannelBitSet = std::bitset(Channel::MaxCount)>; + static void RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam, const std::unique_lock& lock); static void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam, const std::unique_lock& lock); -static bool FilterTest(Level level, const char* channelName, const std::unique_lock& lock); -static void ExecuteCallbacks(const char* channelName, const char* functionName, Level level, std::string_view message, + +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, @@ -61,38 +66,61 @@ static void FormatLogMessageAndPrintW(const char* channelName, const char* funct const T& callback); #endif -static const char s_log_level_characters[static_cast(Level::Count)] = {'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'}; +ALWAYS_INLINE static Channel UnpackLogChannel(PackedChannelAndLevel cat) +{ + return static_cast(cat >> 3); +} -static std::vector s_callbacks; -static std::mutex s_callback_mutex; +ALWAYS_INLINE static Level UnpackLogLevel(PackedChannelAndLevel cat) +{ + return static_cast(cat & 0x7); +} -static Common::Timer::Value s_start_timestamp = Common::Timer::GetCurrentValue(); +static constexpr const std::array(Level::MaxCount)> s_log_level_characters = { + {'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'}}; -static std::string s_log_filter; -static Level s_log_level = Level::None; -static bool s_console_output_enabled = false; -static bool s_console_output_timestamps = false; -static bool s_file_output_enabled = false; -static bool s_file_output_timestamp = false; -static bool s_debug_output_enabled = false; +static constexpr const std::array(Channel::MaxCount)> s_log_channel_names = {{ +#define LOG_CHANNEL_NAME(X) #X, + ENUMERATE_LOG_CHANNELS(LOG_CHANNEL_NAME) +#undef LOG_CHANNEL_NAME +}}; + +namespace { + +struct State +{ + Level log_level = Level::Trace; + ChannelBitSet log_channels_enabled = ChannelBitSet().set(); + + std::vector callbacks; + std::mutex callbacks_mutex; + + Common::Timer::Value start_timestamp = Common::Timer::GetCurrentValue(); + + FileSystem::ManagedCFilePtr file_handle; + + bool console_output_enabled = false; + bool console_output_timestamps = false; + bool file_output_enabled = false; + bool file_output_timestamp = false; + bool debug_output_enabled = false; #ifdef _WIN32 -static HANDLE s_hConsoleStdIn = NULL; -static HANDLE s_hConsoleStdOut = NULL; -static HANDLE s_hConsoleStdErr = NULL; + HANDLE hConsoleStdIn = NULL; + HANDLE hConsoleStdOut = NULL; + HANDLE hConsoleStdErr = NULL; #endif -} // namespace Log +}; -std::unique_ptr s_file_handle(nullptr, [](std::FILE* fp) { - if (fp) - { - std::fclose(fp); - } -}); +} // namespace + +ALIGN_TO_CACHE_LINE static State s_state; + +} // namespace Log void Log::RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam) { - std::unique_lock lock(s_callback_mutex); + std::unique_lock lock(s_state.callbacks_mutex); RegisterCallback(callbackFunction, pUserParam, lock); } @@ -103,31 +131,42 @@ void Log::RegisterCallback(CallbackFunctionType callbackFunction, void* pUserPar Callback.Function = callbackFunction; Callback.Parameter = pUserParam; - s_callbacks.push_back(std::move(Callback)); + s_state.callbacks.push_back(std::move(Callback)); } void Log::UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam) { - std::unique_lock lock(s_callback_mutex); + std::unique_lock lock(s_state.callbacks_mutex); UnregisterCallback(callbackFunction, pUserParam, lock); } void Log::UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam, const std::unique_lock& lock) { - for (auto iter = s_callbacks.begin(); iter != s_callbacks.end(); ++iter) + for (auto iter = s_state.callbacks.begin(); iter != s_state.callbacks.end(); ++iter) { if (iter->Function == callbackFunction && iter->Parameter == pUserParam) { - s_callbacks.erase(iter); + s_state.callbacks.erase(iter); break; } } } +const std::array(Log::Channel::MaxCount)>& Log::GetChannelNames() +{ + return s_log_channel_names; +} + float Log::GetCurrentMessageTime() { - return static_cast(Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_start_timestamp)); + return static_cast( + Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_state.start_timestamp)); +} + +bool Log::AreTimestampsEnabled() +{ + return s_state.console_output_timestamps || s_state.file_output_timestamp; } bool Log::IsConsoleOutputCurrentlyAvailable() @@ -146,19 +185,20 @@ bool Log::IsConsoleOutputCurrentlyAvailable() bool Log::IsConsoleOutputEnabled() { - return s_console_output_enabled; + return s_state.console_output_enabled; } bool Log::IsDebugOutputEnabled() { - return s_debug_output_enabled; + return s_state.debug_output_enabled; } -void Log::ExecuteCallbacks(const char* channelName, const char* functionName, Level level, std::string_view message, +void Log::ExecuteCallbacks(Channel channel, const char* functionName, Level level, std::string_view message, const std::unique_lock& lock) { - for (RegisteredCallback& callback : s_callbacks) - callback.Function(callback.Parameter, channelName, functionName, level, message); + for (RegisteredCallback& callback : s_state.callbacks) + callback.Function(callback.Parameter, s_log_channel_names[static_cast(channel)], functionName, level, + message); } ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& buffer, const char* channelName, @@ -166,7 +206,7 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b std::string_view message, bool timestamp, bool ansi_color_code, bool newline) { - static constexpr std::string_view s_ansi_color_codes[static_cast(Level::Count)] = { + static constexpr const std::array s_ansi_color_codes = { "\033[0m"sv, // None "\033[1;31m"sv, // Error "\033[1;33m"sv, // Warning @@ -277,19 +317,19 @@ static bool EnableVirtualTerminalProcessing(HANDLE hConsole) void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level, std::string_view message) { - if (!s_console_output_enabled) + if (!s_state.console_output_enabled) return; #if defined(_WIN32) - FormatLogMessageAndPrintW(channelName, functionName, level, message, s_console_output_timestamps, true, true, - [level](const std::wstring_view& message) { - HANDLE hOutput = (level <= Level::Warning) ? s_hConsoleStdErr : s_hConsoleStdOut; - DWORD chars_written; - WriteConsoleW(hOutput, message.data(), static_cast(message.length()), - &chars_written, nullptr); - }); + FormatLogMessageAndPrintW( + channelName, functionName, level, message, s_state.console_output_timestamps, true, 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_console_output_timestamps, true, true, + FormatLogMessageAndPrint(channelName, functionName, level, message, s_state.console_output_timestamps, true, true, [level](std::string_view message) { const int outputFd = (level <= Log::Level::Warning) ? STDERR_FILENO : STDOUT_FILENO; write(outputFd, message.data(), message.length()); @@ -300,7 +340,7 @@ void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, co void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level, std::string_view message) { - if (!s_debug_output_enabled) + if (!s_state.debug_output_enabled) return; #if defined(_WIN32) @@ -328,13 +368,13 @@ void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, cons void Log::SetConsoleOutputParams(bool enabled, bool timestamps) { - std::unique_lock lock(s_callback_mutex); + std::unique_lock lock(s_state.callbacks_mutex); - s_console_output_timestamps = timestamps; - if (s_console_output_enabled == enabled) + s_state.console_output_timestamps = timestamps; + if (s_state.console_output_enabled == enabled) return; - s_console_output_enabled = enabled; + s_state.console_output_enabled = enabled; #if defined(_WIN32) // On windows, no console is allocated by default on a windows based application @@ -355,12 +395,12 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps) if (!AttachConsole(ATTACH_PARENT_PROCESS) && !AllocConsole()) return; - s_hConsoleStdIn = GetStdHandle(STD_INPUT_HANDLE); - s_hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - s_hConsoleStdErr = GetStdHandle(STD_ERROR_HANDLE); + s_state.hConsoleStdIn = GetStdHandle(STD_INPUT_HANDLE); + s_state.hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + s_state.hConsoleStdErr = GetStdHandle(STD_ERROR_HANDLE); - EnableVirtualTerminalProcessing(s_hConsoleStdOut); - EnableVirtualTerminalProcessing(s_hConsoleStdErr); + EnableVirtualTerminalProcessing(s_state.hConsoleStdOut); + EnableVirtualTerminalProcessing(s_state.hConsoleStdErr); std::FILE* fp; freopen_s(&fp, "CONIN$", "r", stdin); @@ -371,9 +411,9 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps) } else { - s_hConsoleStdIn = old_stdin; - s_hConsoleStdOut = old_stdout; - s_hConsoleStdErr = old_stderr; + s_state.hConsoleStdIn = old_stdin; + s_state.hConsoleStdOut = old_stdout; + s_state.hConsoleStdErr = old_stderr; } } else @@ -391,9 +431,9 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps) SetStdHandle(STD_OUTPUT_HANDLE, old_stdout); SetStdHandle(STD_INPUT_HANDLE, old_stdin); - s_hConsoleStdIn = NULL; - s_hConsoleStdOut = NULL; - s_hConsoleStdErr = NULL; + s_state.hConsoleStdIn = NULL; + s_state.hConsoleStdOut = NULL; + s_state.hConsoleStdErr = NULL; FreeConsole(); } @@ -408,11 +448,11 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps) void Log::SetDebugOutputParams(bool enabled) { - std::unique_lock lock(s_callback_mutex); - if (s_debug_output_enabled == enabled) + std::unique_lock lock(s_state.callbacks_mutex); + if (s_state.debug_output_enabled == enabled) return; - s_debug_output_enabled = enabled; + s_state.debug_output_enabled = enabled; if (enabled) RegisterCallback(DebugOutputLogCallback, nullptr, lock); else @@ -422,27 +462,27 @@ void Log::SetDebugOutputParams(bool enabled) void Log::FileOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level, std::string_view message) { - if (!s_file_output_enabled) + if (!s_state.file_output_enabled) return; FormatLogMessageAndPrint(channelName, functionName, level, message, true, false, true, [](std::string_view message) { - std::fwrite(message.data(), 1, message.size(), s_file_handle.get()); - std::fflush(s_file_handle.get()); + std::fwrite(message.data(), 1, message.size(), s_state.file_handle.get()); + std::fflush(s_state.file_handle.get()); }); } void Log::SetFileOutputParams(bool enabled, const char* filename, bool timestamps /* = true */) { - std::unique_lock lock(s_callback_mutex); - if (s_file_output_enabled == enabled) + std::unique_lock lock(s_state.callbacks_mutex); + if (s_state.file_output_enabled == enabled) return; if (enabled) { - s_file_handle.reset(FileSystem::OpenCFile(filename, "wb")); - if (!s_file_handle) [[unlikely]] + s_state.file_handle = FileSystem::OpenManagedCFile(filename, "wb"); + if (!s_state.file_handle) [[unlikely]] { - ExecuteCallbacks("Log", __FUNCTION__, Level::Error, + ExecuteCallbacks(Log::Channel::Log, __FUNCTION__, Level::Error, TinyString::from_format("Failed to open log file '{}'", filename), lock); return; } @@ -452,86 +492,88 @@ void Log::SetFileOutputParams(bool enabled, const char* filename, bool timestamp else { UnregisterCallback(FileOutputLogCallback, nullptr, lock); - s_file_handle.reset(); + s_state.file_handle.reset(); } - s_file_output_enabled = enabled; - s_file_output_timestamp = timestamps; + s_state.file_output_enabled = enabled; + s_state.file_output_timestamp = timestamps; } Log::Level Log::GetLogLevel() { - return s_log_level; + return s_state.log_level; } -bool Log::IsLogVisible(Level level, const char* channelName) +bool Log::IsLogVisible(Level level, Channel channel) { - if (level > s_log_level) - return false; - - std::unique_lock lock(s_callback_mutex); - return FilterTest(level, channelName, lock); + return FilterTest(channel, level); } void Log::SetLogLevel(Level level) { - std::unique_lock lock(s_callback_mutex); - DebugAssert(level < Level::Count); - s_log_level = level; + std::unique_lock lock(s_state.callbacks_mutex); + DebugAssert(level < Level::MaxCount); + s_state.log_level = level; } -void Log::SetLogFilter(std::string_view filter) +void Log::SetLogChannelEnabled(Channel channel, bool enabled) { - std::unique_lock lock(s_callback_mutex); - if (s_log_filter != filter) - s_log_filter = filter; + std::unique_lock lock(s_state.callbacks_mutex); + DebugAssert(channel < Channel::MaxCount); + s_state.log_channels_enabled[static_cast(channel)] = enabled; } -ALWAYS_INLINE_RELEASE bool Log::FilterTest(Level level, const char* channelName, - const std::unique_lock& lock) +ALWAYS_INLINE_RELEASE bool Log::FilterTest(Channel channel, Level level) { - return (level <= s_log_level && s_log_filter.find(channelName) == std::string::npos); + return (level <= s_state.log_level && s_state.log_channels_enabled[static_cast(channel)]); } -void Log::Write(const char* channelName, Level level, std::string_view message) +void Log::Write(PackedChannelAndLevel cat, std::string_view message) { - std::unique_lock lock(s_callback_mutex); - if (!FilterTest(level, channelName, lock)) + const Channel channel = UnpackLogChannel(cat); + const Level level = UnpackLogLevel(cat); + if (!FilterTest(channel, level)) return; - ExecuteCallbacks(channelName, nullptr, level, message, lock); + std::unique_lock lock(s_state.callbacks_mutex); + ExecuteCallbacks(channel, nullptr, level, message, lock); } -void Log::Write(const char* channelName, const char* functionName, Level level, std::string_view message) +void Log::Write(PackedChannelAndLevel cat, const char* functionName, std::string_view message) { - std::unique_lock lock(s_callback_mutex); - if (!FilterTest(level, channelName, lock)) + const Channel channel = UnpackLogChannel(cat); + const Level level = UnpackLogLevel(cat); + if (!FilterTest(channel, level)) return; - ExecuteCallbacks(channelName, functionName, level, message, lock); + std::unique_lock lock(s_state.callbacks_mutex); + ExecuteCallbacks(channel, functionName, level, message, lock); } -void Log::WriteFmtArgs(const char* channelName, Level level, fmt::string_view fmt, fmt::format_args args) +void Log::WriteFmtArgs(PackedChannelAndLevel cat, fmt::string_view fmt, fmt::format_args args) { - std::unique_lock lock(s_callback_mutex); - if (!FilterTest(level, channelName, lock)) + const Channel channel = UnpackLogChannel(cat); + const Level level = UnpackLogLevel(cat); + if (!FilterTest(channel, level)) return; fmt::memory_buffer buffer; fmt::vformat_to(std::back_inserter(buffer), fmt, args); - ExecuteCallbacks(channelName, nullptr, level, std::string_view(buffer.data(), buffer.size()), lock); + std::unique_lock lock(s_state.callbacks_mutex); + ExecuteCallbacks(channel, nullptr, level, std::string_view(buffer.data(), buffer.size()), lock); } -void Log::WriteFmtArgs(const char* channelName, const char* functionName, Level level, fmt::string_view fmt, - fmt::format_args args) +void Log::WriteFmtArgs(PackedChannelAndLevel cat, const char* functionName, fmt::string_view fmt, fmt::format_args args) { - std::unique_lock lock(s_callback_mutex); - if (!FilterTest(level, channelName, lock)) + const Channel channel = UnpackLogChannel(cat); + const Level level = UnpackLogLevel(cat); + if (!FilterTest(channel, level)) return; fmt::memory_buffer buffer; fmt::vformat_to(std::back_inserter(buffer), fmt, args); - ExecuteCallbacks(channelName, functionName, level, std::string_view(buffer.data(), buffer.size()), lock); + std::unique_lock lock(s_state.callbacks_mutex); + ExecuteCallbacks(channel, functionName, level, std::string_view(buffer.data(), buffer.size()), lock); } diff --git a/src/common/log.h b/src/common/log.h index 43d4b7798..deffc1361 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -3,17 +3,19 @@ #pragma once +#include "log_channels.h" #include "types.h" #include "fmt/base.h" +#include #include #include #include #include namespace Log { -enum class Level +enum class Level : u32 { None, // Silences all log traffic Error, @@ -24,7 +26,16 @@ enum class Level Debug, Trace, - Count + MaxCount +}; + +enum class Channel : u32 +{ +#define LOG_CHANNEL_ENUM(X) X, + ENUMERATE_LOG_CHANNELS(LOG_CHANNEL_ENUM) +#undef LOG_CHANNEL_ENUM + + MaxCount }; // log message callback type @@ -37,8 +48,12 @@ void RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam); // unregisters a log callback void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam); +// returns a list of all log channels +const std::array(Channel::MaxCount)>& GetChannelNames(); + // returns the time in seconds since the start of the process float GetCurrentMessageTime(); +bool AreTimestampsEnabled(); // adds a standard console output bool IsConsoleOutputCurrentlyAvailable(); @@ -56,49 +71,54 @@ void SetFileOutputParams(bool enabled, const char* filename, bool timestamps = t Level GetLogLevel(); // Returns true if log messages for the specified log level/filter would not be filtered (and visible). -bool IsLogVisible(Level level, const char* channelName); +bool IsLogVisible(Level level, Channel channel); // Sets global filtering level, messages below this level won't be sent to any of the logging sinks. void SetLogLevel(Level level); // Sets global filter, any messages from these channels won't be sent to any of the logging sinks. -void SetLogFilter(std::string_view filter); +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(channel) << 3) | static_cast(level)); +} // writes a message to the log -void Write(const char* channelName, Level level, std::string_view message); -void Write(const char* channelName, const char* functionName, Level level, std::string_view message); -void WriteFmtArgs(const char* channelName, Level level, fmt::string_view fmt, fmt::format_args args); -void WriteFmtArgs(const char* channelName, const char* functionName, Level level, fmt::string_view fmt, - fmt::format_args args); +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); -ALWAYS_INLINE static void FastWrite(const char* channelName, Level level, std::string_view message) +ALWAYS_INLINE static void FastWrite(Channel channel, Level level, std::string_view message) { if (level <= GetLogLevel()) [[unlikely]] - Write(channelName, level, message); + Write(PackChannelAndLevel(channel, level), message); } -ALWAYS_INLINE static void FastWrite(const char* channelName, 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]] - Write(channelName, functionName, level, message); + Write(PackChannelAndLevel(channel, level), functionName, message); } template -ALWAYS_INLINE static void FastWrite(const char* channelName, Level level, fmt::format_string fmt, T&&... args) +ALWAYS_INLINE static void FastWrite(Channel channel, Level level, fmt::format_string fmt, T&&... args) { if (level <= GetLogLevel()) [[unlikely]] - WriteFmtArgs(channelName, level, fmt, fmt::make_format_args(args...)); + WriteFmtArgs(PackChannelAndLevel(channel, level), fmt, fmt::make_format_args(args...)); } template -ALWAYS_INLINE static void FastWrite(const char* channelName, const char* functionName, Level level, +ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level, fmt::format_string fmt, T&&... args) { if (level <= GetLogLevel()) [[unlikely]] - WriteFmtArgs(channelName, functionName, level, fmt, fmt::make_format_args(args...)); + WriteFmtArgs(PackChannelAndLevel(channel, level), functionName, fmt, fmt::make_format_args(args...)); } } // namespace Log // log wrappers -#define LOG_CHANNEL(name) [[maybe_unused]] static const char* ___LogChannel___ = #name; +#define LOG_CHANNEL(name) [[maybe_unused]] static constexpr Log::Channel ___LogChannel___ = Log::Channel::name; #define ERROR_LOG(...) Log::FastWrite(___LogChannel___, __func__, Log::Level::Error, __VA_ARGS__) #define WARNING_LOG(...) Log::FastWrite(___LogChannel___, __func__, Log::Level::Warning, __VA_ARGS__) diff --git a/src/common/log_channels.h b/src/common/log_channels.h new file mode 100644 index 000000000..425ebb510 --- /dev/null +++ b/src/common/log_channels.h @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin +// SPDX-License-Identifier: CC-BY-NC-ND-4.0 + +#define ENUMERATE_LOG_CHANNELS(X) \ + X(Achievements) \ + X(AnalogController) \ + X(AnalogJoystick) \ + X(AudioStream) \ + X(AutoUpdaterDialog) \ + X(BIOS) \ + X(Bus) \ + X(CDImage) \ + X(CDROM) \ + X(CDROMAsyncReader) \ + X(CPU) \ + X(Cheats) \ + X(CodeCache) \ + X(CompressHelpers) \ + X(ControllerBindingWidget) \ + X(CubebAudioStream) \ + X(CueParser) \ + X(DInputSource) \ + X(DMA) \ + X(DynamicLibrary) \ + X(FileSystem) \ + X(FullscreenUI) \ + X(GDBProtocol) \ + X(GPU) \ + X(GPUBackend) \ + X(GPUDevice) \ + X(GPUDump) \ + X(GPUShaderCache) \ + X(GPUTexture) \ + X(GPUTextureCache) \ + X(GPU_HW) \ + X(GPU_SW) \ + X(GPU_SW_Rasterizer) \ + X(GameDatabase) \ + X(GameList) \ + X(GunCon) \ + X(HTTPDownloader) \ + X(Host) \ + X(ImGuiFullscreen) \ + X(ImGuiManager) \ + X(Image) \ + X(InputManager) \ + X(InterruptController) \ + X(IsoReader) \ + X(Justifier) \ + X(Log) \ + X(MDEC) \ + X(MediaCapture) \ + X(MemMap) \ + X(MemoryCard) \ + X(Multitap) \ + X(NeGconRumble) \ + X(PCDrv) \ + X(PSFLoader) \ + X(Pad) \ + X(PerfMon) \ + X(PlatformMisc) \ + X(PlayStationMouse) \ + X(PostProcessing) \ + X(ProgressCallback) \ + X(ReShadeFXShader) \ + X(Recompiler) \ + X(SDL) \ + X(SIO) \ + X(SPU) \ + X(Settings) \ + X(SettingsWindow) \ + X(ShaderGen) \ + X(Sockets) \ + X(StateWrapper) \ + X(System) \ + X(TTY) \ + X(Threading) \ + X(Timers) \ + X(TimingEvents) \ + X(Ungrouped) \ + X(WAVWriter) \ + X(Win32RawInputSource) \ + X(WindowInfo) \ + X(XInputSource) diff --git a/src/common/zip_helpers.h b/src/common/zip_helpers.h index 54656ff7f..da6b5c50e 100644 --- a/src/common/zip_helpers.h +++ b/src/common/zip_helpers.h @@ -33,7 +33,7 @@ struct ZipDeleter const int err = zip_close(zf); if (err != 0) { - Log::FastWrite("ZipHelpers", __FUNCTION__, Log::Level::Error, "Failed to close zip file: {}", err); + Log::FastWrite(Log::Channel::Ungrouped, __FUNCTION__, Log::Level::Error, "Failed to close zip file: {}", err); zip_discard(zf); } } diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 34cb8426c..c1e870cd3 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -936,7 +936,7 @@ void Bus::AddTTYCharacter(char ch) { if (!s_tty_line_buffer.empty()) { - Log::FastWrite("TTY", "", Log::Level::Info, "\033[1;34m{}\033[0m", s_tty_line_buffer); + Log::FastWrite(Log::Channel::TTY, Log::Level::Info, "\033[1;34m{}\033[0m", s_tty_line_buffer); #ifdef _DEBUG if (CPU::IsTraceEnabled()) CPU::WriteToExecutionLog("TTY: %s\n", s_tty_line_buffer.c_str()); diff --git a/src/core/cheats.cpp b/src/core/cheats.cpp index 307f6222a..c4492be25 100644 --- a/src/core/cheats.cpp +++ b/src/core/cheats.cpp @@ -77,7 +77,8 @@ public: { if (!stop_on_error) { - Log::WriteFmtArgs(___LogChannel___, Log::Level::Warning, fmt, fmt::make_format_args(args...)); + Log::WriteFmtArgs(Log::PackChannelAndLevel(Log::Channel::Cheats, Log::Level::Warning), fmt, + fmt::make_format_args(args...)); return true; } diff --git a/src/core/cpu_code_cache.cpp b/src/core/cpu_code_cache.cpp index 901a1343d..c9e16e0cb 100644 --- a/src/core/cpu_code_cache.cpp +++ b/src/core/cpu_code_cache.cpp @@ -21,7 +21,7 @@ #include "common/log.h" #include "common/memmap.h" -LOG_CHANNEL(CPU::CodeCache); +LOG_CHANNEL(CodeCache); // Enable dumping of recompiled block code size statistics. // #define DUMP_CODE_SIZE_STATS 1 diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index e257bf688..c78029e40 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -26,7 +26,7 @@ #include -LOG_CHANNEL(CPU::Core); +LOG_CHANNEL(CPU); namespace CPU { enum class ExecutionBreakType diff --git a/src/core/cpu_newrec_compiler.cpp b/src/core/cpu_newrec_compiler.cpp index a95e9f996..8f0aef3f3 100644 --- a/src/core/cpu_newrec_compiler.cpp +++ b/src/core/cpu_newrec_compiler.cpp @@ -15,7 +15,7 @@ #include #include -LOG_CHANNEL(NewRec::Compiler); +LOG_CHANNEL(Recompiler); // TODO: direct link skip delay slot check // TODO: speculative constants diff --git a/src/core/cpu_newrec_compiler_aarch32.cpp b/src/core/cpu_newrec_compiler_aarch32.cpp index 2d9b02ca4..fb8f7c08f 100644 --- a/src/core/cpu_newrec_compiler_aarch32.cpp +++ b/src/core/cpu_newrec_compiler_aarch32.cpp @@ -19,7 +19,7 @@ #ifdef CPU_ARCH_ARM32 -LOG_CHANNEL(CPU::NewRec); +LOG_CHANNEL(Recompiler); #define PTR(x) vixl::aarch32::MemOperand(RSTATE, (((u8*)(x)) - ((u8*)&g_state))) #define RMEMBASE vixl::aarch32::r3 diff --git a/src/core/cpu_newrec_compiler_aarch64.cpp b/src/core/cpu_newrec_compiler_aarch64.cpp index e0a323de2..cb3efeb49 100644 --- a/src/core/cpu_newrec_compiler_aarch64.cpp +++ b/src/core/cpu_newrec_compiler_aarch64.cpp @@ -19,7 +19,7 @@ #ifdef CPU_ARCH_ARM64 -LOG_CHANNEL(CPU::NewRec); +LOG_CHANNEL(Recompiler); #define PTR(x) vixl::aarch64::MemOperand(RSTATE, (((u8*)(x)) - ((u8*)&g_state))) diff --git a/src/core/cpu_newrec_compiler_riscv64.cpp b/src/core/cpu_newrec_compiler_riscv64.cpp index 4204c893c..61ac7604b 100644 --- a/src/core/cpu_newrec_compiler_riscv64.cpp +++ b/src/core/cpu_newrec_compiler_riscv64.cpp @@ -20,7 +20,7 @@ #ifdef CPU_ARCH_RISCV64 -LOG_CHANNEL(CPU::NewRec); +LOG_CHANNEL(Recompiler); #ifdef ENABLE_HOST_DISASSEMBLY extern "C" { diff --git a/src/core/cpu_newrec_compiler_x64.cpp b/src/core/cpu_newrec_compiler_x64.cpp index bf555ac29..5c427f489 100644 --- a/src/core/cpu_newrec_compiler_x64.cpp +++ b/src/core/cpu_newrec_compiler_x64.cpp @@ -20,7 +20,7 @@ #ifdef CPU_ARCH_X64 -LOG_CHANNEL(CPU::NewRec); +LOG_CHANNEL(Recompiler); #define RMEMBASE cg->rbx #define RSTATE cg->rbp diff --git a/src/core/cpu_pgxp.cpp b/src/core/cpu_pgxp.cpp index e4a3ee4d9..163506d7d 100644 --- a/src/core/cpu_pgxp.cpp +++ b/src/core/cpu_pgxp.cpp @@ -19,7 +19,7 @@ #include #include -LOG_CHANNEL(CPU::PGXP); +LOG_CHANNEL(CPU); // #define LOG_VALUES 1 // #define LOG_LOOKUPS 1 diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp index 40e144ce2..50c413918 100644 --- a/src/core/cpu_recompiler_code_generator.cpp +++ b/src/core/cpu_recompiler_code_generator.cpp @@ -11,7 +11,7 @@ #include "common/log.h" -LOG_CHANNEL(CPU::Recompiler); +LOG_CHANNEL(Recompiler); // TODO: Turn load+sext/zext into a single signed/unsigned load // TODO: mulx/shlx/etc diff --git a/src/core/cpu_recompiler_code_generator_aarch32.cpp b/src/core/cpu_recompiler_code_generator_aarch32.cpp index 6b67bb4f1..6d7264256 100644 --- a/src/core/cpu_recompiler_code_generator_aarch32.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch32.cpp @@ -16,7 +16,7 @@ #ifdef CPU_ARCH_ARM32 -LOG_CHANNEL(CPU::Recompiler); +LOG_CHANNEL(Recompiler); #ifdef ENABLE_HOST_DISASSEMBLY #include "vixl/aarch32/disasm-aarch32.h" diff --git a/src/core/cpu_recompiler_code_generator_aarch64.cpp b/src/core/cpu_recompiler_code_generator_aarch64.cpp index df6ae270b..bf207e4e6 100644 --- a/src/core/cpu_recompiler_code_generator_aarch64.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch64.cpp @@ -16,7 +16,7 @@ #ifdef CPU_ARCH_ARM64 -LOG_CHANNEL(CPU::Recompiler); +LOG_CHANNEL(Recompiler); #ifdef ENABLE_HOST_DISASSEMBLY #include "vixl/aarch64/disasm-aarch64.h" diff --git a/src/core/cpu_recompiler_code_generator_generic.cpp b/src/core/cpu_recompiler_code_generator_generic.cpp index 97e3b3414..2661e1d13 100644 --- a/src/core/cpu_recompiler_code_generator_generic.cpp +++ b/src/core/cpu_recompiler_code_generator_generic.cpp @@ -8,7 +8,7 @@ #include "common/log.h" -LOG_CHANNEL(Recompiler::CodeGenerator); +LOG_CHANNEL(Recompiler); namespace CPU::Recompiler { diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp index bb4160639..4ceb71cca 100644 --- a/src/core/cpu_recompiler_code_generator_x64.cpp +++ b/src/core/cpu_recompiler_code_generator_x64.cpp @@ -16,7 +16,7 @@ #ifdef CPU_ARCH_X64 -LOG_CHANNEL(Recompiler::CodeGenerator); +LOG_CHANNEL(Recompiler); #ifdef ENABLE_HOST_DISASSEMBLY #include "Zycore/Format.h" @@ -260,8 +260,7 @@ void CPU::CodeCache::DisassembleAndLogHostCode(const void* start, u32 size) else hex.append(" "); } - Log::FastWrite("HostCode", "", Log::Level::Debug, " {:016X} {} {}", - static_cast(reinterpret_cast(ptr)), hex, buffer); + DEBUG_LOG(" {:016X} {} {}", static_cast(reinterpret_cast(ptr)), hex, buffer); } ptr += disas_instruction.length; diff --git a/src/core/cpu_recompiler_register_cache.cpp b/src/core/cpu_recompiler_register_cache.cpp index 0efbd4496..7e5329015 100644 --- a/src/core/cpu_recompiler_register_cache.cpp +++ b/src/core/cpu_recompiler_register_cache.cpp @@ -8,7 +8,7 @@ #include -LOG_CHANNEL(CPU::Recompiler); +LOG_CHANNEL(Recompiler); namespace CPU::Recompiler { diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 4c2a3f141..f70596100 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -5173,7 +5173,7 @@ void FullscreenUI::DrawAdvancedSettingsPage() DrawEnumSetting(bsi, FSUI_CSTR("Log Level"), FSUI_CSTR("Sets the verbosity of messages logged. Higher levels will log more messages."), "Logging", "LogLevel", Settings::DEFAULT_LOG_LEVEL, &Settings::ParseLogLevelName, &Settings::GetLogLevelName, - &Settings::GetLogLevelDisplayName, Log::Level::Count); + &Settings::GetLogLevelDisplayName, Log::Level::MaxCount); DrawToggleSetting(bsi, FSUI_CSTR("Log To System Console"), FSUI_CSTR("Logs messages to the console window."), FSUI_CSTR("Logging"), "LogToConsole", false); DrawToggleSetting(bsi, FSUI_CSTR("Log To Debug Console"), diff --git a/src/core/host_interface_progress_callback.cpp b/src/core/host_interface_progress_callback.cpp index 05d348d8c..c9fbc58e6 100644 --- a/src/core/host_interface_progress_callback.cpp +++ b/src/core/host_interface_progress_callback.cpp @@ -6,7 +6,7 @@ #include "common/log.h" -LOG_CHANNEL(HostInterfaceProgressCallback); +LOG_CHANNEL(Host); HostInterfaceProgressCallback::HostInterfaceProgressCallback() : ProgressCallback() { diff --git a/src/core/settings.cpp b/src/core/settings.cpp index c4feb6efb..401525463 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -423,15 +423,6 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro achievements_leaderboard_duration = si.GetIntValue("Cheevos", "LeaderboardsDuration", DEFAULT_LEADERBOARD_NOTIFICATION_TIME); - log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str()) - .value_or(DEFAULT_LOG_LEVEL); - log_filter = si.GetStringValue("Logging", "LogFilter", ""); - log_timestamps = si.GetBoolValue("Logging", "LogTimestamps", true); - log_to_console = si.GetBoolValue("Logging", "LogToConsole", false); - log_to_debug = si.GetBoolValue("Logging", "LogToDebug", false); - log_to_window = si.GetBoolValue("Logging", "LogToWindow", false); - log_to_file = si.GetBoolValue("Logging", "LogToFile", false); - debugging.show_vram = si.GetBoolValue("Debug", "ShowVRAM"); debugging.dump_cpu_to_vram_copies = si.GetBoolValue("Debug", "DumpCPUToVRAMCopies"); debugging.dump_vram_to_cpu_copies = si.GetBoolValue("Debug", "DumpVRAMToCPUCopies"); @@ -694,14 +685,6 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const if (!ignore_base) { - si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level)); - si.SetStringValue("Logging", "LogFilter", log_filter.c_str()); - si.SetBoolValue("Logging", "LogTimestamps", log_timestamps); - si.SetBoolValue("Logging", "LogToConsole", log_to_console); - si.SetBoolValue("Logging", "LogToDebug", log_to_debug); - si.SetBoolValue("Logging", "LogToWindow", log_to_window); - si.SetBoolValue("Logging", "LogToFile", log_to_file); - si.SetBoolValue("Debug", "ShowVRAM", debugging.show_vram); si.SetBoolValue("Debug", "DumpCPUToVRAMCopies", debugging.dump_cpu_to_vram_copies); si.SetBoolValue("Debug", "DumpVRAMToCPUCopies", debugging.dump_vram_to_cpu_copies); @@ -1036,11 +1019,40 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages) } } -void Settings::UpdateLogSettings() +void Settings::SetDefaultLogConfig(SettingsInterface& si) { + si.SetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)); + si.SetBoolValue("Logging", "LogTimestamps", true); + +#if !defined(_WIN32) && !defined(__ANDROID__) + // On Linux, default the console to whether standard input is currently available. + si.SetBoolValue("Logging", "LogToConsole", Log::IsConsoleOutputCurrentlyAvailable()); +#else + si.SetBoolValue("Logging", "LogToConsole", false); +#endif + + si.SetBoolValue("Logging", "LogToDebug", false); + si.SetBoolValue("Logging", "LogToWindow", false); + si.SetBoolValue("Logging", "LogToFile", false); + + for (const char* channel_name : Log::GetChannelNames()) + si.SetBoolValue("Logging", channel_name, true); +} + +void Settings::UpdateLogConfig(const SettingsInterface& si) +{ + const Log::Level log_level = + ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str()) + .value_or(DEFAULT_LOG_LEVEL); + const bool log_timestamps = si.GetBoolValue("Logging", "LogTimestamps", true); + const bool log_to_console = si.GetBoolValue("Logging", "LogToConsole", false); + const bool log_to_debug = si.GetBoolValue("Logging", "LogToDebug", false); + const bool log_to_window = si.GetBoolValue("Logging", "LogToWindow", false); + const bool log_to_file = si.GetBoolValue("Logging", "LogToFile", false); + const bool any_logs_enabled = (log_to_console || log_to_debug || log_to_window || log_to_file); Log::SetLogLevel(any_logs_enabled ? log_level : Log::Level::None); - Log::SetLogFilter(any_logs_enabled ? std::string_view(log_filter) : std::string_view()); + Log::SetConsoleOutputParams(log_to_console, log_timestamps); Log::SetDebugOutputParams(log_to_debug); @@ -1053,6 +1065,10 @@ void Settings::UpdateLogSettings() { Log::SetFileOutputParams(false, nullptr); } + + const auto channel_names = Log::GetChannelNames(); + for (size_t i = 0; i < channel_names.size(); i++) + Log::SetLogChannelEnabled(static_cast(i), si.GetBoolValue("Logging", channel_names[i], true)); } void Settings::SetDefaultControllerConfig(SettingsInterface& si) @@ -2306,131 +2322,3 @@ std::string EmuFolders::GetOverridableResourcePath(std::string_view name) return upath; } - -static const char* s_log_filters[] = { - "Achievements", - "AnalogController", - "AnalogJoystick", - "AudioStream", - "AutoUpdaterDialog", - "BIOS", - "Bus", - "CDImage", - "CDImageBin", - "CDImageCHD", - "CDImageCueSheet", - "CDImageDevice", - "CDImageEcm", - "CDImageMds", - "CDImageMemory", - "CDImagePBP", - "CDImagePPF", - "CDROM", - "CDROMAsyncReader", - "CDSubChannelReplacement", - "CPU::CodeCache", - "CPU::Core", - "CPU::Recompiler", - "Common::PageFaultHandler", - "ControllerBindingWidget", - "CueParser", - "Cheats", - "DMA", - "DisplayWidget", - "FileSystem", - "FullscreenUI", - "GDBConnection", - "GDBProtocol", - "GDBServer", - "GPU", - "GPUBackend", - "GPUDevice", - "GPUShaderCache", - "GPUTexture", - "GPU_HW", - "GPU_SW", - "GameDatabase", - "GameList", - "GunCon", - "HTTPDownloader", - "Host", - "HostInterfaceProgressCallback", - "INISettingsInterface", - "ISOReader", - "ImGuiFullscreen", - "ImGuiManager", - "Image", - "InputManager", - "InterruptController", - "JitCodeBuffer", - "MDEC", - "MainWindow", - "MemoryArena", - "MemoryCard", - "Multitap", - "NoGUIHost", - "PCDrv", - "PGXP", - "PSFLoader", - "Pad", - "PlatformMisc", - "PlayStationMouse", - "PostProcessing", - "ProgressCallback", - "QTTranslations", - "QtHost", - "ReShadeFXShader", - "Recompiler::CodeGenerator", - "RegTestHost", - "SDLInputSource", - "SIO", - "SPIRVCompiler", - "SPU", - "Settings", - "ShaderGen", - "StateWrapper", - "System", - "TextureReplacements", - "Timers", - "TimingEvents", - "WAVWriter", - "WindowInfo", - -#ifndef __ANDROID__ - "CubebAudioStream", - "SDLAudioStream", -#endif - -#ifdef ENABLE_OPENGL - "OpenGLContext", - "OpenGLDevice", -#endif - -#ifdef ENABLE_VULKAN - "VulkanDevice", -#endif - -#if defined(_WIN32) - "D3D11Device", - "D3D12Device", - "D3D12StreamBuffer", - "D3DCommon", - "DInputSource", - "Win32ProgressCallback", - "Win32RawInputSource", - "XAudio2AudioStream", - "XInputSource", -#elif defined(__APPLE__) - "CocoaNoGUIPlatform", - "CocoaProgressCallback", - "MetalDevice", -#else - "X11NoGUIPlatform", - "WaylandNoGUIPlatform", -#endif -}; - -std::span Settings::GetLogFilters() -{ - return s_log_filters; -} diff --git a/src/core/settings.h b/src/core/settings.h index 1f82f8fd5..d30b40767 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -291,14 +291,6 @@ struct Settings std::string pcdrv_root; bool pcdrv_enable_writes = false; - Log::Level log_level = DEFAULT_LOG_LEVEL; - std::string log_filter; - bool log_timestamps : 1 = true; - bool log_to_console : 1 = false; - bool log_to_debug : 1 = false; - bool log_to_window : 1 = false; - bool log_to_file : 1 = false; - ALWAYS_INLINE bool IsUsingSoftwareRenderer() const { return (gpu_renderer == GPURenderer::Software); } ALWAYS_INLINE bool IsUsingAccurateBlending() const { return (gpu_accurate_blending && !gpu_true_color); } ALWAYS_INLINE bool IsRunaheadEnabled() const { return (runahead_frames > 0); } @@ -375,7 +367,8 @@ struct Settings void FixIncompatibleSettings(bool display_osd_messages); /// Initializes configuration. - void UpdateLogSettings(); + static void SetDefaultLogConfig(SettingsInterface& si); + static void UpdateLogConfig(const SettingsInterface& si); static void SetDefaultControllerConfig(SettingsInterface& si); static void SetDefaultHotkeyConfig(SettingsInterface& si); @@ -383,7 +376,6 @@ struct Settings static std::optional ParseLogLevelName(const char* str); static const char* GetLogLevelName(Log::Level level); static const char* GetLogLevelDisplayName(Log::Level level); - static std::span GetLogFilters(); static std::optional ParseConsoleRegionName(const char* str); static const char* GetConsoleRegionName(ConsoleRegion region); diff --git a/src/core/system.cpp b/src/core/system.cpp index 6573cd13d..c8e64f7e5 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1292,13 +1292,13 @@ void System::LoadSettings(bool display_osd_messages) const SettingsInterface& controller_si = GetControllerSettingsLayer(lock); const SettingsInterface& hotkey_si = GetHotkeySettingsLayer(lock); g_settings.Load(si, controller_si); - g_settings.UpdateLogSettings(); // Global safe mode overrides game settings. g_settings.disable_all_enhancements = (g_settings.disable_all_enhancements || Host::Internal::GetBaseSettingsLayer()->GetBoolValue("Main", "DisableAllEnhancements", false)); + Settings::UpdateLogConfig(si); Host::LoadSettings(si, lock); InputManager::ReloadSources(controller_si, lock); InputManager::ReloadBindings(controller_si, hotkey_si); @@ -1399,10 +1399,7 @@ void System::SetDefaultSettings(SettingsInterface& si) si.SetBoolValue("Main", "StartPaused", false); si.SetBoolValue("Main", "StartFullscreen", false); -#if !defined(_WIN32) && !defined(__ANDROID__) - // On Linux, default the console to whether standard input is currently available. - si.SetBoolValue("Logging", "LogToConsole", Log::IsConsoleOutputCurrentlyAvailable()); -#endif + Settings::SetDefaultLogConfig(si); #ifndef __ANDROID__ si.SetStringValue("MediaCapture", "Backend", MediaCapture::GetBackendName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND)); @@ -4493,15 +4490,6 @@ void System::CheckForSettingsChanges(const Settings& old_settings) Panic("Failed to reallocate memory map. The log may contain more information."); } } - - if (g_settings.log_level != old_settings.log_level || g_settings.log_filter != old_settings.log_filter || - g_settings.log_timestamps != old_settings.log_timestamps || - g_settings.log_to_console != old_settings.log_to_console || - g_settings.log_to_debug != old_settings.log_to_debug || g_settings.log_to_window != old_settings.log_to_window || - g_settings.log_to_file != old_settings.log_to_file) - { - g_settings.UpdateLogSettings(); - } } void System::SetTaintsFromSettings() diff --git a/src/duckstation-qt/advancedsettingswidget.cpp b/src/duckstation-qt/advancedsettingswidget.cpp index bc41b29c0..6a0b1f845 100644 --- a/src/duckstation-qt/advancedsettingswidget.cpp +++ b/src/duckstation-qt/advancedsettingswidget.cpp @@ -2,12 +2,17 @@ // SPDX-License-Identifier: CC-BY-NC-ND-4.0 #include "advancedsettingswidget.h" -#include "core/gpu_types.h" +#include "logwindow.h" #include "mainwindow.h" #include "qtutils.h" #include "settingswindow.h" #include "settingwidgetbinder.h" +#include "core/gpu_types.h" + +#include +#include + static QCheckBox* addBooleanTweakOption(SettingsWindow* dialog, QTableWidget* table, QString name, std::string section, std::string key, bool default_value) { @@ -162,12 +167,11 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* m_ui.setupUi(this); - for (u32 i = 0; i < static_cast(Log::Level::Count); i++) + for (u32 i = 0; i < static_cast(Log::Level::MaxCount); i++) m_ui.logLevel->addItem(QString::fromUtf8(Settings::GetLogLevelDisplayName(static_cast(i)))); SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.logLevel, "Logging", "LogLevel", &Settings::ParseLogLevelName, &Settings::GetLogLevelName, Settings::DEFAULT_LOG_LEVEL); - SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.logFilter, "Logging", "LogFilter"); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.logToConsole, "Logging", "LogToConsole", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.logToDebug, "Logging", "LogToDebug", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.logToWindow, "Logging", "LogToWindow", false); @@ -175,6 +179,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showDebugMenu, "Main", "ShowDebugMenu", false); + connect(m_ui.logChannels, &QToolButton::clicked, this, &AdvancedSettingsWidget::onLogChannelsButtonClicked); connect(m_ui.resetToDefaultButton, &QPushButton::clicked, this, &AdvancedSettingsWidget::onResetToDefaultClicked); connect(m_ui.showDebugMenu, &QCheckBox::checkStateChanged, g_main_window, &MainWindow::updateDebugMenuVisibility, Qt::QueuedConnection); @@ -202,6 +207,13 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* AdvancedSettingsWidget::~AdvancedSettingsWidget() = default; +void AdvancedSettingsWidget::onLogChannelsButtonClicked() +{ + QMenu menu; + LogWindow::populateFilterMenu(&menu); + menu.exec(QCursor::pos()); +} + void AdvancedSettingsWidget::onShowDebugOptionsStateChanged() { const bool enabled = QtHost::ShouldShowDebugOptions(); diff --git a/src/duckstation-qt/advancedsettingswidget.h b/src/duckstation-qt/advancedsettingswidget.h index ab51eda31..a1bb393a1 100644 --- a/src/duckstation-qt/advancedsettingswidget.h +++ b/src/duckstation-qt/advancedsettingswidget.h @@ -21,6 +21,7 @@ Q_SIGNALS: void onShowDebugOptionsChanged(bool enabled); private Q_SLOTS: + void onLogChannelsButtonClicked(); void onShowDebugOptionsStateChanged(); private: diff --git a/src/duckstation-qt/advancedsettingswidget.ui b/src/duckstation-qt/advancedsettingswidget.ui index 9e6047e42..529184056 100644 --- a/src/duckstation-qt/advancedsettingswidget.ui +++ b/src/duckstation-qt/advancedsettingswidget.ui @@ -6,8 +6,8 @@ 0 0 - 973 - 507 + 560 + 358 @@ -39,17 +39,21 @@ - - - - - - Log Filters: - - - - - + + + + + + + + Log Channels + + + + + + + @@ -158,7 +162,7 @@ - + diff --git a/src/duckstation-qt/displaywidget.cpp b/src/duckstation-qt/displaywidget.cpp index 575f18f6c..e91790d5f 100644 --- a/src/duckstation-qt/displaywidget.cpp +++ b/src/duckstation-qt/displaywidget.cpp @@ -30,7 +30,7 @@ #include "common/windows_headers.h" #endif -LOG_CHANNEL(DisplayWidget); +LOG_CHANNEL(Host); DisplayWidget::DisplayWidget(QWidget* parent) : QWidget(parent) { diff --git a/src/duckstation-qt/logwindow.cpp b/src/duckstation-qt/logwindow.cpp index 3d80c5f7e..8b7b9f58f 100644 --- a/src/duckstation-qt/logwindow.cpp +++ b/src/duckstation-qt/logwindow.cpp @@ -19,8 +19,7 @@ LogWindow* g_log_window; LogWindow::LogWindow(bool attach_to_main) - : QMainWindow(), m_filter_names(Settings::GetLogFilters()), m_is_dark_theme(QtHost::IsDarkApplicationTheme()), - m_attached_to_main_window(attach_to_main) + : QMainWindow(), m_is_dark_theme(QtHost::IsDarkApplicationTheme()), m_attached_to_main_window(attach_to_main) { restoreSize(); createUi(); @@ -158,7 +157,7 @@ void LogWindow::createUi() settings_menu->addSeparator(); m_level_menu = settings_menu->addMenu(tr("&Log Level")); - for (u32 i = 0; i < static_cast(Log::Level::Count); i++) + for (u32 i = 0; i < static_cast(Log::Level::MaxCount); i++) { action = m_level_menu->addAction(QString::fromUtf8(Settings::GetLogLevelDisplayName(static_cast(i)))); action->setCheckable(true); @@ -166,8 +165,11 @@ void LogWindow::createUi() } updateLogLevelUi(); - QMenu* filters_menu = menu->addMenu(tr("&Filters")); - populateFilters(filters_menu); + QMenu* filters_menu = menu->addMenu(tr("&Channels")); + connect(filters_menu, &QMenu::aboutToShow, this, [filters_menu]() { + filters_menu->clear(); + populateFilterMenu(filters_menu); + }); m_text = new QPlainTextEdit(this); m_text->setReadOnly(true); @@ -208,52 +210,25 @@ void LogWindow::setLogLevel(Log::Level level) g_emu_thread->applySettings(false); } -void LogWindow::populateFilters(QMenu* filter_menu) +void LogWindow::populateFilterMenu(QMenu* filter_menu) { - const std::string filters = Host::GetBaseStringSettingValue("Logging", "LogFilter", ""); - for (size_t i = 0; i < m_filter_names.size(); i++) + const auto settings_Lock = Host::GetSettingsLock(); + const INISettingsInterface* si = QtHost::GetBaseSettingsInterface(); + + for (const char* channel_name : Log::GetChannelNames()) { - const char* filter = m_filter_names[i]; - const bool is_currently_filtered = (filters.find(filter) == std::string::npos); - QAction* action = filter_menu->addAction(QString::fromUtf8(filter)); - action->setCheckable(action); - action->setChecked(is_currently_filtered); - connect(action, &QAction::triggered, this, [this, i](bool checked) { setChannelFiltered(i, !checked); }); + const bool enabled = si->GetBoolValue("Logging", channel_name, true); + QAction* action = filter_menu->addAction(QString::fromUtf8(channel_name)); + action->setCheckable(true); + action->setChecked(enabled); + connect(action, &QAction::triggered, action, [channel_name](bool checked) { + Host::SetBaseBoolSettingValue("Logging", channel_name, checked); + Host::CommitBaseSettingChanges(); + g_emu_thread->applySettings(false); + }); } } -void LogWindow::setChannelFiltered(size_t index, bool enabled) -{ - const char* filter = m_filter_names[index]; - const size_t filter_len = std::strlen(filter); - - std::string filters = Host::GetBaseStringSettingValue("Logging", "LogFilter", ""); - const std::string::size_type pos = filters.find(filter); - - if (!enabled) - { - if (pos == std::string::npos) - return; - - const size_t erase_count = - filter_len + (((pos + filter_len) < filters.length() && filters[pos + filter_len] == ' ') ? 1 : 0); - filters.erase(pos, erase_count); - } - else - { - if (pos != std::string::npos) - return; - - if (!filters.empty() && filters.back() != ' ') - filters.push_back(' '); - filters.append(filter); - } - - Host::SetBaseStringSettingValue("Logging", "LogFilter", filters.c_str()); - Host::CommitBaseSettingChanges(); - g_emu_thread->applySettings(false); -} - void LogWindow::onClearTriggered() { m_text->clear(); @@ -339,9 +314,9 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, c temp_cursor.movePosition(QTextCursor::End); { - static constexpr const QChar level_characters[static_cast(Log::Level::Count)] = {'X', 'E', 'W', 'I', - 'V', 'D', 'B', 'T'}; - static constexpr const QColor level_colors[2][static_cast(Log::Level::Count)] = { + static constexpr const QChar level_characters[static_cast(Log::Level::MaxCount)] = {'X', 'E', 'W', 'I', + 'V', 'D', 'B', 'T'}; + static constexpr const QColor level_colors[2][static_cast(Log::Level::MaxCount)] = { { // Light theme QColor(0, 0, 0), // NONE @@ -371,7 +346,7 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, c QTextCharFormat format = temp_cursor.charFormat(); const size_t dark = static_cast(m_is_dark_theme); - if (g_settings.log_timestamps) + if (Log::AreTimestampsEnabled()) { const float message_time = Log::GetCurrentMessageTime(); const QString qtimestamp = QStringLiteral("[%1] ").arg(message_time, 10, 'f', 4); diff --git a/src/duckstation-qt/logwindow.h b/src/duckstation-qt/logwindow.h index d00054191..ffd2e0ee1 100644 --- a/src/duckstation-qt/logwindow.h +++ b/src/duckstation-qt/logwindow.h @@ -25,12 +25,12 @@ public: void updateWindowTitle(); + static void populateFilterMenu(QMenu* menu); + private: void createUi(); void updateLogLevelUi(); void setLogLevel(Log::Level level); - void populateFilters(QMenu* filter_menu); - void setChannelFiltered(size_t index, bool state); static void logCallback(void* pUserParam, const char* channelName, const char* functionName, Log::Level level, std::string_view message); @@ -53,7 +53,6 @@ private: QPlainTextEdit* m_text; QMenu* m_level_menu; - std::span m_filter_names; bool m_is_dark_theme = false; bool m_attached_to_main_window = true; diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index 99e8b7011..d2312dc1d 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -58,7 +58,7 @@ #include #endif -LOG_CHANNEL(MainWindow); +LOG_CHANNEL(Host); static constexpr char DISC_IMAGE_FILTER[] = QT_TRANSLATE_NOOP( "MainWindow", "All File Types (*.bin *.img *.iso *.cue *.chd *.ecm *.mds *.pbp *.exe *.psexe *.ps-exe *.psx *.psf " diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 76719b7e3..49f59bf2d 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -69,7 +69,7 @@ #include #include -LOG_CHANNEL(QtHost); +LOG_CHANNEL(Host); #ifdef _WIN32 #include "common/windows_headers.h" diff --git a/src/duckstation-qt/qttranslations.cpp b/src/duckstation-qt/qttranslations.cpp index 8bba4f646..c1fe0eb2d 100644 --- a/src/duckstation-qt/qttranslations.cpp +++ b/src/duckstation-qt/qttranslations.cpp @@ -32,7 +32,7 @@ #include #endif -LOG_CHANNEL(QTTranslations); +LOG_CHANNEL(Host); #if 0 // Qt internal strings we'd like to have translated diff --git a/src/duckstation-qt/qtutils.cpp b/src/duckstation-qt/qtutils.cpp index 82a133953..f613aa2a6 100644 --- a/src/duckstation-qt/qtutils.cpp +++ b/src/duckstation-qt/qtutils.cpp @@ -40,7 +40,7 @@ #include "common/windows_headers.h" #endif -LOG_CHANNEL(QtUtils); +LOG_CHANNEL(Host); QFrame* QtUtils::CreateHorizontalLine(QWidget* parent) { diff --git a/src/updater/cocoa_progress_callback.mm b/src/updater/cocoa_progress_callback.mm index ac2e61370..229e4903a 100644 --- a/src/updater/cocoa_progress_callback.mm +++ b/src/updater/cocoa_progress_callback.mm @@ -6,7 +6,7 @@ #include "common/cocoa_tools.h" #include "common/log.h" -LOG_CHANNEL(CocoaProgressCallback); +LOG_CHANNEL(Host); CocoaProgressCallback::CocoaProgressCallback() : ProgressCallback() { diff --git a/src/updater/win32_progress_callback.cpp b/src/updater/win32_progress_callback.cpp index e046b090d..a7b50a2cf 100644 --- a/src/updater/win32_progress_callback.cpp +++ b/src/updater/win32_progress_callback.cpp @@ -8,7 +8,7 @@ #include -LOG_CHANNEL(Win32ProgressCallback); +LOG_CHANNEL(Host); Win32ProgressCallback::Win32ProgressCallback() : ProgressCallback() { diff --git a/src/util/cd_image_chd.cpp b/src/util/cd_image_chd.cpp index a315be7e1..42e575de6 100644 --- a/src/util/cd_image_chd.cpp +++ b/src/util/cd_image_chd.cpp @@ -26,7 +26,7 @@ #include #include -LOG_CHANNEL(CDImageCHD); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/cd_image_cue.cpp b/src/util/cd_image_cue.cpp index 6b1406632..c4e52c84e 100644 --- a/src/util/cd_image_cue.cpp +++ b/src/util/cd_image_cue.cpp @@ -16,7 +16,7 @@ #include #include -LOG_CHANNEL(CDImageCueSheet); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/cd_image_device.cpp b/src/util/cd_image_device.cpp index 082a8aeb2..18fd8e032 100644 --- a/src/util/cd_image_device.cpp +++ b/src/util/cd_image_device.cpp @@ -23,7 +23,7 @@ #include #include -LOG_CHANNEL(CDImageDevice); +LOG_CHANNEL(CDImage); // Common code [[maybe_unused]] static constexpr u32 MAX_TRACK_NUMBER = 99; diff --git a/src/util/cd_image_ecm.cpp b/src/util/cd_image_ecm.cpp index 9c680f435..3cc5e2103 100644 --- a/src/util/cd_image_ecm.cpp +++ b/src/util/cd_image_ecm.cpp @@ -14,7 +14,7 @@ #include #include -LOG_CHANNEL(CDImageEcm); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/cd_image_m3u.cpp b/src/util/cd_image_m3u.cpp index 42e84aea7..1d0d12177 100644 --- a/src/util/cd_image_m3u.cpp +++ b/src/util/cd_image_m3u.cpp @@ -14,7 +14,7 @@ #include #include -LOG_CHANNEL(CDImageMemory); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/cd_image_mds.cpp b/src/util/cd_image_mds.cpp index 5dd98e14f..96146feb8 100644 --- a/src/util/cd_image_mds.cpp +++ b/src/util/cd_image_mds.cpp @@ -13,7 +13,7 @@ #include #include -LOG_CHANNEL(CDImageMds); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/cd_image_memory.cpp b/src/util/cd_image_memory.cpp index 7904909b5..df8de4132 100644 --- a/src/util/cd_image_memory.cpp +++ b/src/util/cd_image_memory.cpp @@ -11,7 +11,7 @@ #include #include -LOG_CHANNEL(CDImageMemory); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/cd_image_pbp.cpp b/src/util/cd_image_pbp.cpp index 7335299b3..050393ac0 100644 --- a/src/util/cd_image_pbp.cpp +++ b/src/util/cd_image_pbp.cpp @@ -21,7 +21,7 @@ #include #include -LOG_CHANNEL(CDImagePBP); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/cd_image_ppf.cpp b/src/util/cd_image_ppf.cpp index 8f59721e5..b57296b22 100644 --- a/src/util/cd_image_ppf.cpp +++ b/src/util/cd_image_ppf.cpp @@ -13,7 +13,7 @@ #include #include -LOG_CHANNEL(CDImagePPF); +LOG_CHANNEL(CDImage); namespace { diff --git a/src/util/ini_settings_interface.cpp b/src/util/ini_settings_interface.cpp index 614a64fff..855d49ee9 100644 --- a/src/util/ini_settings_interface.cpp +++ b/src/util/ini_settings_interface.cpp @@ -13,7 +13,7 @@ #include #include -LOG_CHANNEL(INISettingsInterface); +LOG_CHANNEL(Settings); // To prevent races between saving and loading settings, particularly with game settings, // we only allow one ini to be parsed at any point in time. diff --git a/src/util/metal_device.mm b/src/util/metal_device.mm index fe30df994..486a88fcd 100644 --- a/src/util/metal_device.mm +++ b/src/util/metal_device.mm @@ -75,9 +75,9 @@ static constexpr std::array(GPUTexture::Format: static void LogNSError(NSError* error, std::string_view message) { - Log::FastWrite("MetalDevice", Log::Level::Error, message); - Log::FastWrite("MetalDevice", Log::Level::Error, " NSError Code: {}", static_cast(error.code)); - Log::FastWrite("MetalDevice", Log::Level::Error, " NSError Description: {}", [error.description UTF8String]); + Log::FastWrite(Log::Channel::GPUDevice, Log::Level::Error, message); + Log::FastWrite(Log::Channel::GPUDevice, Log::Level::Error, " NSError Code: {}", static_cast(error.code)); + Log::FastWrite(Log::Channel::GPUDevice, Log::Level::Error, " NSError Description: {}", [error.description UTF8String]); } static GPUTexture::Format GetTextureFormatForMTLFormat(MTLPixelFormat fmt) diff --git a/src/util/sdl_audio_stream.cpp b/src/util/sdl_audio_stream.cpp index c08a5d33a..43850b13b 100644 --- a/src/util/sdl_audio_stream.cpp +++ b/src/util/sdl_audio_stream.cpp @@ -9,7 +9,7 @@ #include -LOG_CHANNEL(SDLAudioStream); +LOG_CHANNEL(SDL); namespace { class SDLAudioStream final : public AudioStream diff --git a/src/util/sdl_input_source.cpp b/src/util/sdl_input_source.cpp index bba9f0bf1..484f41f49 100644 --- a/src/util/sdl_input_source.cpp +++ b/src/util/sdl_input_source.cpp @@ -23,7 +23,7 @@ #include #endif -LOG_CHANNEL(SDLInputSource); +LOG_CHANNEL(SDL); static constexpr const char* CONTROLLER_DB_FILENAME = "gamecontrollerdb.txt"; @@ -149,7 +149,7 @@ static void SDLLogCallback(void* userdata, int category, SDL_LogPriority priorit Log::Level::Error, // SDL_LOG_PRIORITY_CRITICAL }; - Log::Write("SDL", "SDL", priority_map[priority], message); + Log::FastWrite(Log::Channel::SDL, priority_map[priority], message); } bool SDLInputSource::ALLOW_EVENT_POLLING = true; diff --git a/src/util/vulkan_builders.cpp b/src/util/vulkan_builders.cpp index 1c747b6a5..d9a64a356 100644 --- a/src/util/vulkan_builders.cpp +++ b/src/util/vulkan_builders.cpp @@ -106,8 +106,8 @@ const char* Vulkan::VkResultToString(VkResult res) void Vulkan::LogVulkanResult(const char* func_name, VkResult res, std::string_view msg) { - Log::FastWrite("VulkanDevice", func_name, Log::Level::Error, "{} (0x{:08X}: {})", msg, static_cast(res), - VkResultToString(res)); + Log::FastWrite(Log::Channel::GPUDevice, func_name, Log::Level::Error, "{} (0x{:08X}: {})", msg, + static_cast(res), VkResultToString(res)); } void Vulkan::SetErrorObject(Error* errptr, std::string_view prefix, VkResult res)