Log: Replace channel string search with bitset

Knocks off around ~20KB of code.
This commit is contained in:
Stenzek 2024-10-31 14:22:41 +10:00
parent afb9ab7d11
commit 6551358212
No known key found for this signature in database
54 changed files with 422 additions and 414 deletions

View File

@ -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

View File

@ -24,6 +24,7 @@
<ClInclude Include="intrin.h" />
<ClInclude Include="layered_settings_interface.h" />
<ClInclude Include="log.h" />
<ClInclude Include="log_channels.h" />
<ClInclude Include="lru_cache.h" />
<ClInclude Include="memmap.h" />
<ClInclude Include="memory_settings_interface.h" />

View File

@ -49,6 +49,7 @@
<ClInclude Include="gsvector_formatter.h" />
<ClInclude Include="gsvector_nosimd.h" />
<ClInclude Include="ryml_helpers.h" />
<ClInclude Include="log_channels.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="small_string.cpp" />

View File

@ -9,6 +9,8 @@
#include "fmt/format.h"
#include <array>
#include <bitset>
#include <cstdio>
#include <mutex>
#include <vector>
@ -34,12 +36,15 @@ struct RegisteredCallback
};
} // namespace
using ChannelBitSet = std::bitset<static_cast<size_t>(Channel::MaxCount)>;
static void RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam,
const std::unique_lock<std::mutex>& lock);
static void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam,
const std::unique_lock<std::mutex>& lock);
static bool FilterTest(Level level, const char* channelName, const std::unique_lock<std::mutex>& 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<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,
@ -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<size_t>(Level::Count)] = {'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'};
ALWAYS_INLINE static Channel UnpackLogChannel(PackedChannelAndLevel cat)
{
return static_cast<Channel>(cat >> 3);
}
static std::vector<RegisteredCallback> s_callbacks;
static std::mutex s_callback_mutex;
ALWAYS_INLINE static Level UnpackLogLevel(PackedChannelAndLevel cat)
{
return static_cast<Level>(cat & 0x7);
}
static Common::Timer::Value s_start_timestamp = Common::Timer::GetCurrentValue();
static constexpr const std::array<char, static_cast<size_t>(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<const char*, static_cast<size_t>(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<RegisteredCallback> 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<std::FILE, void (*)(std::FILE*)> 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<std::mutex>& 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<const char*, static_cast<size_t>(Log::Channel::MaxCount)>& Log::GetChannelNames()
{
return s_log_channel_names;
}
float Log::GetCurrentMessageTime()
{
return static_cast<float>(Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_start_timestamp));
return static_cast<float>(
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<std::mutex>& 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<size_t>(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<size_t>(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<DWORD>(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<DWORD>(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<size_t>(channel)] = enabled;
}
ALWAYS_INLINE_RELEASE bool Log::FilterTest(Level level, const char* channelName,
const std::unique_lock<std::mutex>& 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<size_t>(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);
}

View File

@ -3,17 +3,19 @@
#pragma once
#include "log_channels.h"
#include "types.h"
#include "fmt/base.h"
#include <array>
#include <cinttypes>
#include <cstdarg>
#include <mutex>
#include <string_view>
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<const char*, static_cast<size_t>(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<PackedChannelAndLevel>(channel) << 3) | static_cast<PackedChannelAndLevel>(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<typename... T>
ALWAYS_INLINE static void FastWrite(const char* channelName, Level level, fmt::format_string<T...> fmt, T&&... args)
ALWAYS_INLINE static void FastWrite(Channel channel, Level level, fmt::format_string<T...> fmt, T&&... args)
{
if (level <= GetLogLevel()) [[unlikely]]
WriteFmtArgs(channelName, level, fmt, fmt::make_format_args(args...));
WriteFmtArgs(PackChannelAndLevel(channel, level), fmt, fmt::make_format_args(args...));
}
template<typename... T>
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<T...> 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__)

84
src/common/log_channels.h Normal file
View File

@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// 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)

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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;
}

View File

@ -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

View File

@ -26,7 +26,7 @@
#include <cstdio>
LOG_CHANNEL(CPU::Core);
LOG_CHANNEL(CPU);
namespace CPU {
enum class ExecutionBreakType

View File

@ -15,7 +15,7 @@
#include <cstdint>
#include <limits>
LOG_CHANNEL(NewRec::Compiler);
LOG_CHANNEL(Recompiler);
// TODO: direct link skip delay slot check
// TODO: speculative constants

View File

@ -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

View File

@ -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)))

View File

@ -20,7 +20,7 @@
#ifdef CPU_ARCH_RISCV64
LOG_CHANNEL(CPU::NewRec);
LOG_CHANNEL(Recompiler);
#ifdef ENABLE_HOST_DISASSEMBLY
extern "C" {

View File

@ -20,7 +20,7 @@
#ifdef CPU_ARCH_X64
LOG_CHANNEL(CPU::NewRec);
LOG_CHANNEL(Recompiler);
#define RMEMBASE cg->rbx
#define RSTATE cg->rbp

View File

@ -19,7 +19,7 @@
#include <climits>
#include <cmath>
LOG_CHANNEL(CPU::PGXP);
LOG_CHANNEL(CPU);
// #define LOG_VALUES 1
// #define LOG_LOOKUPS 1

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -8,7 +8,7 @@
#include "common/log.h"
LOG_CHANNEL(Recompiler::CodeGenerator);
LOG_CHANNEL(Recompiler);
namespace CPU::Recompiler {

View File

@ -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<u64>(reinterpret_cast<uintptr_t>(ptr)), hex, buffer);
DEBUG_LOG(" {:016X} {} {}", static_cast<u64>(reinterpret_cast<uintptr_t>(ptr)), hex, buffer);
}
ptr += disas_instruction.length;

View File

@ -8,7 +8,7 @@
#include <cinttypes>
LOG_CHANNEL(CPU::Recompiler);
LOG_CHANNEL(Recompiler);
namespace CPU::Recompiler {

View File

@ -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"),

View File

@ -6,7 +6,7 @@
#include "common/log.h"
LOG_CHANNEL(HostInterfaceProgressCallback);
LOG_CHANNEL(Host);
HostInterfaceProgressCallback::HostInterfaceProgressCallback() : ProgressCallback()
{

View File

@ -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<Log::Channel>(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<const char*> Settings::GetLogFilters()
{
return s_log_filters;
}

View File

@ -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<Log::Level> ParseLogLevelName(const char* str);
static const char* GetLogLevelName(Log::Level level);
static const char* GetLogLevelDisplayName(Log::Level level);
static std::span<const char*> GetLogFilters();
static std::optional<ConsoleRegion> ParseConsoleRegionName(const char* str);
static const char* GetConsoleRegionName(ConsoleRegion region);

View File

@ -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()

View File

@ -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 <QtGui/QCursor>
#include <QtWidgets/QMenu>
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<u32>(Log::Level::Count); i++)
for (u32 i = 0; i < static_cast<u32>(Log::Level::MaxCount); i++)
m_ui.logLevel->addItem(QString::fromUtf8(Settings::GetLogLevelDisplayName(static_cast<Log::Level>(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();

View File

@ -21,6 +21,7 @@ Q_SIGNALS:
void onShowDebugOptionsChanged(bool enabled);
private Q_SLOTS:
void onLogChannelsButtonClicked();
void onShowDebugOptionsStateChanged();
private:

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>973</width>
<height>507</height>
<width>560</width>
<height>358</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
@ -39,17 +39,21 @@
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="logLevel"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Log Filters:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="logFilter"/>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="logLevel"/>
</item>
<item>
<widget class="QToolButton" name="logChannels">
<property name="toolTip">
<string>Log Channels</string>
</property>
<property name="icon">
<iconset theme="filter-line"/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
@ -158,7 +162,7 @@
</layout>
</widget>
<resources>
<include location="resources/resources.qrc"/>
<include location="resources/duckstation-qt.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -30,7 +30,7 @@
#include "common/windows_headers.h"
#endif
LOG_CHANNEL(DisplayWidget);
LOG_CHANNEL(Host);
DisplayWidget::DisplayWidget(QWidget* parent) : QWidget(parent)
{

View File

@ -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<u32>(Log::Level::Count); i++)
for (u32 i = 0; i < static_cast<u32>(Log::Level::MaxCount); i++)
{
action = m_level_menu->addAction(QString::fromUtf8(Settings::GetLogLevelDisplayName(static_cast<Log::Level>(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<size_t>(Log::Level::Count)] = {'X', 'E', 'W', 'I',
'V', 'D', 'B', 'T'};
static constexpr const QColor level_colors[2][static_cast<size_t>(Log::Level::Count)] = {
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)] = {
{
// 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<size_t>(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);

View File

@ -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<const char*> m_filter_names;
bool m_is_dark_theme = false;
bool m_attached_to_main_window = true;

View File

@ -58,7 +58,7 @@
#include <VersionHelpers.h>
#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 "

View File

@ -69,7 +69,7 @@
#include <cstdlib>
#include <memory>
LOG_CHANNEL(QtHost);
LOG_CHANNEL(Host);
#ifdef _WIN32
#include "common/windows_headers.h"

View File

@ -32,7 +32,7 @@
#include <ShlObj.h>
#endif
LOG_CHANNEL(QTTranslations);
LOG_CHANNEL(Host);
#if 0
// Qt internal strings we'd like to have translated

View File

@ -40,7 +40,7 @@
#include "common/windows_headers.h"
#endif
LOG_CHANNEL(QtUtils);
LOG_CHANNEL(Host);
QFrame* QtUtils::CreateHorizontalLine(QWidget* parent)
{

View File

@ -6,7 +6,7 @@
#include "common/cocoa_tools.h"
#include "common/log.h"
LOG_CHANNEL(CocoaProgressCallback);
LOG_CHANNEL(Host);
CocoaProgressCallback::CocoaProgressCallback() : ProgressCallback()
{

View File

@ -8,7 +8,7 @@
#include <CommCtrl.h>
LOG_CHANNEL(Win32ProgressCallback);
LOG_CHANNEL(Host);
Win32ProgressCallback::Win32ProgressCallback() : ProgressCallback()
{

View File

@ -26,7 +26,7 @@
#include <mutex>
#include <optional>
LOG_CHANNEL(CDImageCHD);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -16,7 +16,7 @@
#include <cinttypes>
#include <map>
LOG_CHANNEL(CDImageCueSheet);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -23,7 +23,7 @@
#include <optional>
#include <span>
LOG_CHANNEL(CDImageDevice);
LOG_CHANNEL(CDImage);
// Common code
[[maybe_unused]] static constexpr u32 MAX_TRACK_NUMBER = 99;

View File

@ -14,7 +14,7 @@
#include <array>
#include <map>
LOG_CHANNEL(CDImageEcm);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -14,7 +14,7 @@
#include <map>
#include <sstream>
LOG_CHANNEL(CDImageMemory);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -13,7 +13,7 @@
#include <cerrno>
#include <map>
LOG_CHANNEL(CDImageMds);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -11,7 +11,7 @@
#include <algorithm>
#include <cerrno>
LOG_CHANNEL(CDImageMemory);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -21,7 +21,7 @@
#include <variant>
#include <vector>
LOG_CHANNEL(CDImagePBP);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -13,7 +13,7 @@
#include <map>
#include <unordered_map>
LOG_CHANNEL(CDImagePPF);
LOG_CHANNEL(CDImage);
namespace {

View File

@ -13,7 +13,7 @@
#include <iterator>
#include <mutex>
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.

View File

@ -75,9 +75,9 @@ static constexpr std::array<MTLPixelFormat, static_cast<u32>(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<u32>(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<u32>(error.code));
Log::FastWrite(Log::Channel::GPUDevice, Log::Level::Error, " NSError Description: {}", [error.description UTF8String]);
}
static GPUTexture::Format GetTextureFormatForMTLFormat(MTLPixelFormat fmt)

View File

@ -9,7 +9,7 @@
#include <SDL.h>
LOG_CHANNEL(SDLAudioStream);
LOG_CHANNEL(SDL);
namespace {
class SDLAudioStream final : public AudioStream

View File

@ -23,7 +23,7 @@
#include <dispatch/dispatch.h>
#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;

View File

@ -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<unsigned>(res),
VkResultToString(res));
Log::FastWrite(Log::Channel::GPUDevice, func_name, Log::Level::Error, "{} (0x{:08X}: {})", msg,
static_cast<unsigned>(res), VkResultToString(res));
}
void Vulkan::SetErrorObject(Error* errptr, std::string_view prefix, VkResult res)