diff --git a/src/app/audio_player.cpp b/src/app/audio_player.cpp index 7149d0b..fa8659e 100644 --- a/src/app/audio_player.cpp +++ b/src/app/audio_player.cpp @@ -23,7 +23,8 @@ struct DecodedAudio { }; DecodedAudio DecodeOgg(const std::filesystem::path& path) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(path.string()); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("DecodeOgg", path.string()); FILE* file = std::fopen(path.string().c_str(), "rb"); if (!file) { throw std::runtime_error("Failed to open audio file: " + path.string()); @@ -84,7 +85,8 @@ AudioPlayer::~AudioPlayer() { } void AudioPlayer::PlayBackground(const std::filesystem::path& path, bool loop) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(path.string(), loop); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("PlayBackground", path.string() + " " + ToString(loop)); DecodedAudio clip = DecodeOgg(path); EnsureStream(clip.sampleRate, clip.channels); std::scoped_lock lock(voicesMutex_); @@ -92,7 +94,8 @@ void AudioPlayer::PlayBackground(const std::filesystem::path& path, bool loop) { } void AudioPlayer::PlayEffect(const std::filesystem::path& path, bool loop) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(path.string(), loop); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("PlayEffect", path.string() + " " + ToString(loop)); DecodedAudio clip = DecodeOgg(path); EnsureStream(clip.sampleRate, clip.channels); std::scoped_lock lock(voicesMutex_); @@ -105,7 +108,8 @@ void AudioPlayer::AudioStreamCallback(void* userdata, SDL_AudioStream* stream, i } void AudioPlayer::FeedStream(SDL_AudioStream* stream, int totalAmount) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(static_cast(stream), totalAmount); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("FeedStream", ToString(static_cast(stream)) + " " + ToString(totalAmount)); if (totalAmount <= 0 || !stream_) { return; } @@ -147,7 +151,8 @@ void AudioPlayer::FeedStream(SDL_AudioStream* stream, int totalAmount) { } void AudioPlayer::EnsureStream(int sampleRate, int channels) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(sampleRate, channels); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("EnsureStream", ToString(sampleRate) + " " + ToString(channels)); if (sampleRate <= 0 || channels <= 0) { throw std::runtime_error("Audio format is invalid"); } @@ -178,7 +183,8 @@ void AudioPlayer::EnsureStream(int sampleRate, int channels) { } void AudioPlayer::AddVoiceSamples(AudioVoice& voice, std::vector& mixBuffer, size_t sampleCount) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(voice.data.size(), mixBuffer.size(), sampleCount); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("AddVoiceSamples", ToString(voice.data.size()) + " " + ToString(mixBuffer.size()) + " " + ToString(sampleCount)); if (voice.data.empty()) { voice.active = false; return; diff --git a/src/app/sdl3_app_core.cpp b/src/app/sdl3_app_core.cpp index fd000fb..4cf48c4 100644 --- a/src/app/sdl3_app_core.cpp +++ b/src/app/sdl3_app_core.cpp @@ -85,8 +85,9 @@ void ShowErrorDialog(const char* title, const std::string& message) { Sdl3App::Sdl3App(const std::filesystem::path& scriptPath, bool luaDebug) : scriptEngine_(scriptPath, luaDebug), scriptDirectory_(scriptPath.parent_path()) { - sdl3cpp::logging::TraceGuard trace;; - sdl3cpp::logging::Logger::GetInstance().TraceVariable("scriptPath", scriptPath); + sdl3cpp::logging::TraceGuard trace; + auto& logger = sdl3cpp::logging::Logger::GetInstance(); + logger.TraceVariable("scriptPath", scriptPath.string()); } bool Sdl3App::ShouldStop() { @@ -102,9 +103,10 @@ void Sdl3App::Run() { } void Sdl3App::InitSDL() { - sdl3cpp::logging::TraceGuard trace;; - sdl3cpp::logging::Logger::GetInstance().TraceVariable("kWidth", kWidth); - sdl3cpp::logging::Logger::GetInstance().TraceVariable("kHeight", kHeight); + sdl3cpp::logging::TraceGuard trace; + auto& logger = sdl3cpp::logging::Logger::GetInstance(); + logger.TraceVariable("kWidth", kWidth); + logger.TraceVariable("kHeight", kHeight); try { ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO), "SDL_Init failed"); diff --git a/src/core/platform.cpp b/src/core/platform.cpp index 452e091..9142551 100644 --- a/src/core/platform.cpp +++ b/src/core/platform.cpp @@ -29,7 +29,8 @@ std::optional GetUserConfigDirectory() { #ifdef _WIN32 namespace { std::string FormatWin32Error(DWORD errorCode) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(errorCode); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("FormatWin32Error", ToString(static_cast(errorCode))); if (errorCode == ERROR_SUCCESS) { return "ERROR_SUCCESS"; } diff --git a/src/logging/logger.cpp b/src/logging/logger.cpp index ce9c3a7..7e72f78 100644 --- a/src/logging/logger.cpp +++ b/src/logging/logger.cpp @@ -1,47 +1,68 @@ #include "logging/logger.hpp" +#include #include +#include #include +#include +#include +#include +#include #include namespace sdl3cpp::logging { +// Implementation class that holds all the C++ magic +class LoggerImpl { +public: + std::atomic level_; + bool consoleEnabled_; + std::unique_ptr fileStream_; + std::mutex mutex_; + + LoggerImpl() : level_(LogLevel::INFO), consoleEnabled_(true) {} + + ~LoggerImpl() { + if (fileStream_) { + fileStream_->close(); + } + } +}; + Logger& Logger::GetInstance() { static Logger instance; return instance; } -Logger::Logger() : level_(LogLevel::INFO), consoleEnabled_(true) {} +Logger::Logger() : impl_(new LoggerImpl()) {} Logger::~Logger() { - if (fileStream_) { - fileStream_->close(); - } + delete impl_; } void Logger::SetLevel(LogLevel level) { - level_.store(level, std::memory_order_relaxed); + impl_->level_.store(level, std::memory_order_relaxed); } LogLevel Logger::GetLevel() const { - return level_.load(std::memory_order_relaxed); + return impl_->level_.load(std::memory_order_relaxed); } void Logger::SetOutputFile(const std::string& filename) { - std::lock_guard lock(mutex_); - if (fileStream_) { - fileStream_->close(); + std::lock_guard lock(impl_->mutex_); + if (impl_->fileStream_) { + impl_->fileStream_->close(); } - fileStream_ = std::make_unique(filename, std::ios::app); - if (!fileStream_->is_open()) { + impl_->fileStream_ = std::make_unique(filename, std::ios::app); + if (!impl_->fileStream_->is_open()) { // Fallback to console if file can't be opened std::cerr << "Failed to open log file: " << filename << std::endl; - fileStream_.reset(); + impl_->fileStream_.reset(); } } void Logger::EnableConsoleOutput(bool enable) { - consoleEnabled_ = enable; + impl_->consoleEnabled_ = enable; } void Logger::Log(LogLevel level, const std::string& message) { @@ -49,14 +70,14 @@ void Logger::Log(LogLevel level, const std::string& message) { return; } - std::lock_guard lock(mutex_); + std::lock_guard lock(impl_->mutex_); std::string formattedMessage = FormatMessage(level, message); - if (consoleEnabled_) { + if (impl_->consoleEnabled_) { WriteToConsole(level, formattedMessage); } - if (fileStream_) { + if (impl_->fileStream_) { WriteToFile(formattedMessage); } } @@ -85,9 +106,9 @@ void Logger::WriteToConsole(LogLevel level, const std::string& message) { } void Logger::WriteToFile(const std::string& message) { - if (fileStream_) { - *fileStream_ << message << std::endl; - fileStream_->flush(); + if (impl_->fileStream_) { + *impl_->fileStream_ << message << std::endl; + impl_->fileStream_->flush(); } } @@ -105,4 +126,76 @@ std::string Logger::FormatMessage(LogLevel level, const std::string& message) { return oss.str(); } +void Logger::Trace(const std::string& message) { + Log(LogLevel::TRACE, message); +} + +void Logger::Debug(const std::string& message) { + Log(LogLevel::DEBUG, message); +} + +void Logger::Info(const std::string& message) { + Log(LogLevel::INFO, message); +} + +void Logger::Warn(const std::string& message) { + Log(LogLevel::WARN, message); +} + +void Logger::Error(const std::string& message) { + Log(LogLevel::ERROR, message); +} + +void Logger::TraceFunction(const std::string& funcName) { + if (GetLevel() <= LogLevel::TRACE) { + Trace("Entering " + funcName); + } +} + +void Logger::TraceVariable(const std::string& name, const std::string& value) { + if (GetLevel() <= LogLevel::TRACE) { + Trace(name + " = " + value); + } +} + +void Logger::TraceVariable(const std::string& name, int value) { + TraceVariable(name, std::to_string(value)); +} + +void Logger::TraceVariable(const std::string& name, size_t value) { + TraceVariable(name, std::to_string(value)); +} + +void Logger::TraceVariable(const std::string& name, bool value) { + TraceVariable(name, value ? "true" : "false"); +} + +void Logger::TraceVariable(const std::string& name, float value) { + TraceVariable(name, std::to_string(value)); +} + +void Logger::TraceVariable(const std::string& name, double value) { + TraceVariable(name, std::to_string(value)); +} + +void Logger::TraceFunctionWithArgs(const std::string& description, const std::string& args) { + if (GetLevel() <= LogLevel::TRACE) { + Trace(description + ": " + args); + } +} + +TraceGuard::TraceGuard(const std::string& funcName) + : funcName_(funcName), ended_(false) { + if (!funcName_.empty()) { + Logger::GetInstance().Trace("Entering " + funcName_); + } +} + +void TraceGuard::End() { + if (!ended_ && !funcName_.empty()) { + Logger::GetInstance().Trace("Exiting " + funcName_); + ended_ = true; + } +} + } // namespace sdl3cpp::logging \ No newline at end of file diff --git a/src/logging/logger.hpp b/src/logging/logger.hpp index 4709a31..400fc73 100644 --- a/src/logging/logger.hpp +++ b/src/logging/logger.hpp @@ -1,14 +1,7 @@ #ifndef SDL3CPP_LOGGING_LOGGER_HPP #define SDL3CPP_LOGGING_LOGGER_HPP -#include -#include -#include #include -#include -#include -#include -#include namespace sdl3cpp::logging { @@ -21,6 +14,9 @@ enum class LogLevel { OFF = 5 }; +// Forward declaration to hide implementation details +class LoggerImpl; + class Logger { public: static Logger& GetInstance(); @@ -35,67 +31,48 @@ public: void Log(LogLevel level, const char* message); // Convenience methods - void Trace(const std::string& message) { Log(LogLevel::TRACE, message); } - void Debug(const std::string& message) { Log(LogLevel::DEBUG, message); } - void Info(const std::string& message) { Log(LogLevel::INFO, message); } - void Warn(const std::string& message) { Log(LogLevel::WARN, message); } - void Error(const std::string& message) { Log(LogLevel::ERROR, message); } + void Trace(const std::string& message); + void Debug(const std::string& message); + void Info(const std::string& message); + void Warn(const std::string& message); + void Error(const std::string& message); // Tracing methods - void TraceFunction(const std::string& funcName) { - if (GetLevel() <= LogLevel::TRACE) { - Trace(std::string("Entering ") + funcName); - } - } + void TraceFunction(const std::string& funcName); - template - void TraceVariable(const std::string& name, const T& value) { - if (GetLevel() <= LogLevel::TRACE) { - std::ostringstream oss; - oss << name << " = " << value; - Trace(oss.str()); - } - } + // TraceVariable overloads for common types + void TraceVariable(const std::string& name, const std::string& value); + void TraceVariable(const std::string& name, int value); + void TraceVariable(const std::string& name, size_t value); + void TraceVariable(const std::string& name, bool value); + void TraceVariable(const std::string& name, float value); + void TraceVariable(const std::string& name, double value); - template - void TraceFunctionWithArgs(const Args&... args, const std::source_location& location = std::source_location::current()) { - if (GetLevel() <= LogLevel::TRACE) { - std::ostringstream oss; - oss << "Entering " << location.function_name() << " with args: "; - ((oss << args << " "), ...); - Trace(oss.str()); - } - } + void TraceFunctionWithArgs(const std::string& description, const std::string& args); private: Logger(); ~Logger(); - Logger(const Logger&) = delete; - Logger& operator=(const Logger&) = delete; + // Non-copyable (Java final class pattern) + Logger(const Logger&); + Logger& operator=(const Logger&); std::string LevelToString(LogLevel level) const; std::string FormatMessage(LogLevel level, const std::string& message); void WriteToConsole(LogLevel level, const std::string& message); void WriteToFile(const std::string& message); - std::atomic level_; - bool consoleEnabled_; - std::unique_ptr fileStream_; - std::mutex mutex_; + LoggerImpl* impl_; }; class TraceGuard { public: - explicit TraceGuard(const std::source_location& location = std::source_location::current()) - : funcName_(location.function_name()) { - Logger::GetInstance().Trace("Entering " + funcName_); - } - ~TraceGuard() { - Logger::GetInstance().Trace("Exiting " + funcName_); - } + explicit TraceGuard(const std::string& funcName = ""); + void End(); private: std::string funcName_; + bool ended_; }; } // namespace sdl3cpp::logging diff --git a/src/logging/string_utils.cpp b/src/logging/string_utils.cpp new file mode 100644 index 0000000..1861e06 --- /dev/null +++ b/src/logging/string_utils.cpp @@ -0,0 +1,37 @@ +#include "string_utils.hpp" +#include +#include + +namespace sdl3cpp::logging { + +std::string ToString(int value) { + return std::to_string(value); +} + +std::string ToString(size_t value) { + return std::to_string(value); +} + +std::string ToString(bool value) { + return value ? "true" : "false"; +} + +std::string ToString(float value) { + return std::to_string(value); +} + +std::string ToString(double value) { + return std::to_string(value); +} + +std::string ToString(const void* value) { + std::ostringstream oss; + oss << value; + return oss.str(); +} + +std::string ToString(unsigned long value) { + return std::to_string(value); +} + +} // namespace sdl3cpp::logging diff --git a/src/logging/string_utils.hpp b/src/logging/string_utils.hpp new file mode 100644 index 0000000..793f93f --- /dev/null +++ b/src/logging/string_utils.hpp @@ -0,0 +1,19 @@ +#ifndef SDL3CPP_LOGGING_STRING_UTILS_HPP +#define SDL3CPP_LOGGING_STRING_UTILS_HPP + +#include + +namespace sdl3cpp::logging { + +// Helper functions to convert common types to strings for logging +std::string ToString(int value); +std::string ToString(size_t value); +std::string ToString(bool value); +std::string ToString(float value); +std::string ToString(double value); +std::string ToString(const void* value); +std::string ToString(unsigned long value); + +} // namespace sdl3cpp::logging + +#endif // SDL3CPP_LOGGING_STRING_UTILS_HPP diff --git a/src/main.cpp b/src/main.cpp index b88c142..1856582 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,7 +72,8 @@ RuntimeConfig GenerateDefaultRuntimeConfig(const char* argv0) { } RuntimeConfig LoadRuntimeConfigFromJson(const std::filesystem::path& configPath, bool dumpConfig) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(configPath.string(), dumpConfig); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("LoadRuntimeConfigFromJson", configPath.string() + " " + ToString(dumpConfig)); std::ifstream configStream(configPath); if (!configStream) { throw std::runtime_error("Failed to open config file: " + configPath.string()); @@ -237,9 +238,10 @@ AppOptions ParseCommandLine(int argc, char** argv) { } void LogRuntimeConfig(const RuntimeConfig& config) { - sdl3cpp::logging::Logger::GetInstance().TraceVariable("config.width", config.width); - sdl3cpp::logging::Logger::GetInstance().TraceVariable("config.height", config.height); - sdl3cpp::logging::Logger::GetInstance().TraceVariable("config.scriptPath", config.scriptPath); + auto& logger = sdl3cpp::logging::Logger::GetInstance(); + logger.TraceVariable("config.width", config.width); + logger.TraceVariable("config.height", config.height); + logger.TraceVariable("config.scriptPath", config.scriptPath.string()); } void WriteRuntimeConfigJson(const RuntimeConfig& runtimeConfig, diff --git a/src/script/lua_helpers.cpp b/src/script/lua_helpers.cpp index d31ff80..eebf87b 100644 --- a/src/script/lua_helpers.cpp +++ b/src/script/lua_helpers.cpp @@ -11,7 +11,8 @@ namespace sdl3cpp::script { std::array ReadVector3(lua_State* L, int index) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(static_cast(L), index); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("ReadVector3", ToString(static_cast(L)) + " " + ToString(index)); std::array result{}; int absIndex = lua_absindex(L, index); size_t len = lua_rawlen(L, absIndex); @@ -31,7 +32,8 @@ std::array ReadVector3(lua_State* L, int index) { } std::array ReadQuaternion(lua_State* L, int index) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(static_cast(L), index); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("ReadQuaternion", ToString(static_cast(L)) + " " + ToString(index)); std::array result{}; int absIndex = lua_absindex(L, index); size_t len = lua_rawlen(L, absIndex); @@ -51,7 +53,8 @@ std::array ReadQuaternion(lua_State* L, int index) { } std::array ReadMatrix(lua_State* L, int index) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(static_cast(L), index); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("ReadMatrix", ToString(static_cast(L)) + " " + ToString(index)); std::array result{}; int absIndex = lua_absindex(L, index); size_t len = lua_rawlen(L, absIndex); @@ -71,7 +74,8 @@ std::array ReadMatrix(lua_State* L, int index) { } std::string GetLuaError(lua_State* L) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(static_cast(L)); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("GetLuaError", ToString(static_cast(L))); const char* message = lua_tostring(L, -1); return message ? message : "unknown lua error"; } @@ -85,17 +89,20 @@ std::array IdentityMatrix() { } glm::vec3 ToVec3(const std::array& value) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(value[0], value[1], value[2]); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("ToVec3", ToString(value[0]) + " " + ToString(value[1]) + " " + ToString(value[2])); return glm::vec3(value[0], value[1], value[2]); } glm::quat ToQuat(const std::array& value) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(value[0], value[1], value[2], value[3]); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("ToQuat", ToString(value[0]) + " " + ToString(value[1]) + " " + ToString(value[2]) + " " + ToString(value[3])); return glm::quat(value[3], value[0], value[1], value[2]); } void PushMatrix(lua_State* L, const glm::mat4& matrix) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(static_cast(L)); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("PushMatrix", ToString(static_cast(L))); lua_newtable(L); const float* ptr = glm::value_ptr(matrix); for (int i = 0; i < 16; ++i) { @@ -105,7 +112,8 @@ void PushMatrix(lua_State* L, const glm::mat4& matrix) { } int LuaGlmMatrixFromTransform(lua_State* L) { - sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(static_cast(L)); + using sdl3cpp::logging::ToString; + sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs("LuaGlmMatrixFromTransform", ToString(static_cast(L))); std::array translation = ReadVector3(L, 1); std::array rotation = ReadQuaternion(L, 2); glm::vec3 pos = ToVec3(translation);